├── owned.txt ├── .gitignore ├── data ├── green.csv ├── purple.txt ├── chips.csv ├── HeYueOrd-1.txt ├── HeYueOrd2.txt ├── HeYueOrd0.txt ├── HeYueOrd1.txt ├── HeYueOrd3.txt ├── HeYueOrd4.txt ├── HeYue0.txt ├── HeYue2.txt ├── HeYue-1.txt ├── HeYue1.txt ├── HeYue3.txt ├── HeYue4.txt ├── creditPrice.txt ├── price.txt ├── required.txt ├── orange.txt ├── materialIO.txt ├── time.csv ├── items.json ├── stages.json └── formula.json ├── __pycache__ ├── main.cpython-36.pyc ├── utils.cpython-36.pyc ├── MaterialPlanning.cpython-36.pyc └── MaterialPlanningRaw.cpython-36.pyc ├── yellow.py ├── setup.py ├── LICENSE ├── README.md ├── requirement.py ├── server.py ├── formula_processing.py ├── main.py ├── update_db.py ├── AggregationENJPKR.py ├── AggregationTW.py ├── AggregationCN.py ├── update_db_TW.py ├── update_db_ENJPKR.py ├── update_db_new.py ├── utils.py ├── MaterialPlanningRaw.py └── MaterialPlanning.py /owned.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | data/server.txt 2 | data/discordbot.txt 3 | run.bat 4 | __pycache__/* -------------------------------------------------------------------------------- /data/green.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQRPI/ArkOneGraph/HEAD/data/green.csv -------------------------------------------------------------------------------- /data/purple.txt: -------------------------------------------------------------------------------- 1 | 合成玉 20/100 2 | 龙门币 15/2000 3 | 高级作战记录 15 4 | 技巧概要·卷3 20 5 | 提纯源岩 50 6 | 改量装置 85 -------------------------------------------------------------------------------- /__pycache__/main.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQRPI/ArkOneGraph/HEAD/__pycache__/main.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/utils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQRPI/ArkOneGraph/HEAD/__pycache__/utils.cpython-36.pyc -------------------------------------------------------------------------------- /data/chips.csv: -------------------------------------------------------------------------------- 1 | ,近卫,重装,狙击,医疗,辅助,特种,术师,先锋 2 | 双芯片,50,30,32,23,23,22,28,20 3 | 芯片组,35,20,30,25,10,20,15,20 4 | 芯片,86,51,60,45,36,41,38,38 5 | -------------------------------------------------------------------------------- /__pycache__/MaterialPlanning.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQRPI/ArkOneGraph/HEAD/__pycache__/MaterialPlanning.cpython-36.pyc -------------------------------------------------------------------------------- /data/HeYueOrd-1.txt: -------------------------------------------------------------------------------- 1 | 双极纳米片 500 2 | 白马醇 150 3 | 五水研磨石 150 4 | 三水锰矿 150 5 | 聚酸酯组 35 6 | RMA70-12 60 7 | 龙门币 15/2000 8 | 中级作战记录 15/2 9 | 家具零件 20 -------------------------------------------------------------------------------- /__pycache__/MaterialPlanningRaw.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQRPI/ArkOneGraph/HEAD/__pycache__/MaterialPlanningRaw.cpython-36.pyc -------------------------------------------------------------------------------- /data/HeYueOrd2.txt: -------------------------------------------------------------------------------- 1 | 全新装置 30 2 | 固源岩组 15 3 | 糖聚块 75 4 | 酮阵列 80 5 | 提纯源岩 60 6 | D32钢 240 7 | 龙门币 7/2000 8 | 中级作战记录 7/2 9 | 研磨石 25 10 | 家具零件 10 -------------------------------------------------------------------------------- /data/HeYueOrd0.txt: -------------------------------------------------------------------------------- 1 | 凝胶 25 2 | 固源岩组 15 3 | 糖聚块 80 4 | RMA70-24 80 5 | 炽合金块 80 6 | D32钢 240 7 | 龙门币 7/2000 8 | 中级作战记录 7/2 9 | 聚酸酯组 20 10 | 家具零件 10 -------------------------------------------------------------------------------- /data/HeYueOrd1.txt: -------------------------------------------------------------------------------- 1 | 酮凝集组 25 2 | 糖组 20 3 | 五水研磨石 80 4 | 三水锰矿 80 5 | 聚酸酯块 80 6 | 聚合剂 240 7 | 龙门币 7/2000 8 | 中级作战记录 7/2 9 | RMA70-12 30 10 | 家具零件 10 -------------------------------------------------------------------------------- /data/HeYueOrd3.txt: -------------------------------------------------------------------------------- 1 | RMA70-12 30 2 | 异铁组 20 3 | 聚合凝胶 65 4 | 改量装置 110 5 | 白马醇 65 6 | 双极纳米片 240 7 | 龙门币 7/2000 8 | 中级作战记录 7/2 9 | 酮凝集组 20 10 | 家具零件 10 -------------------------------------------------------------------------------- /data/HeYueOrd4.txt: -------------------------------------------------------------------------------- 1 | 全新装置 30 2 | 凝胶 25 3 | 提纯源岩 65 4 | 三水锰矿 80 5 | 聚酸酯块 75 6 | 扭转醇 20 7 | 双极纳米片 240 8 | 龙门币 7/2000 9 | 中级作战记录 7/2 10 | 全新装置 30 11 | 家具零件 10 -------------------------------------------------------------------------------- /data/HeYue0.txt: -------------------------------------------------------------------------------- 1 | 凝胶 40 2 | 聚酸酯组 30 3 | 固源岩组 25 4 | 重装芯片 30 5 | 近卫芯片 30 6 | 狙击芯片 30 7 | 辅助芯片 30 8 | 中级作战记录 7 9 | 龙门币 1/135 10 | 装置 20 11 | 技巧概要·卷2 8 12 | 聚酸酯 12 13 | 酮凝集 15 14 | 先锋芯片 30 15 | 医疗芯片 30 16 | 术师芯片 30 17 | 特种芯片 30 18 | 异铁 15 19 | 糖 12 20 | 固源岩 8 -------------------------------------------------------------------------------- /data/HeYue2.txt: -------------------------------------------------------------------------------- 1 | 全新装置 45 2 | 研磨石 40 3 | 固源岩组 25 4 | 重装芯片 30 5 | 近卫芯片 30 6 | 狙击芯片 30 7 | 辅助芯片 30 8 | 中级作战记录 7 9 | 龙门币 1/135 10 | 装置 20 11 | 技巧概要·卷2 8 12 | 聚酸酯 12 13 | 酮凝集 15 14 | 先锋芯片 30 15 | 医疗芯片 30 16 | 术师芯片 30 17 | 特种芯片 30 18 | 异铁 15 19 | 糖 12 20 | 固源岩 8 -------------------------------------------------------------------------------- /data/HeYue-1.txt: -------------------------------------------------------------------------------- 1 | 聚酸酯组 40 2 | RMA70-12 90 3 | 重装芯片 60 4 | 近卫芯片 60 5 | 狙击芯片 60 6 | 辅助芯片 60 7 | 中级作战记录 12 8 | 龙门币 1/85 9 | 装置 35 10 | 技巧概要·卷2 15 11 | 聚酸酯 20 12 | 酮凝集 25 13 | 先锋芯片 60 14 | 医疗芯片 60 15 | 术师芯片 60 16 | 特种芯片 60 17 | 异铁 25 18 | 糖 15 19 | 固源岩 15 20 | -------------------------------------------------------------------------------- /data/HeYue1.txt: -------------------------------------------------------------------------------- 1 | 酮凝集组 40 2 | RMA70-12 45 3 | 糖组 30 4 | 重装芯片 30 5 | 近卫芯片 30 6 | 狙击芯片 30 7 | 辅助芯片 30 8 | 中级作战记录 7 9 | 龙门币 1/135 10 | 装置 20 11 | 技巧概要·卷2 8 12 | 聚酸酯 12 13 | 酮凝集 15 14 | 先锋芯片 30 15 | 医疗芯片 30 16 | 术师芯片 30 17 | 特种芯片 30 18 | 异铁 15 19 | 糖 12 20 | 固源岩 8 -------------------------------------------------------------------------------- /data/HeYue3.txt: -------------------------------------------------------------------------------- 1 | 酮凝集组 30 2 | 异铁组 30 3 | RMA70-12 45 4 | 重装芯片 30 5 | 近卫芯片 30 6 | 狙击芯片 30 7 | 辅助芯片 30 8 | 中级作战记录 7 9 | 龙门币 1/135 10 | 装置 20 11 | 技巧概要·卷2 8 12 | 聚酸酯 12 13 | 酮凝集 15 14 | 先锋芯片 30 15 | 医疗芯片 30 16 | 术师芯片 30 17 | 特种芯片 30 18 | 异铁 15 19 | 糖 12 20 | 固源岩 8 -------------------------------------------------------------------------------- /data/HeYue4.txt: -------------------------------------------------------------------------------- 1 | 酮凝集组 30 2 | 异铁组 30 3 | RMA70-12 45 4 | 重装芯片 30 5 | 近卫芯片 30 6 | 狙击芯片 30 7 | 辅助芯片 30 8 | 中级作战记录 7 9 | 龙门币 1/135 10 | 装置 20 11 | 技巧概要·卷2 8 12 | 聚酸酯 12 13 | 酮凝集 15 14 | 先锋芯片 30 15 | 医疗芯片 30 16 | 术师芯片 30 17 | 特种芯片 30 18 | 异铁 15 19 | 糖 12 20 | 固源岩 8 -------------------------------------------------------------------------------- /data/creditPrice.txt: -------------------------------------------------------------------------------- 1 | 装置 160 2 | 酮凝集 120 3 | 异铁 120 4 | 聚酸酯 100 5 | 糖 100 6 | 固源岩 66.66666667 7 | 破损装置 80 8 | 双酮 60 9 | 异铁碎片 60 10 | 酯原料 50 11 | 代糖 50 12 | 源岩 40 13 | 家具零件 8 14 | 碳素 66.66666667 15 | 技巧概要·卷2 66.66666667 16 | 技巧概要·卷1 32 17 | 龙门币 0.05555556 18 | 基础作战记录 11.11111111 19 | 初级作战记录 22.22222222 20 | 赤金 26.66666667 21 | 招聘许可 160 22 | 碳 32 -------------------------------------------------------------------------------- /data/price.txt: -------------------------------------------------------------------------------- 1 | 异铁块 15 2 | 酮阵列 15 3 | 三水锰矿 10 4 | 改量装置 20 5 | 糖聚块 10 6 | 五水研磨石 10 7 | 聚酸酯块 10 8 | RMA70-24 15 9 | 白马醇 10 10 | 聚合凝胶 15 11 | 炽合金块 15 12 | 提纯源岩 10 13 | 全新装置 45 14 | RMA70-12 45 15 | 研磨石 40 16 | 凝胶 40 17 | 炽合金 35 18 | 酮凝集组 35 19 | 轻锰矿 35 20 | 异铁组 35 21 | 扭转醇 30 22 | 聚酸酯组 30 23 | 糖组 30 24 | 固源岩组 25 25 | 招聘许可 15 26 | 寻访凭证 450 27 | 芯片助剂 15 28 | 晶体电路 15 29 | 晶体元件 30 30 | -------------------------------------------------------------------------------- /yellow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Dec 8 13:57:27 2019 4 | 5 | @author: sqr_p 6 | """ 7 | 8 | # import numpy as np 9 | from collections import defaultdict as ddict 10 | 11 | Values = ddict(float) 12 | 13 | Values['old6'] = 1 + 15 14 | Values['old5'] = 1 + 8 15 | Values['new6'] = 180 - Values['old6'] 16 | Values['new5'] = 45 - Values['old5'] 17 | Values['get4'] = 1 + 30*Values['green'] 18 | Values['get3'] = 10 * Values['green'] 19 | -------------------------------------------------------------------------------- /data/required.txt: -------------------------------------------------------------------------------- 1 | D32钢 202 2 | 双极纳米片 222 3 | 聚合剂 204 4 | RMA70-24 236 5 | RMA70-12 175 6 | 五水研磨石 289 7 | 研磨石 204 8 | 三水锰矿 236 9 | 轻锰矿 220 10 | 白马醇 283 11 | 扭转醇 293 12 | 改量装置 161 13 | 全新装置 178 14 | 装置 114 15 | 破损装置 46 16 | 酮阵列 207 17 | 酮凝集组 298 18 | 酮凝集 146 19 | 双酮 51 20 | 异铁块 198 21 | 异铁组 208 22 | 异铁 153 23 | 异铁碎片 65 24 | 聚酸酯块 246 25 | 聚酸酯组 221 26 | 聚酸酯 181 27 | 酯原料 83 28 | 糖聚块 269 29 | 糖组 249 30 | 糖 183 31 | 代糖 76 32 | 提纯源岩 287 33 | 固源岩组 298 34 | 固源岩 240 35 | 源岩 113 36 | -------------------------------------------------------------------------------- /data/orange.txt: -------------------------------------------------------------------------------- 1 | 炽合金块 75 2 | 聚合凝胶 65 3 | RMA70-24 80 4 | 五水研磨石 75 5 | 三水锰矿 80 6 | 白马醇 65 7 | 改量装置 85 8 | 酮阵列 85 9 | 异铁块 90 10 | 聚酸酯块 80 11 | 糖聚块 75 12 | 提纯源岩 60 13 | 炽合金 20 14 | 凝胶 25 15 | RMA70-12 30 16 | 研磨石 25 17 | 轻锰矿 22.5 18 | 扭转醇 20 19 | 全新装置 30 20 | 酮凝集组 22.5 21 | 异铁组 22.5 22 | 聚酸酯组 17.5 23 | 糖组 17.5 24 | 固源岩组 15 25 | 装置 10 26 | 酮凝集 7.5 27 | 异铁 7.5 28 | 聚酸酯 6.25 29 | 糖 6.25 30 | 固源岩 3.75 31 | 破损装置 5 32 | 双酮 3.75 33 | 异铁碎片 3.75 34 | 酯原料 3.125 35 | 代糖 3.125 36 | 源岩 1.875 37 | 晶体元件 20 38 | 晶体电路 90 39 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup 3 | 4 | # Utility function to read the README file. 5 | # Used for the long_description. It's nice, because now 1) we have a top level 6 | # README file and 2) it's easier to type in the README file than to put a raw 7 | # string in below ... 8 | def read(fname): 9 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 10 | 11 | setup( 12 | name = "Arknight AutoPlanner", 13 | version = "0.0.4", 14 | author = "YC.Remar", 15 | author_email = "ethan.ycx@gmail.com", 16 | description = ("A tiny program that helps on material planning in Arknight"), 17 | # url = "http://packages.python.org/an_example_pypi_project", 18 | install_requires=[ 19 | "numpy", 20 | "scipy", 21 | "sanic" 22 | ], 23 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Yaochen Xie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /data/materialIO.txt: -------------------------------------------------------------------------------- 1 | [{"name":"D32钢","need":328,"have":0},{"name":"双极纳米片","need":368,"have":0},{"name":"聚合剂","need":340,"have":0},{"name":"白马醇","need":420,"have":0},{"name":"扭转醇","need":420,"have":0},{"name":"三水锰矿","need":379,"have":0},{"name":"轻锰矿","need":332,"have":0},{"name":"五水研磨石","need":411,"have":0},{"name":"研磨石","need":315,"have":0},{"name":"RMA70-24","need":374,"have":0},{"name":"RMA70-12","need":291,"have":0},{"name":"提纯源岩","need":436,"have":0},{"name":"固源岩组","need":486,"have":0},{"name":"固源岩","need":376,"have":0},{"name":"源岩","need":169,"have":0},{"name":"改量装置","need":269,"have":0},{"name":"全新装置","need":272,"have":0},{"name":"装置","need":175,"have":0},{"name":"破损装置","need":74,"have":0},{"name":"聚酸酯块","need":359,"have":0},{"name":"聚酸酯组","need":287,"have":0},{"name":"聚酸酯","need":292,"have":0},{"name":"酯原料","need":121,"have":0},{"name":"糖聚块","need":350,"have":0},{"name":"糖组","need":306,"have":0},{"name":"糖","need":284,"have":0},{"name":"代糖","need":126,"have":0},{"name":"异铁块","need":340,"have":0},{"name":"异铁组","need":337,"have":0},{"name":"异铁","need":254,"have":0},{"name":"异铁碎片","need":101,"have":0},{"name":"酮阵列","need":340,"have":0},{"name":"酮凝集组","need":410,"have":0},{"name":"酮凝集","need":235,"have":0},{"name":"双酮","need":89,"have":0},{"name":"聚合凝胶","need":231,"have":0},{"name":"凝胶","need":83,"have":0},{"name":"炽合金块","need":224,"have":0},{"name":"炽合金","need":43,"have":0}] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ArkOneGraph 2 | 明日方舟刷图/商店一图流 3 | 4 | 主要代码来自 [ArkPlanner](https://github.com/ycremar/ArkPlanner),修改了部分代码用于输出刷图/商店一图流 5 | 6 | [NGA原帖](https://bbs.nga.cn/read.php?tid=19069337) 7 | 每次大型活动(新图)开启后一天及活动关闭时在此贴更新图片 8 | 9 | ![1月22日更新](https://img.nga.178.com/attachments/mon_202001/22/-klbw3Q5-bwzsXdZ3lT3cS2io-1bf.png) 10 | 11 | ## 主要修改 12 | 13 | - 增加绿票, 黄票商店兑换优先级计算 14 | - 增加关卡效率计算, 将龙门币和作战记录对应的理智扣除后计算掉落物品价值与消耗理智的比 15 | - 增加刷图推荐输出, 输出最高效率, 最优掉落及部分其他高掉落关卡(阈值设为期望理智除以效率大于最高效率关卡) 16 | - 增加信用点商店兑换优先级计算 17 | 18 | ## 使用方法 19 | 20 | 按照[ArkPlanner](https://github.com/ycremar/ArkPlanner)中的方法安装后运行main.py, 其中printSetting参数控制输出的项目 21 | 22 | 分别为 理智消耗, 最优关卡, 合成列表, 物品价值, 绿票商店, 黄票商店, 关卡效率, 推荐关卡, 信用商店, 合约商店 23 | 24 | 例如, '1111111111'表示全部输出, '0000000000'表示不输出, '0000000100'表示只输出推荐关卡 25 | 26 | ## 更新记录 27 | 28 | - 1月28日 增加对前端的支持 29 | - 1月22日 修改黄票商店新材料的错误 30 | - 1月13日 加入绿票商店的招募许可, 寻访凭证, 修改SK关卡的计算错误 31 | - 1月12日 修正四五章部分关卡由于新材料加入导致的掉率变化, 信用商店增加碳和家具零件, 图标统一(素材来自PRTS wiki) 32 | - 1月1日 加入新材料的绿票/黄票商店 33 | - 12月15日 更新代码, 加入技能书计算 34 | - 12月5日 修正了经验和技能书计算的bug, 修正了信用商店的bug 35 | - 12月4日 修改了信用商店的显示方式, 修正了赤金的计算错误,感谢SKSoulKeeper提醒. 36 | - 12月2日 活动结束常规更新,修正了PR,CA,LS关卡价值计算时没有扣减龙门币产出的bug, 之前S4-9可能是由于这一问题造成的,如果影响到了各位表示抱歉. 37 | - 11月28日 修复无限池装置价值的bug, 修复1-7掉落数据的bug, 更新最新的企鹅物流数据对应的最优关卡, S4-9取代4-2成为糖组最优关卡 38 | - 11月20日 增加活动常规池, 修改部分错误 39 | - 11月19日 更新喧闹法则版本,增加信用商店及活动商店, 修改黄票商店bug(感谢Again1357258 提出错误),修改推荐关卡逻辑,展示更多常用关卡 40 | -------------------------------------------------------------------------------- /requirement.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Oct 16 18:38:00 2019 4 | 5 | @author: sqr_p 6 | """ 7 | 8 | req = [{"name":"D32钢","need":202,"have":0},{"name":"双极纳米片","need":222,"have":0},{"name":"聚合剂","need":204,"have":0},{"name":"RMA70-24","need":236,"have":0},{"name":"RMA70-12","need":175,"have":0},{"name":"五水研磨石","need":289,"have":0},{"name":"研磨石","need":204,"have":0},{"name":"三水锰矿","need":236,"have":0},{"name":"轻锰矿","need":220,"have":0},{"name":"白马醇","need":283,"have":0},{"name":"扭转醇","need":293,"have":0},{"name":"改量装置","need":161,"have":0},{"name":"全新装置","need":178,"have":0},{"name":"装置","need":114,"have":0},{"name":"破损装置","need":46,"have":0},{"name":"酮阵列","need":207,"have":0},{"name":"酮凝集组","need":298,"have":0},{"name":"酮凝集","need":146,"have":0},{"name":"双酮","need":51,"have":0},{"name":"异铁块","need":198,"have":0},{"name":"异铁组","need":208,"have":0},{"name":"异铁","need":153,"have":0},{"name":"异铁碎片","need":65,"have":0},{"name":"聚酸酯块","need":246,"have":0},{"name":"聚酸酯组","need":221,"have":0},{"name":"聚酸酯","need":181,"have":0},{"name":"酯原料","need":83,"have":0},{"name":"糖聚块","need":269,"have":0},{"name":"糖组","need":249,"have":0},{"name":"糖","need":183,"have":0},{"name":"代糖","need":76,"have":0},{"name":"提纯源岩","need":287,"have":0},{"name":"固源岩组","need":298,"have":0},{"name":"固源岩","need":240,"have":0},{"name":"源岩","need":113,"have":0}] 9 | with open('required.txt', 'w', encoding='utf8') as f: 10 | for item in req: 11 | f.write('%s %s\n'% (item['name'], item['need'])) 12 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | from sanic import Sanic, response 2 | from MaterialPlanning import MaterialPlanning 3 | import time, codecs 4 | 5 | app = Sanic() 6 | 7 | app.static('/', './ArkPlannerWeb/index.html') 8 | app.static('/css', './ArkPlannerWeb/css') 9 | app.static('/fonts', './ArkPlannerWeb/fonts') 10 | app.static('/img', './ArkPlannerWeb/img') 11 | app.static('/js', './ArkPlannerWeb/js') 12 | 13 | 14 | mp = MaterialPlanning() 15 | mp.update() 16 | last_updated = time.time() 17 | 18 | @app.route("/plan", methods=['POST']) 19 | async def plan(request): 20 | global last_updated 21 | try: 22 | input_data = request.json 23 | owned_dct = input_data["owned"] 24 | required_dct = input_data["required"] 25 | except: 26 | return response.json({"error": True, "reason": "Uninterpretable input"}) 27 | 28 | try: 29 | extra_outc = request.json["extra_outc"] 30 | except: 31 | extra_outc = False 32 | 33 | try: 34 | exp_demand = request.json["exp_demand"] 35 | except: 36 | exp_demand = True 37 | 38 | try: 39 | gold_demand = request.json["gold_demand"] 40 | except: 41 | gold_demand = True 42 | 43 | try: 44 | if time.time() - last_updated > 60 * 30: 45 | mp.update() 46 | last_updated = time.time() 47 | dct = mp.get_plan(required_dct, owned_dct, False, 48 | outcome=extra_outc, exp_demand=exp_demand, gold_demand=gold_demand) 49 | except ValueError as e: 50 | return response.json({"error": True, "reason": str(e)}) 51 | 52 | return response.json(dct) 53 | 54 | # def get_costume_counts(countdir='costume_counts.txt'): 55 | # global costume_counts 56 | # try: 57 | # with codecs.open(countdir, 'r', 'utf-8') as f: 58 | # costume_counts = f.readline() 59 | 60 | 61 | 62 | if __name__ == "__main__": 63 | app.run(host="127.0.0.1", port=8000) 64 | -------------------------------------------------------------------------------- /data/time.csv: -------------------------------------------------------------------------------- 1 | stage,time 2 | 'LS-1',106 3 | 'LS-2',111 4 | 'LS-3',128 5 | 'LS-4',128 6 | 'LS-5',145.5 7 | 'CE-1',120 8 | 'CE-2',144 9 | 'CE-3',141 10 | 'CE-4',172 11 | 'CE-5',169 12 | '1-1',120 13 | '1-5',159 14 | '1-4',135 15 | '1-3',112 16 | '1-9',120 17 | '1-8',130.1 18 | 'S3-1',130 19 | '1-7',116 20 | '1-6',172.7 21 | 'S3-2',125 22 | 'S4-6',120 23 | 'S4-4',170 24 | 'S4-5',150 25 | '4-2',140 26 | '4-1',189 27 | '4-4',148 28 | '4-3',209 29 | '1-12',144 30 | '1-10',118 31 | '4-9',216.5 32 | '4-6',202 33 | '4-5',155 34 | '4-8',162 35 | '4-7',173 36 | 'S2-2',132 37 | 'S2-3',127.5 38 | 'S2-1',113 39 | 'S2-6',132 40 | 'S2-7',166 41 | '3-1',178 42 | 'S2-4',138 43 | '3-2',160 44 | '3-3',172.7 45 | 'S2-5',176 46 | '0-11',108 47 | '0-10',112 48 | 'S2-8',109.5 49 | 'S2-9',142 50 | '3-8',162 51 | '3-4',215.6 52 | '3-5',165 53 | '3-6',109.8 54 | '3-7',237.7 55 | 'S4-8',192 56 | 'S4-9',243 57 | 'S4-7',199 58 | 'S5-1',193 59 | 'S5-2',176 60 | 'SK-1',96 61 | 'SK-2',113 62 | 'SK-5',199 63 | 'SK-3',136 64 | 'SK-4',121 65 | '2-10',176 66 | '5-3',203 67 | '5-2',181 68 | '5-5',198 69 | '5-4',139 70 | '5-1',150 71 | '5-7',169.3 72 | '5-6',307 73 | '5-9',180 74 | '5-8',187 75 | '0-9',96.5 76 | 'S2-10',155 77 | 'S2-11',170 78 | 'S2-12',125 79 | '5-10',302.5 80 | '0-4',125.6 81 | '0-3',88.4 82 | '0-2',81 83 | '0-1',63.7 84 | '0-8',98 85 | '0-7',88 86 | 'S5-3',173 87 | 'S5-4',174 88 | '0-6',101.8 89 | '0-5',95 90 | '4-10',185.5 91 | 'S3-4',136 92 | 'S3-5',138.07 93 | 'S3-3',190 94 | 'CA-2',104 95 | 'S4-1',163 96 | 'CA-1',97 97 | 'CA-5',141 98 | 'S4-2',148 99 | 'CA-4',157 100 | 'S4-3',160 101 | 'CA-3',137 102 | '2-1',172 103 | '2-2',154.4 104 | '2-7',164 105 | '2-8',180 106 | '2-9',191 107 | '2-3',184.7 108 | '2-4',148 109 | '2-5',160.5 110 | 'S5-5',205 111 | '2-6',153 112 | 'S5-6',196 113 | ‘6-1’,163 114 | ‘6-2’,202 115 | ‘6-3’,172 116 | ‘6-4’,129 117 | ‘6-5’,240 118 | ‘6-7’,212 119 | ‘6-8’,134 120 | ‘6-9’,154 121 | ‘6-10’,162.2 122 | ‘6-11’,225 123 | ‘6-12’,161 124 | ‘6-14’,180 125 | ‘6-15’,173 126 | ‘6-16’,299 127 | ‘S6-1',160 128 | ‘S6-2',174 129 | ‘S6-3',195 130 | ‘S6-4',162 131 | ‘S5-7',141 132 | ‘S5-8',145 133 | ‘S4-10',88 134 | ‘S3-6',117 135 | ‘AP-5',195 136 | -------------------------------------------------------------------------------- /data/items.json: -------------------------------------------------------------------------------- 1 | {"2001": "\u57fa\u7840\u4f5c\u6218\u8bb0\u5f55", "2002": "\u521d\u7ea7\u4f5c\u6218\u8bb0\u5f55", "2003": "\u4e2d\u7ea7\u4f5c\u6218\u8bb0\u5f55", "2004": "\u9ad8\u7ea7\u4f5c\u6218\u8bb0\u5f55", "3003": "\u8d64\u91d1", "30011": "\u6e90\u5ca9", "30012": "\u56fa\u6e90\u5ca9", "30013": "\u56fa\u6e90\u5ca9\u7ec4", "30014": "\u63d0\u7eaf\u6e90\u5ca9", "30061": "\u7834\u635f\u88c5\u7f6e", "30062": "\u88c5\u7f6e", "30063": "\u5168\u65b0\u88c5\u7f6e", "30064": "\u6539\u91cf\u88c5\u7f6e", "30031": "\u916f\u539f\u6599", "30032": "\u805a\u9178\u916f", "30033": "\u805a\u9178\u916f\u7ec4", "30034": "\u805a\u9178\u916f\u5757", "30021": "\u4ee3\u7cd6", "30022": "\u7cd6", "30023": "\u7cd6\u7ec4", "30024": "\u7cd6\u805a\u5757", "30041": "\u5f02\u94c1\u788e\u7247", "30042": "\u5f02\u94c1", "30043": "\u5f02\u94c1\u7ec4", "30044": "\u5f02\u94c1\u5757", "30051": "\u53cc\u916e", "30052": "\u916e\u51dd\u96c6", "30053": "\u916e\u51dd\u96c6\u7ec4", "30054": "\u916e\u9635\u5217", "30073": "\u626d\u8f6c\u9187", "30074": "\u767d\u9a6c\u9187", "30083": "\u8f7b\u9530\u77ff", "30084": "\u4e09\u6c34\u9530\u77ff", "30093": "\u7814\u78e8\u77f3", "30094": "\u4e94\u6c34\u7814\u78e8\u77f3", "30103": "RMA70-12", "30104": "RMA70-24", "furni": "\u5bb6\u5177", "3112": "\u78b3", "3113": "\u78b3\u7d20", "3114": "\u78b3\u7d20\u7ec4", "3301": "\u6280\u5de7\u6982\u8981\u00b7\u53771", "3302": "\u6280\u5de7\u6982\u8981\u00b7\u53772", "3303": "\u6280\u5de7\u6982\u8981\u00b7\u53773", "et_ObsidianPass": "\u9ed1\u66dc\u77f3\u8282\u95e8\u7968", "token_Obsidian": "\u6c50\u65af\u5854\u7684\u9ed1\u66dc\u77f3", "token_ObsidianCoin": "\u9ed1\u66dc\u77f3\u8282\u62bd\u5956\u4ee3\u5e01", "4001_2000": "\u9f99\u95e8\u5e012000", "4001_1500": "\u9f99\u95e8\u5e011500", "4001_1000": "\u9f99\u95e8\u5e011000", "31013": "\u51dd\u80f6", "31014": "\u805a\u5408\u51dd\u80f6", "31023": "\u70bd\u5408\u91d1", "31024": "\u70bd\u5408\u91d1\u5757", "randomMaterial_1": "\u7f57\u5fb7\u5c9b\u7269\u8d44\u8865\u7ed9", "ap_supply_lt_010": "\u5e94\u6025\u7406\u667a\u5c0f\u6837", "randomMaterial_2": "\u5c81\u8fc7\u534e\u706f", "4005": "\u8d44\u8d28\u51ed\u8bc1", "30115": "\u805a\u5408\u5242", "30125": "\u53cc\u6781\u7eb3\u7c73\u7247", "30135": "D32\u94a2", "randomMaterial_3": "32h\u6218\u7565\u914d\u7ed9", "randomMaterial_4": "\u611f\u8c22\u5e86\u5178\u7269\u8d44\u8865\u7ed9", "31033": "\u6676\u4f53\u5143\u4ef6", "31034": "\u6676\u4f53\u7535\u8def", "30145": "\u6676\u4f53\u7535\u5b50\u5355\u5143", "3211": "\u5148\u950b\u82af\u7247", "3221": "\u8fd1\u536b\u82af\u7247", "3241": "\u72d9\u51fb\u82af\u7247", "3231": "\u91cd\u88c5\u82af\u7247", "3261": "\u533b\u7597\u82af\u7247", "3271": "\u8f85\u52a9\u82af\u7247", "3251": "\u672f\u5e08\u82af\u7247", "3281": "\u7279\u79cd\u82af\u7247", "3212": "\u5148\u950b\u82af\u7247\u7ec4", "3222": "\u8fd1\u536b\u82af\u7247\u7ec4", "3242": "\u72d9\u51fb\u82af\u7247\u7ec4", "3232": "\u91cd\u88c5\u82af\u7247\u7ec4", "3262": "\u533b\u7597\u82af\u7247\u7ec4", "3272": "\u8f85\u52a9\u82af\u7247\u7ec4", "3252": "\u672f\u5e08\u82af\u7247\u7ec4", "3282": "\u7279\u79cd\u82af\u7247\u7ec4"} -------------------------------------------------------------------------------- /formula_processing.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Dec 24 19:22:26 2019 4 | 5 | @author: sqr_p 6 | """ 7 | 8 | formula = json.load(open('data/formula_bak.json', 'r', encoding='utf8')) 9 | 10 | Level4Extra = [{'count': 1, 'id': '31013', 'name': '凝胶', 'rarity': 2, 'weight': 36}, 11 | {'count': 1, 'id': '31023', 'name': '炽合金', 'rarity': 2, 'weight': 40}] 12 | for x in formula: 13 | if x['id'][-1] == '4': 14 | x['extraOutcome'] += Level4Extra 15 | x['totalWeight'] += 36+40 16 | 17 | Level5Extra = [{'count': 1, 'id': '31014', 'name': '聚合凝胶', 'rarity': 3, 'weight': 72}, 18 | {'count': 1, 'id': '31024', 'name': '炽合金块', 'rarity': 3, 'weight': 63}] 19 | for x in formula: 20 | if x['id'][-1] == '5': 21 | x['extraOutcome'] += Level5Extra 22 | x['totalWeight'] += 72+63 23 | s = x 24 | 25 | ChiHeJinKuai = {'costs': [{'count': 1, 'id': '30063', 'name': '全新装置', 'rarity': 2}, 26 | {'count': 1, 'id': '30093', 'name': '研磨石', 'rarity': 2}, 27 | {'count': 1, 'id': '31023', 'name': '炽合金', 'rarity': 2}], 28 | 'extraOutcome': [{'count': 1, 29 | 'id': '30013', 30 | 'name': '固源岩组', 31 | 'rarity': 2, 32 | 'weight': 60}, 33 | {'count': 1, 'id': '30023', 'name': '糖组', 'rarity': 2, 'weight': 50}, 34 | {'count': 1, 'id': '30033', 'name': '聚酸酯组', 'rarity': 2, 'weight': 50}, 35 | {'count': 1, 'id': '30043', 'name': '异铁组', 'rarity': 2, 'weight': 40}, 36 | {'count': 1, 'id': '30053', 'name': '酮凝集组', 'rarity': 2, 'weight': 40}, 37 | {'count': 1, 'id': '30063', 'name': '全新装置', 'rarity': 2, 'weight': 30}, 38 | {'count': 1, 'id': '30073', 'name': '扭转醇', 'rarity': 2, 'weight': 45}, 39 | {'count': 1, 'id': '30083', 'name': '轻锰矿', 'rarity': 2, 'weight': 40}, 40 | {'count': 1, 'id': '30093', 'name': '研磨石', 'rarity': 2, 'weight': 36}, 41 | {'count': 1, 'id': '30103', 'name': 'RMA70-12', 'rarity': 2, 'weight': 30}, 42 | {'count': 1, 'id': '31013', 'name': '凝胶', 'rarity': 2, 'weight': 36}, 43 | {'count': 1, 'id': '31023', 'name': '炽合金', 'rarity': 2, 'weight': 40}], 44 | 'goldCost': 300, 45 | 'id': '31024', 46 | 'name': '炽合金块', 47 | 'totalWeight': 497} 48 | 49 | JuHeNingJiao = {'costs': [{'count': 1, 'id': '30043', 'name': '异铁组', 'rarity': 2}, 50 | {'count': 1, 'id': '31013', 'name': '凝胶', 'rarity': 2}, 51 | {'count': 1, 'id': '31023', 'name': '炽合金', 'rarity': 2}], 52 | 'extraOutcome': [{'count': 1, 53 | 'id': '30013', 54 | 'name': '固源岩组', 55 | 'rarity': 2, 56 | 'weight': 60}, 57 | {'count': 1, 'id': '30023', 'name': '糖组', 'rarity': 2, 'weight': 50}, 58 | {'count': 1, 'id': '30033', 'name': '聚酸酯组', 'rarity': 2, 'weight': 50}, 59 | {'count': 1, 'id': '30043', 'name': '异铁组', 'rarity': 2, 'weight': 40}, 60 | {'count': 1, 'id': '30053', 'name': '酮凝集组', 'rarity': 2, 'weight': 40}, 61 | {'count': 1, 'id': '30063', 'name': '全新装置', 'rarity': 2, 'weight': 30}, 62 | {'count': 1, 'id': '30073', 'name': '扭转醇', 'rarity': 2, 'weight': 45}, 63 | {'count': 1, 'id': '30083', 'name': '轻锰矿', 'rarity': 2, 'weight': 40}, 64 | {'count': 1, 'id': '30093', 'name': '研磨石', 'rarity': 2, 'weight': 36}, 65 | {'count': 1, 'id': '30103', 'name': 'RMA70-12', 'rarity': 2, 'weight': 30}, 66 | {'count': 1, 'id': '31013', 'name': '凝胶', 'rarity': 2, 'weight': 36}, 67 | {'count': 1, 'id': '31023', 'name': '炽合金', 'rarity': 2, 'weight': 40}], 68 | 'goldCost': 300, 69 | 'id': '31014', 70 | 'name': '聚合凝胶', 71 | 'totalWeight': 497} 72 | 73 | formula += [ChiHeJinKuai, JuHeNingJiao] 74 | with open('data/formula.json', 'w', encoding='gbk') as outfile: 75 | json.dump(formula, outfile, indent=1, ensure_ascii=False) 76 | 77 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from MaterialPlanning import MaterialPlanning 4 | 5 | #from MaterialPlanningRaw import MaterialPlanning as MPR 6 | #from utils import required_dctCN, owned_dct 7 | required_dctCN = {'D32钢': 382, '双极纳米片': 454, 'D32钢': 382, '聚合剂': 378, '白马醇': 476, '扭转醇': 339, '三水锰矿': 399, '轻锰矿': 229, '五水研磨石': 458, '研磨石': 237, 'RMA70-24': 430, 'RMA70-12': 218, '提纯源岩': 446, '固源岩组': 329, '固源岩': 259, '源岩': 217, '改量装置': 306, '全新装置': 198, '装置': 116, '破损装置': 96, '聚酸酯块': 316, '聚酸酯组': 140, '聚酸酯': 201, '酯原料': 149, '糖聚块': 303, '糖组': 135, '糖': 194, '代糖': 153, '异铁块': 392, '异铁组': 201, '异铁': 176, '异铁碎片': 120, '酮阵列': 426, '酮凝集组': 339, '酮凝集': 166, '双酮': 123, '聚合凝胶': 384, '凝胶': 261, '炽合金块': 366, '炽合金': 248, '近卫双芯片': 50, '重装双芯片': 20, '狙击双芯片': 35, '医疗双芯片': 25, '辅助双芯片': 15, '特种双芯片': 25, '术师双芯片': 20, '先锋双芯片': 20, '近卫芯片组': 67, '重装芯片组': 37, '狙击芯片组': 46, '医疗芯片组': 26, '辅助芯片组': 36, '特种芯片组': 30, '术师芯片组': 43, '先锋芯片组': 26, '近卫芯片': 117, '重装芯片': 60, '狙击芯片': 81, '医疗芯片': 49, '辅助芯片': 56, '特种芯片': 54, '术师芯片': 68, '先锋芯片': 46, '经验': 102334800, '龙门币': 114019816, '家具零件': 10000, '采购凭证': 1000, '技巧概要·卷1': 1028, '技巧概要·卷2': 2295, '技巧概要·卷3': 7562} 8 | N = 100 9 | required_dctCN.update({ 10 | '晶体电路': N, 11 | '晶体元件': N, 12 | '晶体电子单元': N 13 | }) 14 | owned_dct = {} 15 | ''' 16 | Print_functions = [ 17 | self.output_cost, #理智消耗 18 | self.output_stages, #关卡次数 19 | self.output_items, #合成次数 20 | self.output_values, #物品价值 21 | self.output_green, #绿票商店 22 | self.output_yellow, #黄票商店 23 | self.output_effect, #关卡效率 24 | self.output_best_stage, #关卡推荐 25 | self.output_credit, #信用商店 26 | self.output_WeiJiHeYue #危机合约(喧闹法则活动商店) 27 | ] 28 | ''' 29 | 30 | if True: 31 | prst = '010100000000' if __name__ == '__main__' else '000011001011' 32 | # prst = '0000000000' if __name__ == '__main__' else '0000110010' 33 | print_output = True if __name__ == '__main__' else False 34 | update = False if __name__ == '__main__' else True 35 | SuiGuoHuaDeng = False if __name__ == '__main__' else False 36 | ExpFromBase = False if __name__ == '__main__' else False 37 | 38 | mp = MaterialPlanning(filter_stages=['荒芜行动物资补给', '罗德岛物资补给', '岁过华灯', '32h战略配给', '感谢庆典物资补给', 39 | '应急理智小样', '黄铁行动物资补给', '利刃行动物资补给', '燃灰行动物资补给'] + ['S4-4', 'S6-4','S4-9'], 40 | filter_freq=100, 41 | update=update, 42 | banned_stages={}, 43 | # expValue=30, #1224更新后此参数无效, 使用经验需求来调节经验价值 44 | printSetting=prst, #参照上面Print_functions的顺序设置, 1输出, 0不输出 45 | ConvertionDR=0.18, #副产物掉落率 46 | costLimit=135, #理智上限 47 | #costType='time', 48 | base_exp=0, 49 | base_MTL_GOLD3=0, 50 | base_gold=0, 51 | stone_per_day=0, 52 | display_main_only=True, 53 | SuiGuoHuaDeng=SuiGuoHuaDeng, 54 | ExpFromBase = ExpFromBase 55 | ) 56 | 57 | # mpr = MPR() 58 | res, mat1, mat2 = mp.get_plan(required_dctCN, owned_dct, print_output=print_output, outcome=True, 59 | gold_demand=True, exp_demand=True) 60 | mp.output_effect(filter='8-') 61 | print('发布前记得确认材料需求是否正确!') 62 | # print(mp.effect['1-7']) 63 | # mpr.get_plan(required_dct, owned_dct, print_output=True, outcome=True, 64 | # gold_demand=True, exp_demand=True) 65 | -------------------------------------------------------------------------------- /update_db.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Jan 28 14:13:20 2020 4 | 5 | @author: sqr_p 6 | """ 7 | 8 | import pymongo 9 | from MaterialPlanning import MaterialPlanning 10 | import time 11 | from dateutil import parser 12 | from utils import required_dct, owned_dct 13 | 14 | print('正在从企鹅物流获取数据...') 15 | server = open('data/server.txt', 'r').readline().strip() 16 | dbclient = pymongo.MongoClient(server) 17 | db = dbclient['Arknights_OneGraph'] 18 | collection = db['Material'] 19 | 20 | Event_Stages = ['SA-%d'%x for x in range(1,7)] 21 | update_time = parser.parse(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime())) 22 | mp_event = MaterialPlanning(filter_stages=['S4-4', 'S6-4'], 23 | filter_freq=100, 24 | update=True, 25 | printSetting='0000110011' 26 | ) 27 | mp_event.get_plan(required_dct, owned_dct, print_output=False, outcome=True, 28 | gold_demand=True, exp_demand=True) 29 | mp = MaterialPlanning(filter_stages=['S4-4', 'S6-4'] + Event_Stages, 30 | filter_freq=100, 31 | update=False, 32 | printSetting='0000110011' 33 | ) 34 | mp.get_plan(required_dct, owned_dct, print_output=False, outcome=True, 35 | gold_demand=True, exp_demand=True) 36 | 37 | [mp_event.output_best_stage(x) for x in '123'] 38 | [mp.output_best_stage(x) for x in '123'] 39 | 40 | print('正在更新数据库...') 41 | for item in collection.find(): 42 | x = item['name'] 43 | print('\r已更新%s\t' % x, end='\t') 44 | if item['name'] in mp.HeYueDict or item['name'] in mp.HYODict: 45 | collection.update_one({'_id': item['_id']}, 46 | {'$set': {'contingency_store_value': {'infinite': '%.3f'%mp.HeYueDict[x] if x in mp.HeYueDict else '0.0', 47 | 'finite': '%.3f'%mp.HYODict[x] if x in mp.HYODict else '0.0'}} 48 | }) 49 | if 'credit_store_value' in item: 50 | if item['name'] in mp.best_stage: 51 | collection.update_one({'_id': item['_id']}, 52 | {'$set': {'credit_store_value' : '%.3f'%(100*mp.creditEffect[item['name']]), 53 | 'Notes': mp.Notes[item['name']], 54 | 'lowest_ap_stages': mp.best_stage[item['name']]['lowest_ap_stages'], 55 | 'balanced_stages': mp.best_stage[item['name']]['balanced_stages'], 56 | 'drop_rate_first_stages': mp.best_stage[item['name']]['drop_rate_first_stages'], 57 | 'last_updated': update_time} 58 | }) 59 | else: 60 | collection.update_one({'_id': item['_id']}, 61 | {'$set': {'credit_store_value': '%.3f'%(100*mp.creditEffect[item['name']]), 62 | 'Notes': mp.Notes[item['name']], 63 | 'lowest_ap_stages': [{}], 64 | 'balanced_stages': [{}], 65 | 'drop_rate_first_stages': [{}], 66 | 'last_updated': update_time} 67 | }) 68 | if 'green_ticket_value' in item: 69 | if item['name'] in mp.best_stage: 70 | collection.update_one({'_id': item['_id']}, 71 | {'$set': {'green_ticket_value': '%.3f'%(mp.greenTickets[item['name']]), 72 | 'Notes': mp.Notes[item['name']], 73 | 'lowest_ap_stages': mp.best_stage[item['name']]['lowest_ap_stages'], 74 | 'balanced_stages': mp.best_stage[item['name']]['balanced_stages'], 75 | 'drop_rate_first_stages': mp.best_stage[item['name']]['drop_rate_first_stages'], 76 | 'last_updated': update_time}}) 77 | else: 78 | collection.update_one({'_id': item['_id']}, 79 | {'$set': {'green_ticket_value': '%.3f'%(mp.greenTickets[item['name']]), 80 | 'Notes': mp.Notes[item['name']], 81 | 'lowest_ap_stages': [{}], 82 | 'balanced_stages': [{}], 83 | 'drop_rate_first_stages': [{}], 84 | 'last_updated': update_time}}) 85 | if 'golden_ticket_value' in item: 86 | collection.update_one({'_id': item['_id']}, 87 | {'$set': {'golden_ticket_value': '%.3f'%(mp.yellowTickets[item['name']]), 88 | 'Notes': mp.Notes[item['name']], 89 | 'last_updated': update_time}}) 90 | 91 | print('\n更新完成.') 92 | -------------------------------------------------------------------------------- /AggregationENJPKR.py: -------------------------------------------------------------------------------- 1 | 2 | collection = db['CharactersENJPKR'] 3 | with open('data/character_tableEN.json',encoding='UTF-8') as rawFile: 4 | characterTableJSON = json.load(rawFile) 5 | 6 | for key in characterTableJSON.keys(): 7 | if 'token' in key: 8 | continue 9 | item=characterTableJSON[key] 10 | name = item['name'] 11 | rarity = item['rarity'] 12 | profession = item['profession'] 13 | if profession == "TRAP": 14 | continue 15 | if rarity ==2: #3* characters 16 | phase1Cost = item['phases'][1]['evolveCost'] 17 | skillCost = [] 18 | for i in item['allSkillLvlup']: 19 | skillCost.append(i['lvlUpCost']) 20 | print(name) 21 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 22 | 'profession': profession, 23 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 24 | '4to5': skillCost[3], 25 | '5to6': skillCost[4], '6to7': skillCost[5] 26 | } 27 | }, upsert=True) 28 | elif rarity ==3 or rarity == 4: #4 and 5* characters 29 | phase1Cost = item['phases'][1]['evolveCost'] 30 | phase2Cost = item['phases'][2]['evolveCost'] 31 | skillCost = [] 32 | for i in item['allSkillLvlup']: 33 | skillCost.append(i['lvlUpCost']) 34 | for i in item['skills']: 35 | for j in i['levelUpCostCond']: 36 | skillCost.append(j['levelUpCost']) 37 | print(name) 38 | if name =="Amiya": 39 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 40 | 'profession': profession, 'phase1Cost': phase1Cost, 41 | 'phase2Cost': phase2Cost, 42 | '1to2': skillCost[0], '2to3': skillCost[1], 43 | '3to4': skillCost[2], 44 | '4to5': skillCost[3], 45 | '5to6': skillCost[4], '6to7': skillCost[5], 46 | 'S1M1': skillCost[6], 47 | 'S1M2': skillCost[7], 'S1M3': skillCost[8], 48 | 'S2M1': skillCost[9], 49 | 'S2M2': skillCost[10], 'S2M3': skillCost[11], 50 | 'S3M1': skillCost[12], 51 | 'S3M2': skillCost[13], 'S3M3': skillCost[14] 52 | } 53 | }, upsert=True) 54 | else: 55 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 56 | 'profession': profession, 'phase1Cost': phase1Cost, 57 | 'phase2Cost': phase2Cost, 58 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 59 | '4to5': skillCost[3], 60 | '5to6': skillCost[4], '6to7': skillCost[5], 'S1M1': skillCost[6], 61 | 'S1M2':skillCost[7], 'S1M3': skillCost[8], 'S2M1': skillCost[9], 62 | 'S2M2': skillCost[10],'S2M3': skillCost[11] 63 | } 64 | }, upsert=True) 65 | elif rarity ==5: #4,5, and 6* characters 66 | phase1Cost = item['phases'][1]['evolveCost'] 67 | phase2Cost = item['phases'][2]['evolveCost'] 68 | skillCost = [] 69 | for i in item['allSkillLvlup']: 70 | skillCost.append(i['lvlUpCost']) 71 | for i in item['skills']: 72 | for j in i['levelUpCostCond']: 73 | skillCost.append(j['levelUpCost']) 74 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 75 | 'profession': profession, 'phase1Cost': phase1Cost, 76 | 'phase2Cost': phase2Cost, 77 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 78 | '4to5': skillCost[3], 79 | '5to6': skillCost[4], '6to7': skillCost[5], 'S1M1': skillCost[6], 80 | 'S1M2':skillCost[7], 'S1M3': skillCost[8], 'S2M1': skillCost[9], 81 | 'S2M2': skillCost[10],'S2M3': skillCost[11],'S3M1': skillCost[12], 82 | 'S3M2': skillCost[13],'S3M3': skillCost[14] 83 | } 84 | }, upsert=True) 85 | else: #1,2* characters 86 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 87 | 'profession': profession} 88 | }, upsert=True) 89 | 90 | print('\nDone for EN, JP and KR server.') -------------------------------------------------------------------------------- /AggregationTW.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | import json 3 | server = open('data/server.txt', 'r').readline().strip() 4 | dbclient = pymongo.MongoClient(server) 5 | db = dbclient['ArknightsGamedata'] 6 | 7 | collection = db['CharactersTW'] 8 | with open('data/character_tableTW.json',encoding='UTF-8') as rawFile: 9 | characterTableJSON = json.load(rawFile) 10 | 11 | for key in characterTableJSON.keys(): 12 | if 'token' in key: 13 | continue 14 | item=characterTableJSON[key] 15 | name = item['name'] 16 | rarity = item['rarity'] 17 | profession = item['profession'] 18 | if profession == "TRAP": 19 | continue 20 | if rarity ==2: #3* characters 21 | phase1Cost = item['phases'][1]['evolveCost'] 22 | skillCost = [] 23 | for i in item['allSkillLvlup']: 24 | skillCost.append(i['lvlUpCost']) 25 | print(name) 26 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 27 | 'profession': profession, 28 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 29 | '4to5': skillCost[3], 30 | '5to6': skillCost[4], '6to7': skillCost[5] 31 | } 32 | }, upsert=True) 33 | elif rarity ==3 or rarity == 4: #4 and 5* characters 34 | phase1Cost = item['phases'][1]['evolveCost'] 35 | phase2Cost = item['phases'][2]['evolveCost'] 36 | skillCost = [] 37 | for i in item['allSkillLvlup']: 38 | skillCost.append(i['lvlUpCost']) 39 | for i in item['skills']: 40 | for j in i['levelUpCostCond']: 41 | skillCost.append(j['levelUpCost']) 42 | print(name) 43 | if name =="阿米婭": 44 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 45 | 'profession': profession, 'phase1Cost': phase1Cost, 46 | 'phase2Cost': phase2Cost, 47 | '1to2': skillCost[0], '2to3': skillCost[1], 48 | '3to4': skillCost[2], 49 | '4to5': skillCost[3], 50 | '5to6': skillCost[4], '6to7': skillCost[5], 51 | 'S1M1': skillCost[6], 52 | 'S1M2': skillCost[7], 'S1M3': skillCost[8], 53 | 'S2M1': skillCost[9], 54 | 'S2M2': skillCost[10], 'S2M3': skillCost[11], 55 | 'S3M1': skillCost[12], 56 | 'S3M2': skillCost[13], 'S3M3': skillCost[14] 57 | } 58 | }, upsert=True) 59 | else: 60 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 61 | 'profession': profession, 'phase1Cost': phase1Cost, 62 | 'phase2Cost': phase2Cost, 63 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 64 | '4to5': skillCost[3], 65 | '5to6': skillCost[4], '6to7': skillCost[5], 'S1M1': skillCost[6], 66 | 'S1M2':skillCost[7], 'S1M3': skillCost[8], 'S2M1': skillCost[9], 67 | 'S2M2': skillCost[10],'S2M3': skillCost[11] 68 | } 69 | }, upsert=True) 70 | elif rarity ==5: #4,5, and 6* characters 71 | phase1Cost = item['phases'][1]['evolveCost'] 72 | phase2Cost = item['phases'][2]['evolveCost'] 73 | skillCost = [] 74 | for i in item['allSkillLvlup']: 75 | skillCost.append(i['lvlUpCost']) 76 | for i in item['skills']: 77 | for j in i['levelUpCostCond']: 78 | skillCost.append(j['levelUpCost']) 79 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 80 | 'profession': profession, 'phase1Cost': phase1Cost, 81 | 'phase2Cost': phase2Cost, 82 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 83 | '4to5': skillCost[3], 84 | '5to6': skillCost[4], '6to7': skillCost[5], 'S1M1': skillCost[6], 85 | 'S1M2':skillCost[7], 'S1M3': skillCost[8], 'S2M1': skillCost[9], 86 | 'S2M2': skillCost[10],'S2M3': skillCost[11],'S3M1': skillCost[12], 87 | 'S3M2': skillCost[13],'S3M3': skillCost[14] 88 | } 89 | }, upsert=True) 90 | else: #1,2* characters 91 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 92 | 'profession': profession} 93 | }, upsert=True) 94 | 95 | print('\nDone for TW server.') 96 | -------------------------------------------------------------------------------- /AggregationCN.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | import json 3 | server = open('data/server.txt', 'r').readline().strip() 4 | dbclient = pymongo.MongoClient(server) 5 | db = dbclient['ArknightsGamedata'] 6 | 7 | collection = db['CharactersCN'] 8 | 9 | 10 | 11 | with open('data/character_tableCN.json',encoding='UTF-8') as rawFile: 12 | characterTableJSON = json.load(rawFile) 13 | 14 | for key in characterTableJSON.keys(): 15 | if 'token' in key: 16 | continue 17 | item=characterTableJSON[key] 18 | name = item['name'] 19 | rarity = item['rarity'] 20 | profession = item['profession'] 21 | if profession == "TRAP": 22 | continue 23 | if rarity ==2: #3* characters 24 | phase1Cost = item['phases'][1]['evolveCost'] 25 | skillCost = [] 26 | for i in item['allSkillLvlup']: 27 | skillCost.append(i['lvlUpCost']) 28 | print(name) 29 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 30 | 'profession': profession, 31 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 32 | '4to5': skillCost[3], 33 | '5to6': skillCost[4], '6to7': skillCost[5] 34 | } 35 | }, upsert=True) 36 | elif rarity ==3 or rarity == 4: #4 and 5* characters 37 | phase1Cost = item['phases'][1]['evolveCost'] 38 | phase2Cost = item['phases'][2]['evolveCost'] 39 | skillCost = [] 40 | for i in item['allSkillLvlup']: 41 | skillCost.append(i['lvlUpCost']) 42 | for i in item['skills']: 43 | for j in i['levelUpCostCond']: 44 | skillCost.append(j['levelUpCost']) 45 | print(name) 46 | if name =="阿米娅": 47 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 48 | 'profession': profession, 'phase1Cost': phase1Cost, 49 | 'phase2Cost': phase2Cost, 50 | '1to2': skillCost[0], '2to3': skillCost[1], 51 | '3to4': skillCost[2], 52 | '4to5': skillCost[3], 53 | '5to6': skillCost[4], '6to7': skillCost[5], 54 | 'S1M1': skillCost[6], 55 | 'S1M2': skillCost[7], 'S1M3': skillCost[8], 56 | 'S2M1': skillCost[9], 57 | 'S2M2': skillCost[10], 'S2M3': skillCost[11], 58 | 'S3M1': skillCost[12], 59 | 'S3M2': skillCost[13], 'S3M3': skillCost[14] 60 | } 61 | }, upsert=True) 62 | else: 63 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 64 | 'profession': profession, 'phase1Cost': phase1Cost, 65 | 'phase2Cost': phase2Cost, 66 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 67 | '4to5': skillCost[3], 68 | '5to6': skillCost[4], '6to7': skillCost[5], 'S1M1': skillCost[6], 69 | 'S1M2':skillCost[7], 'S1M3': skillCost[8], 'S2M1': skillCost[9], 70 | 'S2M2': skillCost[10],'S2M3': skillCost[11] 71 | } 72 | }, upsert=True) 73 | elif rarity ==5: #4,5, and 6* characters 74 | phase1Cost = item['phases'][1]['evolveCost'] 75 | phase2Cost = item['phases'][2]['evolveCost'] 76 | skillCost = [] 77 | for i in item['allSkillLvlup']: 78 | skillCost.append(i['lvlUpCost']) 79 | for i in item['skills']: 80 | for j in i['levelUpCostCond']: 81 | skillCost.append(j['levelUpCost']) 82 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 83 | 'profession': profession, 'phase1Cost': phase1Cost, 84 | 'phase2Cost': phase2Cost, 85 | '1to2': skillCost[0], '2to3': skillCost[1], '3to4': skillCost[2], 86 | '4to5': skillCost[3], 87 | '5to6': skillCost[4], '6to7': skillCost[5], 'S1M1': skillCost[6], 88 | 'S1M2':skillCost[7], 'S1M3': skillCost[8], 'S2M1': skillCost[9], 89 | 'S2M2': skillCost[10],'S2M3': skillCost[11],'S3M1': skillCost[12], 90 | 'S3M2': skillCost[13],'S3M3': skillCost[14] 91 | } 92 | }, upsert=True) 93 | else: #1,2* characters 94 | collection.update_one({'_id': name}, {'$set': {'rarity': rarity, 95 | 'profession': profession} 96 | }, upsert=True) 97 | 98 | print('\nDone for CN server.') 99 | -------------------------------------------------------------------------------- /update_db_TW.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Jan 28 14:13:20 2020 4 | 5 | @author: sqr_p 6 | """ 7 | 8 | import pymongo 9 | from MaterialPlanning import MaterialPlanning 10 | import time 11 | from dateutil import parser 12 | from utils import required_dctTW, owned_dct, aggregation, collectionTW 13 | 14 | aggregation(collectionTW, required_dctTW, "阿米婭") 15 | 16 | update_time = parser.parse(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime())) 17 | print(update_time) 18 | print('正在从企鹅物流获取数据...') 19 | server = open('data/server.txt', 'r').readline().strip() 20 | dbclient = pymongo.MongoClient(server) 21 | db = dbclient['Arknights_OneGraph'] 22 | 23 | Filter_special_items = ['荒芜行动物资补给', '罗德岛物资补给', '岁过华灯', '32h战略配给','利刃行动物资补给','黄铁行动物资补给'] 24 | Filter_special_stages = ['S4-4', 'S6-4', 'S4-9']+['S3-6','S4-10','S5-8','S5-7'] 25 | 26 | 27 | # Calculation for TW server 28 | collection = db['Material_TW'] 29 | StagesNotAval = ['7-%d'%x for x in range(1,19)]+['6-%d'%x for x in range(1,18)]+['S7-1','S7-2']+['S6-%d'%x for x in range(1,6)] 30 | StagesNotAval.extend(['R8-%d'%x for x in range(1, 12)] + ['M8-6', 'M8-7', 'M8-8'] + ['JT8-%d'%x for x in range(1, 4)]) 31 | print(StagesNotAval) 32 | Event_Stages = ['OF-%d'%x for x in range(1,9)] 33 | mp_event = MaterialPlanning(filter_stages=Filter_special_stages + Filter_special_items+StagesNotAval, 34 | filter_freq=100, 35 | update=True, 36 | printSetting='000011101100' 37 | ) 38 | mp_event.get_plan(required_dctTW, owned_dct, print_output=False, outcome=True, 39 | gold_demand=True, exp_demand=True) 40 | mp = MaterialPlanning(filter_stages=Filter_special_stages + Filter_special_items + Event_Stages+StagesNotAval, 41 | filter_freq=100, 42 | update=True, 43 | printSetting='000011101100' 44 | ) 45 | mp.get_plan(required_dctTW, owned_dct, print_output=False, outcome=True, 46 | gold_demand=True, exp_demand=True) 47 | [mp_event.output_best_stage(x) for x in '123'] 48 | [mp.output_best_stage(x) for x in '123'] 49 | print('正在更新TW服数据库') 50 | for k, v in sorted(mp.effect.items(), key=lambda x: x[1], reverse=True): 51 | print(f'已更新关卡{k}, 效率{100*v:.2f}', end=' ') 52 | db['StagesTW'].update_one({'code': k}, {'$set': {'efficiency': v , 'sampleSize': mp.stage_times[k]}},upsert=True) 53 | 54 | for item in collection.find(): 55 | x = item['name'] 56 | print('已更新%s\t' % x, end='\t') 57 | collection.update_one({'_id': item['_id']}, 58 | {'$set': {'contingency_store_value': {'infinite': '%.3f'%mp.HeYueDict[x] if x in mp.HeYueDict else '0.0', 59 | 'finite': '%.3f'%mp.HYODict[x] if x in mp.HYODict else '0.0'}} 60 | },upsert=True) 61 | 62 | if 'credit_store_value' in item: 63 | if item['name'] in mp.best_stage: 64 | collection.update_one({'_id': item['_id']}, 65 | {'$set': {'credit_store_value': {'event': '%.3f'%(100*mp_event.creditEffect[item['name']]), 66 | 'normal': '%.3f'%(100*mp.creditEffect[item['name']])}, 67 | 'Notes': {'event': mp_event.Notes[item['name']], 68 | 'normal': mp.Notes[item['name']]}, 69 | 'lowest_ap_stages': {'event': mp_event.best_stage[item['name']]['lowest_ap_stages'], 70 | 'normal': mp.best_stage[item['name']]['lowest_ap_stages']}, 71 | 'balanced_stages': {'event': mp_event.best_stage[item['name']]['balanced_stages'], 72 | 'normal': mp.best_stage[item['name']]['balanced_stages']}, 73 | 'drop_rate_first_stages': {'event': mp_event.best_stage[item['name']]['drop_rate_first_stages'], 74 | 'normal': mp.best_stage[item['name']]['drop_rate_first_stages']}, 75 | 'last_updated': update_time 76 | } 77 | },upsert=True) 78 | else: 79 | collection.update_one({'_id': item['_id']}, 80 | {'$set': {'credit_store_value': {'event': '%.3f'%(100*mp_event.creditEffect[item['name']]), 81 | 'normal': '%.3f'%(100*mp.creditEffect[item['name']])}, 82 | 'Notes': {'event': mp_event.Notes[item['name']], 83 | 'normal': mp.Notes[item['name']]}, 84 | 'lowest_ap_stages': {'event': [], 85 | 'normal': []}, 86 | 'balanced_stages': {'event': [], 87 | 'normal': []}, 88 | 'drop_rate_first_stages': {'event': [], 89 | 'normal': []}, 90 | 'last_updated': update_time} 91 | },upsert=True) 92 | if 'green_ticket_value' in item: 93 | if item['name'] in mp.best_stage: 94 | collection.update_one({'_id': item['_id']}, 95 | {'$set': {'green_ticket_value': {'event': '%.3f'%(mp_event.greenTickets[item['name']]), 96 | 'normal': '%.3f'%(mp.greenTickets[item['name']])}, 97 | 'Notes': {'event': mp_event.Notes[item['name']], 98 | 'normal': mp.Notes[item['name']]}, 99 | 'lowest_ap_stages': {'event': mp_event.best_stage[item['name']]['lowest_ap_stages'], 100 | 'normal': mp.best_stage[item['name']]['lowest_ap_stages']}, 101 | 'balanced_stages': {'event': mp_event.best_stage[item['name']]['balanced_stages'], 102 | 'normal': mp.best_stage[item['name']]['balanced_stages']}, 103 | 'drop_rate_first_stages': {'event': mp_event.best_stage[item['name']]['drop_rate_first_stages'], 104 | 'normal': mp.best_stage[item['name']]['drop_rate_first_stages']}, 105 | 'last_updated': update_time}},upsert=True) 106 | else: 107 | collection.update_one({'_id': item['_id']}, 108 | {'$set': {'green_ticket_value': {'event': '%.3f'%(mp_event.greenTickets[item['name']]), 109 | 'normal': '%.3f'%(mp.greenTickets[item['name']])}, 110 | 'Notes': {'event': mp_event.Notes[item['name']], 111 | 'normal': mp.Notes[item['name']]}, 112 | 'lowest_ap_stages': {'event': [], 113 | 'normal': []}, 114 | 'balanced_stages': {'event': [], 115 | 'normal': []}, 116 | 'drop_rate_first_stages': {'event': [], 117 | 'normal': []}, 118 | 'last_updated': update_time}},upsert=True) 119 | if 'golden_ticket_value' in item: 120 | collection.update_one({'_id': item['_id']}, 121 | {'$set': {'golden_ticket_value': {'event': '%.3f'%(mp_event.yellowTickets[item['name']]), 122 | 'normal': '%.3f'%(mp.yellowTickets[item['name']])}, 123 | 'Notes': {'event': mp_event.Notes[item['name']], 124 | 'normal': mp.Notes[item['name']]}, 125 | 'last_updated': update_time}},upsert=True) 126 | 127 | print('\nTW服更新完成.') 128 | -------------------------------------------------------------------------------- /update_db_ENJPKR.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Jan 28 14:13:20 2020 4 | 5 | @author: sqr_p 6 | """ 7 | 8 | import pymongo 9 | from MaterialPlanning import MaterialPlanning 10 | import time 11 | from dateutil import parser 12 | from utils import required_dctENJPKR, owned_dct, aggregation, collectionENJPKR 13 | from discord_webhook import DiscordWebhook, DiscordEmbed 14 | 15 | aggregation(collectionENJPKR,required_dctENJPKR,"Amiya") 16 | 17 | update_time = parser.parse(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime())) 18 | print(update_time) 19 | print('正在从企鹅物流获取数据...') 20 | server = open('data/server.txt', 'r').readline().strip() 21 | dbclient = pymongo.MongoClient(server) 22 | db = dbclient['Arknights_OneGraph'] 23 | 24 | Filter_special_items = ['荒芜行动物资补给', '罗德岛物资补给', '岁过华灯', '32h战略配给', '感谢庆典物资补给'] 25 | Filter_special_stages = ['S4-4', 'S6-4','S4-9'] 26 | 27 | 28 | # Calculation for EN, JP and KR server 29 | collection = db['Material_ENJPKR'] 30 | StagesNotAval = ['7-%d'%x for x in range(1, 19)]+['S7-1', 'S7-2']+['RI-%d'%x for x in range(1, 9)] #chapter 7 31 | StagesNotAval.extend(['R8-%d'%x for x in range(1, 12)] + ['M8-6', 'M8-7', 'M8-8'] + ['JT8-%d'%x for x in range(1, 4)]) 32 | print(StagesNotAval) 33 | Event_Stages = ['FA-%d'%x for x in range(1, 9)] 34 | mp_event = MaterialPlanning(filter_stages=Filter_special_stages + Filter_special_items+StagesNotAval, 35 | filter_freq=100, 36 | update=True, 37 | printSetting='000011101100' 38 | ) 39 | mp_event.get_plan(required_dctENJPKR, owned_dct, print_output=False, outcome=True, 40 | gold_demand=True, exp_demand=True) 41 | mp = MaterialPlanning(filter_stages=Filter_special_stages + Filter_special_items + Event_Stages+StagesNotAval, 42 | filter_freq=100, 43 | update=True, 44 | printSetting='000011101100' 45 | ) 46 | mp.get_plan(required_dctENJPKR, owned_dct, print_output=False, outcome=True, 47 | gold_demand=True, exp_demand=True) 48 | [mp_event.output_best_stage(x) for x in '123'] 49 | [mp.output_best_stage(x) for x in '123'] 50 | print('正在更新EN, JP和KR服数据库') 51 | for k, v in sorted(mp.effect.items(), key=lambda x: x[1], reverse=True): 52 | print(f'已更新关卡{k}, 效率{100*v:.2f}', end=' ') 53 | db['StagesENJPKR'].update_one({'code': k}, {'$set': {'efficiency': v , 'sampleSize': mp.stage_times[k]}},upsert=True) 54 | 55 | for item in collection.find(): 56 | x = item['name'] 57 | print('已更新%s\t' % x, end='\t') 58 | collection.update_one({'_id': item['_id']}, 59 | {'$set': {'contingency_store_value': {'infinite': '%.3f'%mp.HeYueDict[x] if x in mp.HeYueDict else '0.0', 60 | 'finite': '%.3f'%mp.HYODict[x] if x in mp.HYODict else '0.0'}} 61 | },upsert=True) 62 | 63 | if 'credit_store_value' in item: 64 | if item['name'] in mp.best_stage: 65 | collection.update_one({'_id': item['_id']}, 66 | {'$set': {'credit_store_value': {'event': '%.3f'%(100*mp_event.creditEffect[item['name']]), 67 | 'normal': '%.3f'%(100*mp.creditEffect[item['name']])}, 68 | 'Notes': {'event': mp_event.Notes[item['name']], 69 | 'normal': mp.Notes[item['name']]}, 70 | 'lowest_ap_stages': {'event': mp_event.best_stage[item['name']]['lowest_ap_stages'], 71 | 'normal': mp.best_stage[item['name']]['lowest_ap_stages']}, 72 | 'balanced_stages': {'event': mp_event.best_stage[item['name']]['balanced_stages'], 73 | 'normal': mp.best_stage[item['name']]['balanced_stages']}, 74 | 'drop_rate_first_stages': {'event': mp_event.best_stage[item['name']]['drop_rate_first_stages'], 75 | 'normal': mp.best_stage[item['name']]['drop_rate_first_stages']}, 76 | 'last_updated': update_time 77 | } 78 | },upsert=True) 79 | else: 80 | collection.update_one({'_id': item['_id']}, 81 | {'$set': {'credit_store_value': {'event': '%.3f'%(100*mp_event.creditEffect[item['name']]), 82 | 'normal': '%.3f'%(100*mp.creditEffect[item['name']])}, 83 | 'Notes': {'event': mp_event.Notes[item['name']], 84 | 'normal': mp.Notes[item['name']]}, 85 | 'lowest_ap_stages': {'event': [], 86 | 'normal': []}, 87 | 'balanced_stages': {'event': [], 88 | 'normal': []}, 89 | 'drop_rate_first_stages': {'event': [], 90 | 'normal': []}, 91 | 'last_updated': update_time} 92 | },upsert=True) 93 | if 'green_ticket_value' in item: 94 | if item['name'] in mp.best_stage: 95 | collection.update_one({'_id': item['_id']}, 96 | {'$set': {'green_ticket_value': {'event': '%.3f'%(mp_event.greenTickets[item['name']]), 97 | 'normal': '%.3f'%(mp.greenTickets[item['name']])}, 98 | 'Notes': {'event': mp_event.Notes[item['name']], 99 | 'normal': mp.Notes[item['name']]}, 100 | 'lowest_ap_stages': {'event': mp_event.best_stage[item['name']]['lowest_ap_stages'], 101 | 'normal': mp.best_stage[item['name']]['lowest_ap_stages']}, 102 | 'balanced_stages': {'event': mp_event.best_stage[item['name']]['balanced_stages'], 103 | 'normal': mp.best_stage[item['name']]['balanced_stages']}, 104 | 'drop_rate_first_stages': {'event': mp_event.best_stage[item['name']]['drop_rate_first_stages'], 105 | 'normal': mp.best_stage[item['name']]['drop_rate_first_stages']}, 106 | 'last_updated': update_time}},upsert=True) 107 | else: 108 | collection.update_one({'_id': item['_id']}, 109 | {'$set': {'green_ticket_value': {'event': '%.3f'%(mp_event.greenTickets[item['name']]), 110 | 'normal': '%.3f'%(mp.greenTickets[item['name']])}, 111 | 'Notes': {'event': mp_event.Notes[item['name']], 112 | 'normal': mp.Notes[item['name']]}, 113 | 'lowest_ap_stages': {'event': [], 114 | 'normal': []}, 115 | 'balanced_stages': {'event': [], 116 | 'normal': []}, 117 | 'drop_rate_first_stages': {'event': [], 118 | 'normal': []}, 119 | 'last_updated': update_time}},upsert=True) 120 | if 'golden_ticket_value' in item: 121 | collection.update_one({'_id': item['_id']}, 122 | {'$set': {'golden_ticket_value': {'event': '%.3f'%(mp_event.yellowTickets[item['name']]), 123 | 'normal': '%.3f'%(mp.yellowTickets[item['name']])}, 124 | 'Notes': {'event': mp_event.Notes[item['name']], 125 | 'normal': mp.Notes[item['name']]}, 126 | 'last_updated': update_time}},upsert=True) 127 | 128 | print('\nEn,JP,KR服更新完成.') 129 | -------------------------------------------------------------------------------- /update_db_new.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Jan 28 14:13:20 2020 4 | 5 | @author: sqr_p 6 | """ 7 | 8 | import pymongo 9 | from MaterialPlanning import MaterialPlanning 10 | import time 11 | from dateutil import parser 12 | from utils import required_dctCN, owned_dct, aggregation, collectionCN 13 | from discord_webhook import DiscordWebhook, DiscordEmbed 14 | 15 | CCSeason = 4 16 | message = """Error when updating arkonegraph""" 17 | webhook_link= open('data/discordbot.txt', 'r').readline().strip() 18 | webhook = DiscordWebhook(url=webhook_link) 19 | aggregation(collectionCN, required_dctCN, "阿米娅") 20 | update_time = parser.parse(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime())) 21 | print(update_time) 22 | print('正在从企鹅物流获取数据...') 23 | server = open('data/server.txt', 'r').readline().strip() 24 | dbclient = pymongo.MongoClient(server) 25 | db = dbclient['Arknights_OneGraph'] 26 | 27 | Filter_special_items = ['荒芜行动物资补给', '罗德岛物资补给', '岁过华灯', '32h战略配给', '感谢庆典物资补给', 28 | '应急理智小样', '黄铁行动物资补给', '利刃行动物资补给', '燃灰行动物资补给'] 29 | Filter_special_stages = ['S4-4', 'S6-4','S4-9'] 30 | 31 | # Calculation for CN server 32 | collection = db['Material_Event'] 33 | Event_Stages = ['WR-%d'%x for x in range(1, 9)] 34 | try: 35 | mp_event = MaterialPlanning(filter_stages=Filter_special_stages + Filter_special_items, 36 | filter_freq=100, 37 | update=True, 38 | printSetting='000011101111',CCSeason=CCSeason 39 | ) 40 | mp_event.get_plan(required_dctCN, owned_dct, print_output=False, outcome=True, 41 | gold_demand=True, exp_demand=True) 42 | 43 | 44 | mp_expFromBase = MaterialPlanning(filter_stages=Filter_special_stages + Filter_special_items + Event_Stages, 45 | filter_freq=100, 46 | update=False, 47 | printSetting='000011101111',CCSeason=CCSeason, 48 | ExpFromBase=True 49 | ) 50 | mp_expFromBase.get_plan(required_dctCN, owned_dct, print_output=False, outcome=True, 51 | gold_demand=True, exp_demand=True) 52 | 53 | 54 | mp = MaterialPlanning(filter_stages=Filter_special_stages + Filter_special_items + Event_Stages, 55 | # mp = MaterialPlanning(filter_stages=Filter_special_stages + Filter_special_items, 56 | filter_freq=100, 57 | update=False, 58 | printSetting='000011101111',CCSeason=CCSeason 59 | ) 60 | 61 | [mp_event.output_best_stage(x) for x in '123'] 62 | [mp.output_best_stage(x) for x in '123'] 63 | print('正在更新CN服数据库') 64 | for k, v in sorted(mp_event.effect.items(), key=lambda x: x[1], reverse=True): 65 | print(f'已更新关卡{k}, 效率{100*v:.2f}', end=' ') 66 | db['Stages'].update_one({'code': k}, {'$set': {'efficiency': v , 'sampleSize': mp.stage_times[k]}},upsert=True) 67 | 68 | 69 | for item in collection.find(): 70 | x = item['name'] 71 | print('已更新%s\t' % x, end='\t') 72 | 73 | collection.update_one({'_id': item['_id']}, 74 | {'$set': {'contingency_store_value': {'infinite': '%.3f'%mp.HeYueDict[x] if x in mp.HeYueDict else '0.0', 75 | 'finite': '%.3f'%mp.HYODict[x] if x in mp.HYODict else '0.0'}} 76 | }) 77 | if item['name'] in mp.orangeTickets: 78 | collection.update_one({'_id': item['_id']}, 79 | {'$set': {'orange_store_value': {'event': '%.3f'%mp_event.orangeTickets[item['name']], 80 | 'normal': '%.3f'%mp.orangeTickets[item['name']]}, 81 | 'orange_note': {'event': mp_event.orangeNotes[item['name']], 82 | 'normal': mp.orangeNotes[item['name']]} 83 | } 84 | }) 85 | if 'credit_store_value' in item: 86 | if item['name'] in mp.best_stage: 87 | collection.update_one({'_id': item['_id']}, 88 | {'$set': {'credit_store_value': {'event': '%.3f'%(100*mp_event.creditEffect[item['name']]), 89 | 'normal': '%.3f'%(100*mp.creditEffect[item['name']])}, 90 | 'Notes': {'event': mp_event.Notes[item['name']], 91 | 'normal': mp.Notes[item['name']]}, 92 | 'lowest_ap_stages': {'event': mp_event.best_stage[item['name']]['lowest_ap_stages'], 93 | 'normal': mp.best_stage[item['name']]['lowest_ap_stages']}, 94 | 'balanced_stages': {'event': mp_event.best_stage[item['name']]['balanced_stages'], 95 | 'normal': mp.best_stage[item['name']]['balanced_stages']}, 96 | 'drop_rate_first_stages': {'event': mp_event.best_stage[item['name']]['drop_rate_first_stages'], 97 | 'normal': mp.best_stage[item['name']]['drop_rate_first_stages']}, 98 | 'last_updated': update_time 99 | } 100 | }) 101 | else: 102 | collection.update_one({'_id': item['_id']}, 103 | {'$set': {'credit_store_value': {'event': '%.3f'%(100*mp_event.creditEffect[item['name']]), 104 | 'normal': '%.3f'%(100*mp.creditEffect[item['name']])}, 105 | 'Notes': {'event': mp_event.Notes[item['name']], 106 | 'normal': mp.Notes[item['name']]}, 107 | 'lowest_ap_stages': {'event': [], 108 | 'normal': []}, 109 | 'balanced_stages': {'event': [], 110 | 'normal': []}, 111 | 'drop_rate_first_stages': {'event': [], 112 | 'normal': []}, 113 | 'last_updated': update_time} 114 | }) 115 | if 'green_ticket_value' in item: 116 | if item['name'] in mp.best_stage: 117 | collection.update_one({'_id': item['_id']}, 118 | {'$set': {'green_ticket_value': {'event': '%.3f'%(mp_event.greenTickets[item['name']]), 119 | 'normal': '%.3f'%(mp.greenTickets[item['name']])}, 120 | 'Notes': {'event': mp_event.Notes[item['name']], 121 | 'normal': mp.Notes[item['name']]}, 122 | 'lowest_ap_stages': {'event': mp_event.best_stage[item['name']]['lowest_ap_stages'], 123 | 'normal': mp.best_stage[item['name']]['lowest_ap_stages']}, 124 | 'balanced_stages': {'event': mp_event.best_stage[item['name']]['balanced_stages'], 125 | 'normal': mp.best_stage[item['name']]['balanced_stages']}, 126 | 'drop_rate_first_stages': {'event': mp_event.best_stage[item['name']]['drop_rate_first_stages'], 127 | 'normal': mp.best_stage[item['name']]['drop_rate_first_stages']}, 128 | 'last_updated': update_time}}) 129 | else: 130 | collection.update_one({'_id': item['_id']}, 131 | {'$set': {'green_ticket_value': {'event': '%.3f'%(mp_event.greenTickets[item['name']]), 132 | 'normal': '%.3f'%(mp.greenTickets[item['name']])}, 133 | 'Notes': {'event': mp_event.Notes[item['name']], 134 | 'normal': mp.Notes[item['name']]}, 135 | 'lowest_ap_stages': {'event': [], 136 | 'normal': []}, 137 | 'balanced_stages': {'event': [], 138 | 'normal': []}, 139 | 'drop_rate_first_stages': {'event': [], 140 | 'normal': []}, 141 | 'last_updated': update_time}}) 142 | if 'golden_ticket_value' in item: 143 | collection.update_one({'_id': item['_id']}, 144 | {'$set': {'golden_ticket_value': {'event': '%.3f'%(mp_event.yellowTickets[item['name']]), 145 | 'normal': '%.3f'%(mp.yellowTickets[item['name']])}, 146 | 'Notes': {'event': mp_event.Notes[item['name']], 147 | 'normal': mp.Notes[item['name']]}, 148 | 'last_updated': update_time}}) 149 | embed = DiscordEmbed(title='Scripts ran', description='running ok without errors', color=242424) 150 | # add embed object to webhook 151 | webhook.add_embed(embed) 152 | response = webhook.execute() 153 | 154 | except: 155 | embed = DiscordEmbed(title='Scripts ran', description='ERROR!!', color=15158332) 156 | # add embed object to webhook 157 | webhook.add_embed(embed) 158 | response = webhook.execute() 159 | 160 | print('\nCN服更新完成.') 161 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Oct 16 22:32:11 2019 4 | 5 | @author: sqr_p 6 | @modified: strontium 7 | """ 8 | import codecs 9 | import pymongo 10 | import json 11 | # Aggregation 12 | def aggregation(collection, required_dct, heroine_name): 13 | # Initialization 14 | figureCount = { 15 | '1/2-Star': 0, 16 | '3-Star': 0, 17 | '4-Star': 0, 18 | '5-Star': 0, 19 | '6-Star': 0 20 | } 21 | bookCount = { 22 | '技巧概要·卷1': 0, 23 | '技巧概要·卷2': 0, 24 | '技巧概要·卷3': 0 25 | } 26 | 27 | # Lookup Tables 28 | skillLvlCost = ['1to2', '2to3', '3to4', '4to5', '5to6', '6to7', 29 | 'S1M1', 'S1M2', 'S1M3', 'S2M1', 'S2M2', 'S2M3', 30 | 'S3M1', 'S3M2', 'S3M3'] 31 | classesList = {'MEDIC': '医疗', 'WARRIOR': '近卫', 'SPECIAL': '特种', 'TANK': '重装', 'PIONEER': '先锋', 'SNIPER': '狙击', 32 | 'CASTER': '术师', 33 | 'SUPPORT': '辅助'} 34 | for item in collection.find(): 35 | if item['rarity']<2: #1,2* 36 | figureCount['1/2-Star'] +=1 37 | 38 | elif item['rarity'] == 2: #3* 39 | figureCount['3-Star'] += 1 40 | for i in range(0,6): 41 | for k in item[skillLvlCost[i]]: 42 | if k['id'] == '3301': 43 | bookCount['技巧概要·卷1'] += k['count'] 44 | elif k['id'] == '3302': 45 | bookCount['技巧概要·卷2'] += k['count'] 46 | elif k['id'] == '3303': 47 | bookCount['技巧概要·卷3'] += k['count'] 48 | elif k['id'] in Item_table.keys(): 49 | required_dct[Item_table[k['id']]] += k['count'] 50 | 51 | elif item['rarity'] == 3: #4* 52 | figureCount['4-Star'] += 1 53 | profession = classesList[item['profession']] 54 | required_dct[profession+'芯片']+=3 55 | required_dct[profession + '双芯片'] += 5 56 | for i in range(0,12): 57 | for k in item[skillLvlCost[i]]: 58 | if k['id'] == '3301': 59 | bookCount['技巧概要·卷1'] += k['count'] 60 | elif k['id'] == '3302': 61 | bookCount['技巧概要·卷2'] += k['count'] 62 | elif k['id'] == '3303': 63 | bookCount['技巧概要·卷3'] += k['count'] 64 | elif k['id'] in Item_table.keys(): 65 | required_dct[Item_table[k['id']]] += k['count'] 66 | 67 | elif item['rarity'] == 4: #5* 68 | figureCount['5-Star'] += 1 69 | profession = classesList[item['profession']] 70 | required_dct[profession + '芯片'] += 4 71 | required_dct[profession + '芯片组'] += 3 72 | if item['_id'] != heroine_name: 73 | for i in range(0, 12): 74 | for k in item[skillLvlCost[i]]: 75 | if k['id'] == '3301': 76 | bookCount['技巧概要·卷1'] += k['count'] 77 | elif k['id'] == '3302': 78 | bookCount['技巧概要·卷2'] += k['count'] 79 | elif k['id'] == '3303': 80 | bookCount['技巧概要·卷3'] += k['count'] 81 | elif k['id'] in Item_table.keys(): 82 | required_dct[Item_table[k['id']]] += k['count'] 83 | else: 84 | for i in range(0, 15): 85 | for k in item[skillLvlCost[i]]: 86 | if k['id'] == '3301': 87 | bookCount['技巧概要·卷1'] += k['count'] 88 | elif k['id'] == '3302': 89 | bookCount['技巧概要·卷2'] += k['count'] 90 | elif k['id'] == '3303': 91 | bookCount['技巧概要·卷3'] += k['count'] 92 | elif k['id'] in Item_table.keys(): 93 | required_dct[Item_table[k['id']]] += k['count'] 94 | 95 | else: #6* 96 | figureCount['6-Star'] +=1 97 | profession = classesList[item['profession']] 98 | required_dct[profession + '芯片'] += 5 99 | required_dct[profession + '芯片组'] += 4 100 | for i in range(0, 15): 101 | for k in item[skillLvlCost[i]]: 102 | if k['id'] == '3301': 103 | bookCount['技巧概要·卷1'] += k['count'] 104 | elif k['id'] == '3302': 105 | bookCount['技巧概要·卷2'] += k['count'] 106 | elif k['id'] == '3303': 107 | bookCount['技巧概要·卷3'] += k['count'] 108 | elif k['id'] in Item_table.keys(): 109 | required_dct[Item_table[k['id']]] += k['count'] 110 | exp_required = { 111 | '1/2-Star': 9800, 112 | '3-Star': 115400, 113 | '4-Star': 484000, 114 | '5-Star': 734400, 115 | '6-Star': 1111400 116 | } 117 | gold_required = { 118 | '1/2-Star': 5323, 119 | '3-Star': 104040, 120 | '4-Star': 482003, 121 | '5-Star': 819325, 122 | '6-Star': 1334769 123 | } 124 | required_dct.update({ 125 | '经验': sum(v * exp_required[k] for k, v in figureCount.items()), 126 | '龙门币': sum(v * gold_required[k] for k, v in figureCount.items()), 127 | '家具零件': 10000, 128 | '采购凭证': 1000 129 | }) 130 | # required_dct.update({ 131 | # '经验': 0, 132 | # '龙门币': 0, 133 | # '家具零件': 0 134 | # }) 135 | # required_dct.update({# 更新时间: 2020/4/23 傀影池 136 | # '技巧概要·卷1': 818, 137 | # '技巧概要·卷2': 1812, 138 | # '技巧概要·卷3': 5911 139 | # }) 140 | required_dct.update(bookCount) 141 | if heroine_name != "阿米婭": 142 | required_dct.update({ # 扩大价值,否则橙票商店会崩溃 143 | '凝胶': 261, 144 | '聚合凝胶': 384, 145 | '炽合金': 248, 146 | '炽合金块': 366 147 | }) 148 | if heroine_name == "阿米娅": 149 | required_dct.update({ # 扩大价值,否则橙票商店会崩溃 150 | '晶体电路': 100, 151 | '晶体元件': 100, 152 | '晶体电子单元': 100 153 | }) 154 | print(required_dct) 155 | return required_dct 156 | 157 | 158 | server = open('data/server.txt', 'r').readline().strip() 159 | dbclient = pymongo.MongoClient(server) 160 | db = dbclient['ArknightsGamedata'] 161 | collectionCN = db['CharactersCN'] 162 | collectionENJPKR = db['CharactersENJPKR'] 163 | collectionTW = db['CharactersTW'] 164 | 165 | Price = dict() 166 | with open('data/price.txt', 'r', encoding='utf8') as f: 167 | for line in f.readlines(): 168 | name, value = line.split() 169 | Price[name] = int(value) 170 | 171 | Credit = dict() 172 | with open('data/creditPrice.txt', 'r', encoding='utf8') as f: 173 | for line in f.readlines(): 174 | name, value = line.split() 175 | Credit[name] = float(value) 176 | 177 | HeYue_1 = dict() 178 | with open('data/HeYue-1.txt', 'r', encoding='utf8') as f: 179 | for line in f.readlines(): 180 | name, value = line.split() 181 | HeYue_1[name] = float(eval(value)) 182 | 183 | HYO_1 = dict() 184 | with open('data/HeYueOrd-1.txt', 'r', encoding='utf8') as f: 185 | for line in f.readlines(): 186 | name, value = line.split() 187 | HYO_1[name] = float(eval(value)) 188 | 189 | HeYue0 = dict() 190 | with open('data/HeYue0.txt', 'r', encoding='utf8') as f: 191 | for line in f.readlines(): 192 | name, value = line.split() 193 | HeYue0[name] = float(eval(value)) 194 | 195 | HYO0 = dict() 196 | with open('data/HeYueOrd0.txt', 'r', encoding='utf8') as f: 197 | for line in f.readlines(): 198 | name, value = line.split() 199 | HYO0[name] = float(eval(value)) 200 | 201 | HeYue1 = dict() 202 | with open('data/HeYue1.txt', 'r', encoding='utf8') as f: 203 | for line in f.readlines(): 204 | name, value = line.split() 205 | HeYue1[name] = float(eval(value)) 206 | 207 | HYO1 = dict() 208 | with open('data/HeYueOrd1.txt', 'r', encoding='utf8') as f: 209 | for line in f.readlines(): 210 | name, value = line.split() 211 | HYO1[name] = float(eval(value)) 212 | 213 | HeYue2 = dict() 214 | with open('data/HeYue2.txt', 'r', encoding='utf8') as f: 215 | for line in f.readlines(): 216 | name, value = line.split() 217 | HeYue2[name] = float(eval(value)) 218 | 219 | HYO2 = dict() 220 | with open('data/HeYueOrd2.txt', 'r', encoding='utf8') as f: 221 | for line in f.readlines(): 222 | name, value = line.split() 223 | HYO2[name] = float(eval(value)) 224 | 225 | HeYue3 = dict() 226 | with open('data/HeYue3.txt', 'r', encoding='utf8') as f: 227 | for line in f.readlines(): 228 | name, value = line.split() 229 | HeYue3[name] = float(eval(value)) 230 | 231 | HYO3 = dict() 232 | with open('data/HeYueOrd3.txt', 'r', encoding='utf8') as f: 233 | for line in f.readlines(): 234 | name, value = line.split() 235 | HYO3[name] = float(eval(value)) 236 | HeYue4 = dict() 237 | with open('data/HeYue4.txt', 'r', encoding='utf8') as f: 238 | for line in f.readlines(): 239 | name, value = line.split() 240 | HeYue3[name] = float(eval(value)) 241 | 242 | HYO4 = dict() 243 | with open('data/HeYueOrd4.txt', 'r', encoding='utf8') as f: 244 | for line in f.readlines(): 245 | name, value = line.split() 246 | HYO3[name] = float(eval(value)) 247 | 248 | CCStores = [HeYue_1, HYO_1, HeYue0, HYO0, HeYue1, HYO1, HeYue2, HYO2,HeYue3, HYO3, HeYue4, HYO4] 249 | 250 | Orange = dict() 251 | with open('data/orange.txt', 'r', encoding='utf-8') as f: 252 | for line in f.readlines(): 253 | name, value = line.split() 254 | Orange[name] = float(eval(value)) 255 | 256 | Purple = dict() 257 | with open('data/purple.txt', 'r', encoding='utf-8') as f: 258 | for line in f.readlines(): 259 | name, value = line.split() 260 | Purple[name] = float(eval(value)) 261 | 262 | with codecs.open('data/materialIO.txt', 'r', 'utf-8') as f: 263 | material = eval(f.readline()) 264 | required_dctCN = {x['name']: 0 for x in material} 265 | required_dctENJPKR = {x['name']: 0 for x in material} 266 | required_dctTW = {x['name']: 0 for x in material} 267 | owned_dct = {x['name']: x['have'] for x in material} 268 | 269 | with open('data/chips.csv', 'r', encoding='utf-8') as f: 270 | class_name = f.readline().strip().split(',')[1:] 271 | for _ in range(3): 272 | content = f.readline().strip().split(',') 273 | item_name, num = content[0], [int(x) for x in content[1:]] 274 | for i in range(8): 275 | required_dctCN.update({class_name[i] + item_name: 0}) 276 | required_dctENJPKR.update({class_name[i] + item_name: 0}) 277 | required_dctTW.update({class_name[i] + item_name: 0}) 278 | 279 | Item_table = dict() 280 | with open('data/item_table.json', encoding='UTF-8') as rawFile: 281 | itemTable = json.load(rawFile) 282 | materialTable = itemTable['items'] 283 | for item in materialTable.keys(): 284 | if materialTable[item]['itemType'] == 'MATERIAL' and item.isdigit() and len(item)==5 and item !='32001': 285 | Item_table.update({materialTable[item]['itemId']: materialTable[item]['name']}) 286 | 287 | # 当前干员数量 288 | # figureCount = {# 更新时间: 2020/06/02 石棉/月禾池 289 | # '1/2-Star': 7, 290 | # '3-Star': 17, 291 | # '4-Star': 37, 292 | # '5-Star': 52, 293 | # '6-Star': 22 294 | # } 295 | 296 | 297 | # Aggregation on number of characters in DB for all 3 servers 298 | # It is AAAAAAAAAAAAAUUUUUUUTTTTTOOOOOOMMATIC! 299 | # aggregation(collectionCN,required_dctCN,"阿米娅") 300 | # aggregation(collectionENJPKR,required_dctENJPKR,"Amiya") 301 | # aggregation(collectionTW,required_dctTW,"阿米婭") 302 | 303 | owned_dct.update({'经验': 0, '龙门币': 0, '技巧概要·卷3': 0, 304 | '技巧概要·卷2': 0, '技巧概要·卷1': 0}) 305 | 306 | 凝胶_group = {'固源岩组':[4/3, 60/171*4], 307 | '扭转醇':[3/3, 45/171*4], 308 | '全新装置':[2/3, 30/171*4]} 309 | 310 | 凝胶_update = { 311 | '4-10': '全新装置', 312 | '4-4': '扭转醇', 313 | '4-7': '', 314 | '5-5': '', 315 | '4-6': '固源岩组', 316 | '4-1': '', 317 | '4-3': '' 318 | } 319 | 320 | 炽合金_group = {'糖组':[5/13*3, 5/17*4], 321 | '轻锰矿':[4/13*3, 4/17*4], 322 | '异铁组':[4/13*3, 4/17*4]} 323 | 324 | 炽合金_update = { 325 | '5-6': '轻锰矿', 326 | 'S4-7': '', 327 | 'S4-3': '', 328 | 'S4-9': '', 329 | 'S4-1': '异铁组', 330 | '4-2': '糖组', 331 | 'S4-4': '', 332 | 'S4-6': '' 333 | } 334 | 335 | -------------------------------------------------------------------------------- /data/stages.json: -------------------------------------------------------------------------------- 1 | {"main_00-01": {"code": "0-1", "cost": 6}, "main_00-02": {"code": "0-2", "cost": 6}, "main_00-03": {"code": "0-3", "cost": 6}, "main_00-04": {"code": "0-4", "cost": 6}, "main_00-05": {"code": "0-5", "cost": 6}, "main_00-06": {"code": "0-6", "cost": 6}, "main_00-07": {"code": "0-7", "cost": 6}, "main_00-08": {"code": "0-8", "cost": 6}, "main_00-09": {"code": "0-9", "cost": 6}, "main_00-10": {"code": "0-10", "cost": 6}, "main_00-11": {"code": "0-11", "cost": 6}, "main_01-01": {"code": "1-1", "cost": 6}, "main_01-02": {"code": "1-2", "cost": 0}, "main_01-03": {"code": "1-3", "cost": 6}, "main_01-04": {"code": "1-4", "cost": 6}, "main_01-05": {"code": "1-5", "cost": 6}, "main_01-06": {"code": "1-6", "cost": 6}, "main_01-07": {"code": "1-7", "cost": 6}, "main_01-08": {"code": "1-8", "cost": 9}, "main_01-09": {"code": "1-9", "cost": 9}, "main_01-10": {"code": "1-10", "cost": 9}, "main_01-11": {"code": "1-11", "cost": 0}, "main_01-12": {"code": "1-12", "cost": 9}, "main_02-01": {"code": "2-1", "cost": 9}, "main_02-02": {"code": "2-2", "cost": 9}, "main_02-03": {"code": "2-3", "cost": 12}, "main_02-04": {"code": "2-4", "cost": 12}, "main_02-05": {"code": "2-5", "cost": 12}, "main_02-06": {"code": "2-6", "cost": 12}, "main_02-07": {"code": "2-7", "cost": 12}, "main_02-08": {"code": "2-8", "cost": 12}, "main_02-09": {"code": "2-9", "cost": 12}, "main_02-10": {"code": "2-10", "cost": 15}, "sub_02-01": {"code": "S2-1", "cost": 9}, "sub_02-02": {"code": "S2-2", "cost": 9}, "sub_02-03": {"code": "S2-3", "cost": 9}, "sub_02-04": {"code": "S2-4", "cost": 9}, "sub_02-05": {"code": "S2-5", "cost": 12}, "sub_02-06": {"code": "S2-6", "cost": 12}, "sub_02-07": {"code": "S2-7", "cost": 12}, "sub_02-08": {"code": "S2-8", "cost": 12}, "sub_02-09": {"code": "S2-9", "cost": 12}, "sub_02-10": {"code": "S2-10", "cost": 12}, "sub_02-11": {"code": "S2-11", "cost": 12}, "sub_02-12": {"code": "S2-12", "cost": 15}, "main_03-01": {"code": "3-1", "cost": 15}, "main_03-02": {"code": "3-2", "cost": 15}, "main_03-03": {"code": "3-3", "cost": 15}, "main_03-04": {"code": "3-4", "cost": 15}, "main_03-05": {"code": "3-5", "cost": 15}, "main_03-06": {"code": "3-6", "cost": 15}, "main_03-07": {"code": "3-7", "cost": 15}, "main_03-08": {"code": "3-8", "cost": 18}, "sub_03-1-1": {"code": "S3-1", "cost": 15}, "sub_03-1-2": {"code": "S3-2", "cost": 15}, "sub_03-2-1": {"code": "S3-3", "cost": 15}, "sub_03-2-2": {"code": "S3-4", "cost": 15}, "sub_03-2-3": {"code": "S3-5", "cost": 15}, "main_04-01": {"code": "4-1", "cost": 18}, "main_04-02": {"code": "4-2", "cost": 18}, "main_04-03": {"code": "4-3", "cost": 18}, "main_04-04": {"code": "4-4", "cost": 18}, "main_04-05": {"code": "4-5", "cost": 18}, "main_04-06": {"code": "4-6", "cost": 18}, "main_04-07": {"code": "4-7", "cost": 18}, "main_04-08": {"code": "4-8", "cost": 21}, "main_04-09": {"code": "4-9", "cost": 21}, "main_04-10": {"code": "4-10", "cost": 21}, "sub_04-1-1": {"code": "S4-1", "cost": 18}, "sub_04-1-2": {"code": "S4-2", "cost": 18}, "sub_04-1-3": {"code": "S4-3", "cost": 18}, "sub_04-2-1": {"code": "S4-4", "cost": 18}, "sub_04-2-2": {"code": "S4-5", "cost": 18}, "sub_04-2-3": {"code": "S4-6", "cost": 21}, "sub_04-3-1": {"code": "S4-7", "cost": 18}, "sub_04-3-2": {"code": "S4-8", "cost": 18}, "sub_04-3-3": {"code": "S4-9", "cost": 21}, "a001_01": {"code": "GT-1", "cost": 9}, "a001_02": {"code": "GT-2", "cost": 9}, "a001_03": {"code": "GT-3", "cost": 12}, "a001_04": {"code": "GT-4", "cost": 12}, "a001_05": {"code": "GT-5", "cost": 15}, "a001_06": {"code": "GT-6", "cost": 15}, "wk_armor_1": {"code": "SK-1", "cost": 10}, "wk_armor_2": {"code": "SK-2", "cost": 15}, "wk_armor_3": {"code": "SK-3", "cost": 20}, "wk_armor_4": {"code": "SK-4", "cost": 25}, "wk_armor_5": {"code": "SK-5", "cost": 30}, "wk_fly_1": {"code": "CA-1", "cost": 10}, "wk_fly_2": {"code": "CA-2", "cost": 15}, "wk_fly_3": {"code": "CA-3", "cost": 20}, "wk_fly_4": {"code": "CA-4", "cost": 25}, "wk_fly_5": {"code": "CA-5", "cost": 30}, "main_05-01": {"code": "5-1", "cost": 18}, "main_05-02": {"code": "5-2", "cost": 18}, "main_05-03": {"code": "5-3", "cost": 18}, "main_05-04": {"code": "5-4", "cost": 18}, "main_05-05": {"code": "5-5", "cost": 18}, "main_05-06": {"code": "5-6", "cost": 18}, "main_05-07": {"code": "5-7", "cost": 21}, "main_05-08": {"code": "5-8", "cost": 18}, "main_05-09": {"code": "5-9", "cost": 18}, "main_05-10": {"code": "5-10", "cost": 21}, "sub_05-1-1": {"code": "S5-1", "cost": 18}, "sub_05-1-2": {"code": "S5-2", "cost": 18}, "sub_05-2-1": {"code": "S5-3", "cost": 18}, "sub_05-2-2": {"code": "S5-4", "cost": 18}, "sub_05-3-1": {"code": "S5-5", "cost": 18}, "sub_05-3-2": {"code": "S5-6", "cost": 18}, "a003_01": {"code": "OF-1", "cost": 8}, "a003_02": {"code": "OF-2", "cost": 12}, "a003_03": {"code": "OF-3", "cost": 16}, "a003_04": {"code": "OF-4", "cost": 16}, "a003_05": {"code": "OF-5", "cost": 16}, "a003_06": {"code": "OF-6", "cost": 20}, "a003_07": {"code": "OF-7", "cost": 20}, "a003_08": {"code": "OF-8", "cost": 20}, "a003_f01": {"code": "OF-F1", "cost": 12}, "a003_f02": {"code": "OF-F2", "cost": 20}, "a003_f03": {"code": "OF-F3", "cost": 30}, "a003_f04": {"code": "OF-F4", "cost": 40}, "gachabox6": {"code": "\u5956\u52b1\u626d\u86cb\u673a", "cost": 20}, "act4d0_01": {"code": "SW-EV-1", "cost": 6}, "act4d0_02": {"code": "SW-EV-2", "cost": 9}, "act4d0_03": {"code": "SW-EV-3", "cost": 12}, "act4d0_04": {"code": "SW-EV-4", "cost": 15}, "act4d0_05": {"code": "SW-EV-5", "cost": 18}, "act5d0_01": {"code": "CB-1", "cost": 10}, "act5d0_02": {"code": "CB-2", "cost": 10}, "act5d0_03": {"code": "CB-3", "cost": 10}, "act5d0_04": {"code": "CB-4", "cost": 10}, "act5d0_05": {"code": "CB-5", "cost": 15}, "act5d0_06": {"code": "CB-6", "cost": 15}, "act5d0_07": {"code": "CB-7", "cost": 15}, "act5d0_08": {"code": "CB-8", "cost": 15}, "act5d0_09": {"code": "CB-9", "cost": 20}, "act5d0_10": {"code": "CB-10", "cost": 20}, "main_06-01": {"code": "6-1", "cost": 18}, "main_06-02": {"code": "6-2", "cost": 18}, "main_06-03": {"code": "6-3", "cost": 18}, "main_06-04": {"code": "6-4", "cost": 18}, "main_06-05": {"code": "6-5", "cost": 18}, "main_06-06": {"code": "6-7", "cost": 0}, "main_06-07": {"code": "6-8", "cost": 18}, "main_06-08": {"code": "6-9", "cost": 18}, "main_06-09": {"code": "6-10", "cost": 18}, "main_06-10": {"code": "6-11", "cost": 21}, "main_06-11": {"code": "6-12", "cost": 18}, "main_06-12": {"code": "6-14", "cost": 18}, "main_06-13": {"code": "6-15", "cost": 18}, "main_06-14": {"code": "6-16", "cost": 21}, "main_06-15": {"code": "6-17", "cost": 0}, "sub_03-3-1": {"code": "S3-6", "cost": 15}, "sub_04-4-1": {"code": "S4-10", "cost": 18}, "sub_05-4-1": {"code": "S5-7", "cost": 18}, "sub_05-4-2": {"code": "S5-8", "cost": 18}, "sub_06-1-1": {"code": "S6-1", "cost": 18}, "sub_06-1-2": {"code": "S6-2", "cost": 18}, "sub_06-2-1": {"code": "S6-3", "cost": 18}, "sub_06-2-2": {"code": "S6-4", "cost": 18}, "randomMaterial_1": {"code": "\u7f57\u5fb7\u5c9b\u7269\u8d44\u8865\u7ed9", "cost": 99}, "act6d5_01": {"code": "AF-1", "cost": 6}, "act6d5_02": {"code": "AF-2", "cost": 9}, "act6d5_03": {"code": "AF-3", "cost": 12}, "act6d5_04": {"code": "AF-4", "cost": 12}, "act6d5_05": {"code": "AF-5", "cost": 15}, "act6d5_06": {"code": "AF-6", "cost": 15}, "act6d5_07": {"code": "AF-7", "cost": 15}, "act6d5_08": {"code": "AF-8", "cost": 18}, "randomMaterial_2": {"code": "\u5c81\u8fc7\u534e\u706f", "cost": 99}, "wk_melee_1": {"code": "CE-1", "cost": 10}, "wk_melee_2": {"code": "CE-2", "cost": 15}, "wk_melee_3": {"code": "CE-3", "cost": 20}, "wk_melee_4": {"code": "CE-4", "cost": 25}, "wk_melee_5": {"code": "CE-5", "cost": 30}, "wk_toxic_1": {"code": "AP-1", "cost": 10}, "wk_toxic_2": {"code": "AP-2", "cost": 15}, "wk_toxic_3": {"code": "AP-3", "cost": 20}, "wk_toxic_4": {"code": "AP-4", "cost": 25}, "wk_toxic_5": {"code": "AP-5", "cost": 30}, "act7d5_01": {"code": "SA-1", "cost": 6}, "act7d5_02": {"code": "SA-2", "cost": 9}, "act7d5_03": {"code": "SA-3", "cost": 12}, "act7d5_04": {"code": "SA-4", "cost": 15}, "act7d5_05": {"code": "SA-5", "cost": 18}, "act7d5_06": {"code": "SA-6", "cost": 18}, "randomMaterialRune_0": {"code": "\u8352\u829c\u884c\u52a8\u7269\u8d44\u8865\u7ed9", "cost": 99}, "act9d0_01": {"code": "DM-1", "cost": 9}, "act9d0_02": {"code": "DM-2", "cost": 9}, "act9d0_03": {"code": "DM-3", "cost": 12}, "act9d0_04": {"code": "DM-4", "cost": 12}, "act9d0_05": {"code": "DM-5", "cost": 15}, "act9d0_06": {"code": "DM-6", "cost": 15}, "act9d0_07": {"code": "DM-7", "cost": 18}, "act9d0_08": {"code": "DM-8", "cost": 18}, "main_07-01": {"code": "7-2", "cost": 18}, "main_07-02": {"code": "7-3", "cost": 18}, "main_07-03": {"code": "7-4", "cost": 18}, "main_07-04": {"code": "7-5", "cost": 18}, "main_07-05": {"code": "7-6", "cost": 18}, "main_07-06": {"code": "7-8", "cost": 18}, "main_07-07": {"code": "7-9", "cost": 21}, "main_07-08": {"code": "7-10", "cost": 18}, "main_07-09": {"code": "7-11", "cost": 18}, "main_07-10": {"code": "7-12", "cost": 18}, "main_07-11": {"code": "7-13", "cost": 18}, "main_07-12": {"code": "7-14", "cost": 18}, "main_07-13": {"code": "7-15", "cost": 18}, "main_07-14": {"code": "7-16", "cost": 18}, "main_07-15": {"code": "7-17", "cost": 21}, "main_07-16": {"code": "7-18", "cost": 21}, "sub_07-1-1": {"code": "S7-1", "cost": 18}, "sub_07-1-2": {"code": "S7-2", "cost": 18}, "randomMaterial_3": {"code": "32h\u6218\u7565\u914d\u7ed9", "cost": 99}, "pro_a_1": {"code": "PR-A-1", "cost": 18}, "pro_a_2": {"code": "PR-A-2", "cost": 36}, "pro_b_1": {"code": "PR-B-1", "cost": 18}, "pro_b_2": {"code": "PR-B-2", "cost": 36}, "pro_c_1": {"code": "PR-C-1", "cost": 18}, "pro_c_2": {"code": "PR-C-2", "cost": 36}, "pro_d_1": {"code": "PR-D-1", "cost": 18}, "pro_d_2": {"code": "PR-D-2", "cost": 36}, "wk_kc_1": {"code": "LS-1", "cost": 10}, "wk_kc_2": {"code": "LS-2", "cost": 15}, "wk_kc_3": {"code": "LS-3", "cost": 20}, "wk_kc_4": {"code": "LS-4", "cost": 25}, "wk_kc_5": {"code": "LS-5", "cost": 30}, "randomMaterialRune_1": {"code": "\u9ec4\u94c1\u884c\u52a8\u7269\u8d44\u8865\u7ed9", "cost": 99}, "act10d5_01": {"code": "SV-1", "cost": 6}, "act10d5_02": {"code": "SV-2", "cost": 9}, "act10d5_03": {"code": "SV-3", "cost": 9}, "act10d5_04": {"code": "SV-4", "cost": 12}, "act10d5_05": {"code": "SV-5", "cost": 15}, "act10d5_06": {"code": "SV-6", "cost": 15}, "act10d5_07": {"code": "SV-7", "cost": 18}, "act11d0_01": {"code": "TW-1", "cost": 9}, "act11d0_02": {"code": "TW-2", "cost": 9}, "act11d0_03": {"code": "TW-3", "cost": 12}, "act11d0_04": {"code": "TW-4", "cost": 12}, "act11d0_05": {"code": "TW-5", "cost": 15}, "act11d0_06": {"code": "TW-6", "cost": 15}, "act11d0_07": {"code": "TW-7", "cost": 18}, "act11d0_08": {"code": "TW-8", "cost": 18}, "randomMaterialRune_2": {"code": "\u5229\u5203\u884c\u52a8\u7269\u8d44\u8865\u7ed9", "cost": 99}, "act12d0_01": {"code": "RI-1", "cost": 9}, "act12d0_02": {"code": "RI-2", "cost": 9}, "act12d0_03": {"code": "RI-3", "cost": 12}, "act12d0_04": {"code": "RI-4", "cost": 12}, "act12d0_05": {"code": "RI-5", "cost": 15}, "act12d0_06": {"code": "RI-6", "cost": 15}, "act12d0_07": {"code": "RI-7", "cost": 18}, "act12d0_08": {"code": "RI-8", "cost": 18}, "act13d0_01": {"code": "FA-1", "cost": 6}, "act13d0_02": {"code": "FA-2", "cost": 6}, "act13d0_03": {"code": "FA-3", "cost": 9}, "act13d0_04": {"code": "FA-4", "cost": 9}, "act13d0_05": {"code": "FA-5", "cost": 12}, "act13d0_06": {"code": "FA-6", "cost": 12}, "act13d0_07": {"code": "FA-7", "cost": 15}, "act13d0_08": {"code": "FA-8", "cost": 18}, "a001_01_rep": {"code": "GT-1", "cost": 9}, "a001_02_rep": {"code": "GT-2", "cost": 9}, "a001_03_rep": {"code": "GT-3", "cost": 12}, "a001_04_rep": {"code": "GT-4", "cost": 12}, "a001_05_rep": {"code": "GT-5", "cost": 15}, "a001_06_rep": {"code": "GT-6", "cost": 15}, "act13d5_01": {"code": "MN-1", "cost": 9}, "act13d5_02": {"code": "MN-2", "cost": 9}, "act13d5_03": {"code": "MN-3", "cost": 12}, "act13d5_04": {"code": "MN-4", "cost": 12}, "act13d5_05": {"code": "MN-5", "cost": 15}, "act13d5_06": {"code": "MN-6", "cost": 15}, "act13d5_07": {"code": "MN-7", "cost": 18}, "act13d5_08": {"code": "MN-8", "cost": 18}, "sub_05-4-3": {"code": "S5-9", "cost": 18}, "sub_03-3-2": {"code": "S3-7", "cost": 18}, "main_08-01": {"code": "R8-1", "cost": 18}, "main_08-02": {"code": "R8-2", "cost": 18}, "main_08-03": {"code": "R8-3", "cost": 18}, "main_08-04": {"code": "R8-4", "cost": 18}, "main_08-05": {"code": "R8-5", "cost": 18}, "main_08-06": {"code": "R8-6", "cost": 18}, "main_08-07": {"code": "R8-7", "cost": 18}, "main_08-08": {"code": "R8-8", "cost": 18}, "main_08-09": {"code": "M8-6", "cost": 18}, "main_08-10": {"code": "R8-9", "cost": 18}, "main_08-11": {"code": "R8-10", "cost": 18}, "main_08-12": {"code": "M8-7", "cost": 21}, "main_08-13": {"code": "R8-11", "cost": 21}, "main_08-14": {"code": "M8-8", "cost": 18}, "main_08-15": {"code": "JT8-1", "cost": 0}, "main_08-16": {"code": "JT8-2", "cost": 21}, "main_08-17": {"code": "JT8-3", "cost": 18}, "randomMaterial_4": {"code": "\u611f\u8c22\u5e86\u5178\u7269\u8d44\u8865\u7ed9", "cost": 99}, "randomMaterialRune_3": {"code": "\u71c3\u7070\u884c\u52a8\u7269\u8d44\u8865\u7ed9", "cost": 99}, "act5d0_01_rep": {"code": "CB-1", "cost": 10}, "act5d0_02_rep": {"code": "CB-2", "cost": 10}, "act5d0_03_rep": {"code": "CB-3", "cost": 10}, "act5d0_04_rep": {"code": "CB-4", "cost": 10}, "act5d0_05_rep": {"code": "CB-5", "cost": 15}, "act5d0_06_rep": {"code": "CB-6", "cost": 15}, "act5d0_07_rep": {"code": "CB-7", "cost": 15}, "act5d0_08_rep": {"code": "CB-8", "cost": 15}, "act5d0_09_rep": {"code": "CB-9", "cost": 20}, "act5d0_10_rep": {"code": "CB-10", "cost": 20}, "act15d0_01": {"code": "MB-1", "cost": 9}, "act15d0_02": {"code": "MB-2", "cost": 9}, "act15d0_03": {"code": "MB-3", "cost": 12}, "act15d0_04": {"code": "MB-4", "cost": 12}, "act15d0_05": {"code": "MB-5", "cost": 15}, "act15d0_06": {"code": "MB-6", "cost": 15}, "act15d0_07": {"code": "MB-7", "cost": 18}, "act15d0_08": {"code": "MB-8", "cost": 18}, "act15d5_01": {"code": "BH-1", "cost": 6}, "act15d5_02": {"code": "BH-2", "cost": 6}, "act15d5_03": {"code": "BH-3", "cost": 9}, "act15d5_04": {"code": "BH-4", "cost": 9}, "act15d5_05": {"code": "BH-5", "cost": 12}, "act15d5_06": {"code": "BH-6", "cost": 12}, "act15d5_07": {"code": "BH-7", "cost": 15}, "act15d5_08": {"code": "BH-8", "cost": 18}, "randomMaterialRune_4": {"code": "\u94c5\u5c01\u884c\u52a8\u7269\u8d44\u8865\u7ed9", "cost": 99}, "act16d5_01": {"code": "WR-1", "cost": 9}, "act16d5_02": {"code": "WR-2", "cost": 9}, "act16d5_03": {"code": "WR-3", "cost": 12}, "act16d5_04": {"code": "WR-4", "cost": 12}, "act16d5_05": {"code": "WR-5", "cost": 12}, "act16d5_06": {"code": "WR-6", "cost": 12}, "act16d5_07": {"code": "WR-7", "cost": 12}, "act16d5_08": {"code": "WR-8", "cost": 15}, "act16d5_09": {"code": "WR-9", "cost": 18}, "act16d5_10": {"code": "WR-10", "cost": 18}} -------------------------------------------------------------------------------- /MaterialPlanningRaw.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Dec 2 11:43:50 2019 4 | 5 | @author: sqr_p 6 | """ 7 | 8 | import numpy as np 9 | import urllib.request, json, time, os, copy, sys 10 | from scipy.optimize import linprog 11 | 12 | global penguin_url 13 | penguin_url = 'https://penguin-stats.io/PenguinStats/api/' 14 | 15 | class MaterialPlanning(object): 16 | 17 | def __init__(self, 18 | filter_freq=20, 19 | filter_stages=[], 20 | url_stats='result/matrix?show_stage_details=true&show_item_details=true', 21 | url_rules='formula', 22 | path_stats='data/matrix.json', 23 | path_rules='data/formula.json'): 24 | """ 25 | Object initialization. 26 | Args: 27 | filter_freq: int or None. The lowest frequence that we consider. 28 | No filter will be applied if None. 29 | url_stats: string. url to the dropping rate stats data. 30 | url_rules: string. url to the composing rules data. 31 | path_stats: string. local path to the dropping rate stats data. 32 | path_rules: string. local path to the composing rules data. 33 | """ 34 | try: 35 | material_probs, convertion_rules = load_data(path_stats, path_rules) 36 | except: 37 | print('Requesting data from web resources (i.e., penguin-stats.io)...', end=' ') 38 | material_probs, convertion_rules = request_data(penguin_url+url_stats, penguin_url+url_rules, path_stats, path_rules) 39 | print('done.') 40 | 41 | if filter_freq: 42 | filtered_probs = [] 43 | for dct in material_probs['matrix']: 44 | if dct['times']>=filter_freq and dct['stage']['code'] not in filter_stages: 45 | filtered_probs.append(dct) 46 | material_probs['matrix'] = filtered_probs 47 | 48 | self._set_lp_parameters(*self._pre_processing(material_probs, convertion_rules)) 49 | 50 | 51 | def _pre_processing(self, material_probs, convertion_rules): 52 | """ 53 | Compute costs, convertion rules and items probabilities from requested dictionaries. 54 | Args: 55 | material_probs: List of dictionaries recording the dropping info per stage per item. 56 | Keys of instances: ["itemID", "times", "itemName", "quantity", "apCost", "stageCode", "stageID"]. 57 | convertion_rules: List of dictionaries recording the rules of composing. 58 | Keys of instances: ["id", "name", "level", "source", "madeof"]. 59 | """ 60 | # To count items and stages. 61 | additional_items = {'30135': u'D32钢', '30125': u'双极纳米片', '30115': u'聚合剂'} 62 | exp_unit = 200*30.0/7400 63 | gold_unit = 0.004 64 | exp_worths = {'2001':exp_unit, '2002':exp_unit*2, '2003':exp_unit*5, '2004':exp_unit*10} 65 | gold_worths = {'3003':gold_unit*500} 66 | 67 | item_dct = {} 68 | stage_dct = {} 69 | for dct in material_probs['matrix']: 70 | item_dct[dct['item']['itemId']]=dct['item']['name'] 71 | stage_dct[dct['stage']['code']]=dct['stage']['code'] 72 | item_dct.update(additional_items) 73 | 74 | # To construct mapping from id to item names. 75 | item_array = [] 76 | item_id_array = [] 77 | for k,v in item_dct.items(): 78 | try: 79 | float(k) 80 | item_array.append(v) 81 | item_id_array.append(k) 82 | except: 83 | pass 84 | self.item_array = np.array(item_array) 85 | self.item_id_array = np.array(item_id_array) 86 | self.item_dct_rv = {v:k for k,v in enumerate(item_array)} 87 | 88 | # To construct mapping from stage id to stage names and vice versa. 89 | stage_array = [] 90 | for k,v in stage_dct.items(): 91 | stage_array.append(v) 92 | self.stage_array = np.array(stage_array) 93 | self.stage_dct_rv = {v:k for k,v in enumerate(self.stage_array)} 94 | 95 | # To format dropping records into sparse probability matrix 96 | probs_matrix = np.zeros([len(stage_array), len(item_array)]) 97 | cost_lst = np.zeros(len(stage_array)) 98 | cost_exp_offset = np.zeros(len(stage_array)) 99 | cost_gold_offset = np.zeros(len(stage_array)) 100 | for dct in material_probs['matrix']: 101 | try: 102 | float(dct['item']['itemId']) 103 | probs_matrix[self.stage_dct_rv[dct['stage']['code']], self.item_dct_rv[dct['item']['name']]] = dct['quantity']/float(dct['times']) 104 | if cost_lst[self.stage_dct_rv[dct['stage']['code']]] == 0: 105 | cost_gold_offset[self.stage_dct_rv[dct['stage']['code']]] = - dct['stage']['apCost']*(12*gold_unit) 106 | cost_lst[self.stage_dct_rv[dct['stage']['code']]] = dct['stage']['apCost'] 107 | except: 108 | pass 109 | 110 | try: 111 | cost_exp_offset[self.stage_dct_rv[dct['stage']['code']]] -= exp_worths[dct['item']['itemId']]*dct['quantity']/float(dct['times']) 112 | except: 113 | pass 114 | 115 | try: 116 | cost_gold_offset[self.stage_dct_rv[dct['stage']['code']]] -= gold_worths[dct['item']['itemId']]*dct['quantity']/float(dct['times']) 117 | except: 118 | pass 119 | 120 | # Hardcoding: extra gold farmed. 121 | cost_gold_offset[self.stage_dct_rv['S4-6']] -= 3228 * gold_unit 122 | cost_gold_offset[self.stage_dct_rv['S5-2']] -= 2484 * gold_unit 123 | 124 | # To build equavalence relationship from convert_rule_dct. 125 | self.convertions_dct = {} 126 | convertion_matrix = [] 127 | convertion_outc_matrix = [] 128 | convertion_cost_lst = [] 129 | for rule in convertion_rules: 130 | convertion = np.zeros(len(self.item_array)) 131 | convertion[self.item_dct_rv[rule['name']]] = 1 132 | 133 | comp_dct = {comp['name']:comp['count'] for comp in rule['costs']} 134 | self.convertions_dct[rule['name']] = comp_dct 135 | for iname in comp_dct: 136 | convertion[self.item_dct_rv[iname]] -= comp_dct[iname] 137 | convertion_matrix.append(copy.deepcopy(convertion)) 138 | 139 | outc_dct = {outc['name']:outc['count'] for outc in rule['extraOutcome']} 140 | outc_wgh = {outc['name']:outc['weight'] for outc in rule['extraOutcome']} 141 | weight_sum = float(sum(outc_wgh.values())) 142 | for iname in outc_dct: 143 | convertion[self.item_dct_rv[iname]] += outc_dct[iname]*0.175*outc_wgh[iname]/weight_sum 144 | convertion_outc_matrix.append(convertion) 145 | 146 | convertion_cost_lst.append(rule['goldCost']*0.004) 147 | 148 | convertions_group = (np.array(convertion_matrix), np.array(convertion_outc_matrix), np.array(convertion_cost_lst)) 149 | farms_group = (probs_matrix, cost_lst, cost_exp_offset, cost_gold_offset) 150 | 151 | return convertions_group, farms_group 152 | 153 | 154 | def _set_lp_parameters(self, convertions_group, farms_group): 155 | """ 156 | Object initialization. 157 | Args: 158 | convertion_matrix: matrix of shape [n_rules, n_items]. 159 | Each row represent a rule. 160 | convertion_cost_lst: list. Cost in equal value to the currency spent in convertion. 161 | probs_matrix: sparse matrix of shape [n_stages, n_items]. 162 | Items per clear (probabilities) at each stage. 163 | cost_lst: list. Costs per clear at each stage. 164 | """ 165 | self.convertion_matrix, self.convertion_outc_matrix, self.convertion_cost_lst = convertions_group 166 | self.probs_matrix, self.cost_lst, self.cost_exp_offset, self.cost_gold_offset = farms_group 167 | 168 | assert len(self.probs_matrix)==len(self.cost_lst) 169 | assert len(self.convertion_matrix)==len(self.convertion_cost_lst) 170 | assert self.probs_matrix.shape[1]==self.convertion_matrix.shape[1] 171 | 172 | 173 | def update(self, 174 | filter_freq=20, 175 | filter_stages=[], 176 | url_stats='result/matrix?show_stage_details=true&show_item_details=true', 177 | url_rules='formula', 178 | path_stats='data/matrix.json', 179 | path_rules='data/formula.json'): 180 | """ 181 | To update parameters when probabilities change or new items added. 182 | Args: 183 | url_stats: string. url to the dropping rate stats data. 184 | url_rules: string. url to the composing rules data. 185 | path_stats: string. local path to the dropping rate stats data. 186 | path_rules: string. local path to the composing rules data. 187 | """ 188 | print('Requesting data from web resources (i.e., penguin-stats.io)...', end=' ') 189 | material_probs, convertion_rules = request_data(penguin_url+url_stats, penguin_url+url_rules, path_stats, path_rules) 190 | print('done.') 191 | 192 | if filter_freq: 193 | filtered_probs = [] 194 | for dct in material_probs['matrix']: 195 | if dct['times']>=filter_freq and dct['stage']['code'] not in filter_stages: 196 | filtered_probs.append(dct) 197 | material_probs['matrix'] = filtered_probs 198 | 199 | self._set_lp_parameters(*self._pre_processing(material_probs, convertion_rules)) 200 | 201 | 202 | def _get_plan_no_prioties(self, demand_lst, outcome=False, gold_demand=True, exp_demand=True): 203 | """ 204 | To solve linear programming problem without prioties. 205 | Args: 206 | demand_lst: list of materials demand. Should include all items (zero if not required). 207 | Returns: 208 | strategy: list of required clear times for each stage. 209 | fun: estimated total cost. 210 | """ 211 | A_ub = (np.vstack([self.probs_matrix, self.convertion_outc_matrix]) 212 | if outcome else np.vstack([self.probs_matrix, self.convertion_matrix])).T 213 | farm_cost = (self.cost_lst + 214 | (self.cost_exp_offset if exp_demand else 0) + 215 | (self.cost_gold_offset if gold_demand else 0)) 216 | cost = (np.hstack([farm_cost, self.convertion_cost_lst])) 217 | assert np.any(farm_cost>=0) 218 | 219 | excp_factor = 1.0 220 | dual_factor = 1.0 221 | 222 | while excp_factor>1e-5: 223 | solution = linprog(c=cost, 224 | A_ub=-A_ub, 225 | b_ub=-np.array(demand_lst)*excp_factor, 226 | method='interior-point') 227 | if solution.status != 4: 228 | break 229 | 230 | excp_factor /= 10.0 231 | 232 | while dual_factor>1e-5: 233 | dual_solution = linprog(c=-np.array(demand_lst)*excp_factor*dual_factor, 234 | A_ub=A_ub.T, 235 | b_ub=cost, 236 | method='interior-point') 237 | if solution.status != 4: 238 | break 239 | 240 | dual_factor /= 10.0 241 | 242 | 243 | return solution, dual_solution, excp_factor 244 | 245 | 246 | def get_plan(self, requirement_dct, deposited_dct={}, 247 | print_output=True, outcome=False, gold_demand=True, exp_demand=True): 248 | """ 249 | User API. Computing the material plan given requirements and owned items. 250 | Args: 251 | requirement_dct: dictionary. Contain only required items with their numbers. 252 | deposit_dct: dictionary. Contain only owned items with their numbers. 253 | """ 254 | status_dct = {0: 'Optimization terminated successfully. ', 255 | 1: 'Iteration limit reached. ', 256 | 2: 'Problem appears to be infeasible. ', 257 | 3: 'Problem appears to be unbounded. ', 258 | 4: 'Numerical difficulties encountered.'} 259 | 260 | demand_lst = np.zeros(len(self.item_array)) 261 | for k, v in requirement_dct.items(): 262 | if k in self.item_dct_rv: 263 | demand_lst[self.item_dct_rv[k]] = v 264 | for k, v in deposited_dct.items(): 265 | if k in self.item_dct_rv: 266 | demand_lst[self.item_dct_rv[k]] -= v 267 | 268 | stt = time.time() 269 | solution, dual_solution, excp_factor = self._get_plan_no_prioties(demand_lst, outcome, gold_demand, exp_demand) 270 | x, status = solution.x/excp_factor, solution.status 271 | y, slack = dual_solution.x, dual_solution.slack 272 | n_looting, n_convertion = x[:len(self.cost_lst)], x[len(self.cost_lst):] 273 | 274 | cost = np.dot(x[:len(self.cost_lst)], self.cost_lst) 275 | gcost = np.dot(x[len(self.cost_lst):], self.convertion_cost_lst) / 0.004 276 | gold = - np.dot(n_looting, self.cost_gold_offset) / 0.004 277 | exp = - np.dot(n_looting, self.cost_exp_offset) * 7400 / 30.0 278 | 279 | print(n_looting[self.stage_dct_rv['S4-6']]) 280 | print(self.cost_exp_offset[self.stage_dct_rv['S4-6']]) 281 | 282 | if print_output: 283 | print(status_dct[status]+(' Computed in %.4f seconds,' %(time.time()-stt))) 284 | 285 | if status != 0: 286 | raise ValueError(status_dct[status]) 287 | 288 | stages = [] 289 | for i,t in enumerate(n_looting): 290 | if t >= 0.1: 291 | target_items = np.where(self.probs_matrix[i]>=0.02)[0] 292 | items = {self.item_array[idx]: float2str(self.probs_matrix[i, idx]*t) 293 | for idx in target_items if len(self.item_id_array[idx])==5} 294 | stage = { 295 | "stage": self.stage_array[i], 296 | "count": float2str(t), 297 | "items": items 298 | } 299 | stages.append(stage) 300 | 301 | syntheses = [] 302 | for i,t in enumerate(n_convertion): 303 | if t >= 0.1: 304 | target_item = self.item_array[np.argmax(self.convertion_matrix[i])] 305 | materials = { k: str(v*int(t+0.9)) for k,v in self.convertions_dct[target_item].items() } 306 | synthesis = { 307 | "target": target_item, 308 | "count": str(int(t+0.9)), 309 | "materials": materials 310 | } 311 | syntheses.append(synthesis) 312 | elif t >= 0.05: 313 | target_item = self.item_array[np.argmax(self.convertion_matrix[i])] 314 | materials = { k: '%.1f'%(v*t) for k,v in self.convertions_dct[target_item].items() } 315 | synthesis = { 316 | "target": target_item, 317 | "count": '%.1f'%t, 318 | "materials": materials 319 | } 320 | syntheses.append(synthesis) 321 | 322 | values = [{"level":'1', "items":[]}, 323 | {"level":'2', "items":[]}, 324 | {"level":'3', "items":[]}, 325 | {"level":'4', "items":[]}, 326 | {"level":'5', "items":[]}] 327 | for i,item in enumerate(self.item_array): 328 | if len(self.item_id_array[i])==5 and y[i]>0.1: 329 | item_value = { 330 | "name": item, 331 | "value": '%.2f'%y[i] 332 | } 333 | values[int(self.item_id_array[i][-1])-1]['items'].append(item_value) 334 | for group in values: 335 | group["items"] = sorted(group["items"], key=lambda k: float(k['value']), reverse=True) 336 | 337 | res = { 338 | "cost": int(cost), 339 | "gcost": int(gcost), 340 | "gold": int(gold), 341 | "exp": int(exp), 342 | "stages": stages, 343 | "syntheses": syntheses, 344 | "values": list(reversed(values)) 345 | } 346 | 347 | if print_output: 348 | print('Estimated total cost: %d, gold: %d, exp: %d.'%(res['cost'],res['gold'],res['exp'])) 349 | print('Loot at following stages:') 350 | for stage in stages: 351 | display_lst = [k + '(%s) '%stage['items'][k] for k in stage['items']] 352 | print('Stage ' + stage['stage'] + '(%s times) ===> '%stage['count'] 353 | + ', '.join(display_lst)) 354 | 355 | print('\nSynthesize following items:') 356 | for synthesis in syntheses: 357 | display_lst = [k + '(%s) '%synthesis['materials'][k] for k in synthesis['materials']] 358 | print(synthesis['target'] + '(%s) <=== '%synthesis['count'] 359 | + ', '.join(display_lst)) 360 | 361 | print('\nItems Values:') 362 | for i, group in reversed(list(enumerate(values))): 363 | display_lst = ['%s:%s'%(item['name'], item['value']) for item in group['items']] 364 | print('Level %d items: '%(i+1)) 365 | print(', '.join(display_lst)) 366 | 367 | return res 368 | 369 | 370 | def Cartesian_sum(arr1, arr2): 371 | arr_r = [] 372 | for arr in arr1: 373 | arr_r.append(arr+arr2) 374 | arr_r = np.vstack(arr_r) 375 | return arr_r 376 | 377 | def float2str(x, offset=0.5): 378 | 379 | if x < 1.0: 380 | out = '%.1f'%x 381 | else: 382 | out = '%d'%(int(x+offset)) 383 | return out 384 | 385 | def request_data(url_stats, url_rules, save_path_stats, save_path_rules): 386 | """ 387 | To request probability and convertion rules from web resources and store at local. 388 | Args: 389 | url_stats: string. url to the dropping rate stats data. 390 | url_rules: string. url to the composing rules data. 391 | save_path_stats: string. local path for storing the stats data. 392 | save_path_rules: string. local path for storing the composing rules data. 393 | Returns: 394 | material_probs: dictionary. Content of the stats json file. 395 | convertion_rules: dictionary. Content of the rules json file. 396 | """ 397 | try: 398 | os.mkdir(os.path.dirname(save_path_stats)) 399 | except: 400 | pass 401 | try: 402 | os.mkdir(os.path.dirname(save_path_rules)) 403 | except: 404 | pass 405 | 406 | with urllib.request.urlopen(url_stats) as url: 407 | material_probs = json.loads(url.read().decode()) 408 | with open(save_path_stats, 'w') as outfile: 409 | json.dump(material_probs, outfile) 410 | 411 | with urllib.request.urlopen(url_rules) as url: 412 | convertion_rules = json.loads(url.read().decode()) 413 | with open(save_path_rules, 'w') as outfile: 414 | json.dump(convertion_rules, outfile) 415 | 416 | return material_probs, convertion_rules 417 | 418 | def load_data(path_stats, path_rules): 419 | """ 420 | To load stats and rules data from local directories. 421 | Args: 422 | path_stats: string. local path to the stats data. 423 | path_rules: string. local path to the composing rules data. 424 | Returns: 425 | material_probs: dictionary. Content of the stats json file. 426 | convertion_rules: dictionary. Content of the rules json file. 427 | """ 428 | with open(path_stats) as json_file: 429 | material_probs = json.load(json_file) 430 | with open(path_rules) as json_file: 431 | convertion_rules = json.load(json_file) 432 | 433 | return material_probs, convertion_rules -------------------------------------------------------------------------------- /data/formula.json: -------------------------------------------------------------------------------- 1 | [{"id": "30135", "name": "D32\u94a2", "goldCost": 400, "costs": [{"id": "30084", "name": "\u4e09\u6c34\u9530\u77ff", "rarity": 3, "count": 1}, {"id": "30094", "name": "\u4e94\u6c34\u7814\u78e8\u77f3", "rarity": 3, "count": 1}, {"id": "30104", "name": "RMA70-24", "rarity": 3, "count": 1}], "extraOutcome": [{"id": "30014", "name": "\u63d0\u7eaf\u6e90\u5ca9", "rarity": 3, "count": 1, "weight": 84}, {"id": "30024", "name": "\u7cd6\u805a\u5757", "rarity": 3, "count": 1, "weight": 63}, {"id": "30034", "name": "\u805a\u9178\u916f\u5757", "rarity": 3, "count": 1, "weight": 63}, {"id": "30044", "name": "\u5f02\u94c1\u5757", "rarity": 3, "count": 1, "weight": 56}, {"id": "30054", "name": "\u916e\u9635\u5217", "rarity": 3, "count": 1, "weight": 56}, {"id": "30064", "name": "\u6539\u91cf\u88c5\u7f6e", "rarity": 3, "count": 1, "weight": 42}, {"id": "30074", "name": "\u767d\u9a6c\u9187", "rarity": 3, "count": 1, "weight": 72}, {"id": "30084", "name": "\u4e09\u6c34\u9530\u77ff", "rarity": 3, "count": 1, "weight": 63}, {"id": "30094", "name": "\u4e94\u6c34\u7814\u78e8\u77f3", "rarity": 3, "count": 1, "weight": 63}, {"id": "30104", "name": "RMA70-24", "rarity": 3, "count": 1, "weight": 56}, {"count": 1, "id": "31014", "name": "\u805a\u5408\u51dd\u80f6", "rarity": 3, "weight": 72}, {"count": 1, "id": "31024", "name": "\u70bd\u5408\u91d1\u5757", "rarity": 3, "weight": 63}, {"id": "31034", "name": "\u6676\u4f53\u7535\u8def", "rarity": 3, "count": 1, "weight": 56}], "totalWeight": 809}, {"id": "30125", "name": "\u53cc\u6781\u7eb3\u7c73\u7247", "goldCost": 400, "costs": [{"id": "30064", "name": "\u6539\u91cf\u88c5\u7f6e", "rarity": 3, "count": 1}, {"id": "30074", "name": "\u767d\u9a6c\u9187", "rarity": 3, "count": 2}], "extraOutcome": [{"id": "30014", "name": "\u63d0\u7eaf\u6e90\u5ca9", "rarity": 3, "count": 1, "weight": 84}, {"id": "30024", "name": "\u7cd6\u805a\u5757", "rarity": 3, "count": 1, "weight": 63}, {"id": "30034", "name": "\u805a\u9178\u916f\u5757", "rarity": 3, "count": 1, "weight": 63}, {"id": "30044", "name": "\u5f02\u94c1\u5757", "rarity": 3, "count": 1, "weight": 56}, {"id": "30054", "name": "\u916e\u9635\u5217", "rarity": 3, "count": 1, "weight": 56}, {"id": "30064", "name": "\u6539\u91cf\u88c5\u7f6e", "rarity": 3, "count": 1, "weight": 42}, {"id": "30074", "name": "\u767d\u9a6c\u9187", "rarity": 3, "count": 1, "weight": 72}, {"id": "30084", "name": "\u4e09\u6c34\u9530\u77ff", "rarity": 3, "count": 1, "weight": 63}, {"id": "30094", "name": "\u4e94\u6c34\u7814\u78e8\u77f3", "rarity": 3, "count": 1, "weight": 63}, {"id": "30104", "name": "RMA70-24", "rarity": 3, "count": 1, "weight": 56}, {"count": 1, "id": "31014", "name": "\u805a\u5408\u51dd\u80f6", "rarity": 3, "weight": 72}, {"count": 1, "id": "31024", "name": "\u70bd\u5408\u91d1\u5757", "rarity": 3, "weight": 63}, {"id": "31034", "name": "\u6676\u4f53\u7535\u8def", "rarity": 3, "count": 1, "weight": 56}], "totalWeight": 809}, {"id": "30115", "name": "\u805a\u5408\u5242", "goldCost": 400, "costs": [{"id": "30014", "name": "\u63d0\u7eaf\u6e90\u5ca9", "rarity": 3, "count": 1}, {"id": "30044", "name": "\u5f02\u94c1\u5757", "rarity": 3, "count": 1}, {"id": "30054", "name": "\u916e\u9635\u5217", "rarity": 3, "count": 1}], "extraOutcome": [{"id": "30014", "name": "\u63d0\u7eaf\u6e90\u5ca9", "rarity": 3, "count": 1, "weight": 84}, {"id": "30024", "name": "\u7cd6\u805a\u5757", "rarity": 3, "count": 1, "weight": 63}, {"id": "30034", "name": "\u805a\u9178\u916f\u5757", "rarity": 3, "count": 1, "weight": 63}, {"id": "30044", "name": "\u5f02\u94c1\u5757", "rarity": 3, "count": 1, "weight": 56}, {"id": "30054", "name": "\u916e\u9635\u5217", "rarity": 3, "count": 1, "weight": 56}, {"id": "30064", "name": "\u6539\u91cf\u88c5\u7f6e", "rarity": 3, "count": 1, "weight": 42}, {"id": "30074", "name": "\u767d\u9a6c\u9187", "rarity": 3, "count": 1, "weight": 72}, {"id": "30084", "name": "\u4e09\u6c34\u9530\u77ff", "rarity": 3, "count": 1, "weight": 63}, {"id": "30094", "name": "\u4e94\u6c34\u7814\u78e8\u77f3", "rarity": 3, "count": 1, "weight": 63}, {"id": "30104", "name": "RMA70-24", "rarity": 3, "count": 1, "weight": 56}, {"count": 1, "id": "31014", "name": "\u805a\u5408\u51dd\u80f6", "rarity": 3, "weight": 72}, {"count": 1, "id": "31024", "name": "\u70bd\u5408\u91d1\u5757", "rarity": 3, "weight": 63}, {"id": "31034", "name": "\u6676\u4f53\u7535\u8def", "rarity": 3, "count": 1, "weight": 56}], "totalWeight": 809}, {"id": "30104", "name": "RMA70-24", "goldCost": 300, "costs": [{"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1}, {"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 2}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30094", "name": "\u4e94\u6c34\u7814\u78e8\u77f3", "goldCost": 300, "costs": [{"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30084", "name": "\u4e09\u6c34\u9530\u77ff", "goldCost": 300, "costs": [{"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 2}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30074", "name": "\u767d\u9a6c\u9187", "goldCost": 300, "costs": [{"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30062", "name": "\u88c5\u7f6e", "goldCost": 100, "costs": [{"id": "30061", "name": "\u7834\u635f\u88c5\u7f6e", "rarity": 0, "count": 3}], "extraOutcome": [{"id": "30011", "name": "\u6e90\u5ca9", "rarity": 0, "count": 1, "weight": 15}, {"id": "30021", "name": "\u4ee3\u7cd6", "rarity": 0, "count": 1, "weight": 10}, {"id": "30031", "name": "\u916f\u539f\u6599", "rarity": 0, "count": 1, "weight": 10}, {"id": "30041", "name": "\u5f02\u94c1\u788e\u7247", "rarity": 0, "count": 1, "weight": 8}, {"id": "30051", "name": "\u53cc\u916e", "rarity": 0, "count": 1, "weight": 8}, {"id": "30061", "name": "\u7834\u635f\u88c5\u7f6e", "rarity": 0, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "goldCost": 200, "costs": [{"id": "30062", "name": "\u88c5\u7f6e", "rarity": 1, "count": 4}], "extraOutcome": [{"id": "30012", "name": "\u56fa\u6e90\u5ca9", "rarity": 1, "count": 1, "weight": 15}, {"id": "30022", "name": "\u7cd6", "rarity": 1, "count": 1, "weight": 10}, {"id": "30032", "name": "\u805a\u9178\u916f", "rarity": 1, "count": 1, "weight": 10}, {"id": "30042", "name": "\u5f02\u94c1", "rarity": 1, "count": 1, "weight": 8}, {"id": "30052", "name": "\u916e\u51dd\u96c6", "rarity": 1, "count": 1, "weight": 8}, {"id": "30062", "name": "\u88c5\u7f6e", "rarity": 1, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30064", "name": "\u6539\u91cf\u88c5\u7f6e", "goldCost": 300, "costs": [{"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1}, {"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 2}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30052", "name": "\u916e\u51dd\u96c6", "goldCost": 100, "costs": [{"id": "30051", "name": "\u53cc\u916e", "rarity": 0, "count": 3}], "extraOutcome": [{"id": "30011", "name": "\u6e90\u5ca9", "rarity": 0, "count": 1, "weight": 15}, {"id": "30021", "name": "\u4ee3\u7cd6", "rarity": 0, "count": 1, "weight": 10}, {"id": "30031", "name": "\u916f\u539f\u6599", "rarity": 0, "count": 1, "weight": 10}, {"id": "30041", "name": "\u5f02\u94c1\u788e\u7247", "rarity": 0, "count": 1, "weight": 8}, {"id": "30051", "name": "\u53cc\u916e", "rarity": 0, "count": 1, "weight": 8}, {"id": "30061", "name": "\u7834\u635f\u88c5\u7f6e", "rarity": 0, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "goldCost": 200, "costs": [{"id": "30052", "name": "\u916e\u51dd\u96c6", "rarity": 1, "count": 4}], "extraOutcome": [{"id": "30012", "name": "\u56fa\u6e90\u5ca9", "rarity": 1, "count": 1, "weight": 15}, {"id": "30022", "name": "\u7cd6", "rarity": 1, "count": 1, "weight": 10}, {"id": "30032", "name": "\u805a\u9178\u916f", "rarity": 1, "count": 1, "weight": 10}, {"id": "30042", "name": "\u5f02\u94c1", "rarity": 1, "count": 1, "weight": 8}, {"id": "30052", "name": "\u916e\u51dd\u96c6", "rarity": 1, "count": 1, "weight": 8}, {"id": "30062", "name": "\u88c5\u7f6e", "rarity": 1, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30054", "name": "\u916e\u9635\u5217", "goldCost": 300, "costs": [{"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 2}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30042", "name": "\u5f02\u94c1", "goldCost": 100, "costs": [{"id": "30041", "name": "\u5f02\u94c1\u788e\u7247", "rarity": 0, "count": 3}], "extraOutcome": [{"id": "30011", "name": "\u6e90\u5ca9", "rarity": 0, "count": 1, "weight": 15}, {"id": "30021", "name": "\u4ee3\u7cd6", "rarity": 0, "count": 1, "weight": 10}, {"id": "30031", "name": "\u916f\u539f\u6599", "rarity": 0, "count": 1, "weight": 10}, {"id": "30041", "name": "\u5f02\u94c1\u788e\u7247", "rarity": 0, "count": 1, "weight": 8}, {"id": "30051", "name": "\u53cc\u916e", "rarity": 0, "count": 1, "weight": 8}, {"id": "30061", "name": "\u7834\u635f\u88c5\u7f6e", "rarity": 0, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "goldCost": 200, "costs": [{"id": "30042", "name": "\u5f02\u94c1", "rarity": 1, "count": 4}], "extraOutcome": [{"id": "30012", "name": "\u56fa\u6e90\u5ca9", "rarity": 1, "count": 1, "weight": 15}, {"id": "30022", "name": "\u7cd6", "rarity": 1, "count": 1, "weight": 10}, {"id": "30032", "name": "\u805a\u9178\u916f", "rarity": 1, "count": 1, "weight": 10}, {"id": "30042", "name": "\u5f02\u94c1", "rarity": 1, "count": 1, "weight": 8}, {"id": "30052", "name": "\u916e\u51dd\u96c6", "rarity": 1, "count": 1, "weight": 8}, {"id": "30062", "name": "\u88c5\u7f6e", "rarity": 1, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30044", "name": "\u5f02\u94c1\u5757", "goldCost": 300, "costs": [{"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 2}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30032", "name": "\u805a\u9178\u916f", "goldCost": 100, "costs": [{"id": "30031", "name": "\u916f\u539f\u6599", "rarity": 0, "count": 3}], "extraOutcome": [{"id": "30011", "name": "\u6e90\u5ca9", "rarity": 0, "count": 1, "weight": 15}, {"id": "30021", "name": "\u4ee3\u7cd6", "rarity": 0, "count": 1, "weight": 10}, {"id": "30031", "name": "\u916f\u539f\u6599", "rarity": 0, "count": 1, "weight": 10}, {"id": "30041", "name": "\u5f02\u94c1\u788e\u7247", "rarity": 0, "count": 1, "weight": 8}, {"id": "30051", "name": "\u53cc\u916e", "rarity": 0, "count": 1, "weight": 8}, {"id": "30061", "name": "\u7834\u635f\u88c5\u7f6e", "rarity": 0, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "goldCost": 200, "costs": [{"id": "30032", "name": "\u805a\u9178\u916f", "rarity": 1, "count": 4}], "extraOutcome": [{"id": "30012", "name": "\u56fa\u6e90\u5ca9", "rarity": 1, "count": 1, "weight": 15}, {"id": "30022", "name": "\u7cd6", "rarity": 1, "count": 1, "weight": 10}, {"id": "30032", "name": "\u805a\u9178\u916f", "rarity": 1, "count": 1, "weight": 10}, {"id": "30042", "name": "\u5f02\u94c1", "rarity": 1, "count": 1, "weight": 8}, {"id": "30052", "name": "\u916e\u51dd\u96c6", "rarity": 1, "count": 1, "weight": 8}, {"id": "30062", "name": "\u88c5\u7f6e", "rarity": 1, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30034", "name": "\u805a\u9178\u916f\u5757", "goldCost": 300, "costs": [{"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 2}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30022", "name": "\u7cd6", "goldCost": 100, "costs": [{"id": "30021", "name": "\u4ee3\u7cd6", "rarity": 0, "count": 3}], "extraOutcome": [{"id": "30011", "name": "\u6e90\u5ca9", "rarity": 0, "count": 1, "weight": 15}, {"id": "30021", "name": "\u4ee3\u7cd6", "rarity": 0, "count": 1, "weight": 10}, {"id": "30031", "name": "\u916f\u539f\u6599", "rarity": 0, "count": 1, "weight": 10}, {"id": "30041", "name": "\u5f02\u94c1\u788e\u7247", "rarity": 0, "count": 1, "weight": 8}, {"id": "30051", "name": "\u53cc\u916e", "rarity": 0, "count": 1, "weight": 8}, {"id": "30061", "name": "\u7834\u635f\u88c5\u7f6e", "rarity": 0, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30023", "name": "\u7cd6\u7ec4", "goldCost": 200, "costs": [{"id": "30022", "name": "\u7cd6", "rarity": 1, "count": 4}], "extraOutcome": [{"id": "30012", "name": "\u56fa\u6e90\u5ca9", "rarity": 1, "count": 1, "weight": 15}, {"id": "30022", "name": "\u7cd6", "rarity": 1, "count": 1, "weight": 10}, {"id": "30032", "name": "\u805a\u9178\u916f", "rarity": 1, "count": 1, "weight": 10}, {"id": "30042", "name": "\u5f02\u94c1", "rarity": 1, "count": 1, "weight": 8}, {"id": "30052", "name": "\u916e\u51dd\u96c6", "rarity": 1, "count": 1, "weight": 8}, {"id": "30062", "name": "\u88c5\u7f6e", "rarity": 1, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30024", "name": "\u7cd6\u805a\u5757", "goldCost": 300, "costs": [{"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 2}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "30012", "name": "\u56fa\u6e90\u5ca9", "goldCost": 100, "costs": [{"id": "30011", "name": "\u6e90\u5ca9", "rarity": 0, "count": 3}], "extraOutcome": [{"id": "30011", "name": "\u6e90\u5ca9", "rarity": 0, "count": 1, "weight": 15}, {"id": "30021", "name": "\u4ee3\u7cd6", "rarity": 0, "count": 1, "weight": 10}, {"id": "30031", "name": "\u916f\u539f\u6599", "rarity": 0, "count": 1, "weight": 10}, {"id": "30041", "name": "\u5f02\u94c1\u788e\u7247", "rarity": 0, "count": 1, "weight": 8}, {"id": "30051", "name": "\u53cc\u916e", "rarity": 0, "count": 1, "weight": 8}, {"id": "30061", "name": "\u7834\u635f\u88c5\u7f6e", "rarity": 0, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "goldCost": 200, "costs": [{"id": "30012", "name": "\u56fa\u6e90\u5ca9", "rarity": 1, "count": 5}], "extraOutcome": [{"id": "30012", "name": "\u56fa\u6e90\u5ca9", "rarity": 1, "count": 1, "weight": 15}, {"id": "30022", "name": "\u7cd6", "rarity": 1, "count": 1, "weight": 10}, {"id": "30032", "name": "\u805a\u9178\u916f", "rarity": 1, "count": 1, "weight": 10}, {"id": "30042", "name": "\u5f02\u94c1", "rarity": 1, "count": 1, "weight": 8}, {"id": "30052", "name": "\u916e\u51dd\u96c6", "rarity": 1, "count": 1, "weight": 8}, {"id": "30062", "name": "\u88c5\u7f6e", "rarity": 1, "count": 1, "weight": 6}], "totalWeight": 57}, {"id": "30014", "name": "\u63d0\u7eaf\u6e90\u5ca9", "goldCost": 300, "costs": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 4}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"costs": [{"count": 1, "id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2}, {"count": 1, "id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2}], "extraOutcome": [{"count": 1, "id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "weight": 60}, {"count": 1, "id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "weight": 50}, {"count": 1, "id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "weight": 50}, {"count": 1, "id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "weight": 40}, {"count": 1, "id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "weight": 40}, {"count": 1, "id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "weight": 30}, {"count": 1, "id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "weight": 45}, {"count": 1, "id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "weight": 40}, {"count": 1, "id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "weight": 36}, {"count": 1, "id": "30103", "name": "RMA70-12", "rarity": 2, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "goldCost": 300, "id": "31024", "name": "\u70bd\u5408\u91d1\u5757", "totalWeight": 527}, {"costs": [{"count": 1, "id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2}], "extraOutcome": [{"count": 1, "id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "weight": 60}, {"count": 1, "id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "weight": 50}, {"count": 1, "id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "weight": 50}, {"count": 1, "id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "weight": 40}, {"count": 1, "id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "weight": 40}, {"count": 1, "id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "weight": 30}, {"count": 1, "id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "weight": 45}, {"count": 1, "id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "weight": 40}, {"count": 1, "id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "weight": 36}, {"count": 1, "id": "30103", "name": "RMA70-12", "rarity": 2, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "31033", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "goldCost": 300, "id": "31014", "name": "\u805a\u5408\u51dd\u80f6", "totalWeight": 527}, {"id": "31034", "name": "\u6676\u4f53\u7535\u8def", "goldCost": 300, "costs": [{"id": "30133", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 2}, {"id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "count": 1}, {"id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "count": 1}], "extraOutcome": [{"id": "30013", "name": "\u56fa\u6e90\u5ca9\u7ec4", "rarity": 2, "count": 1, "weight": 60}, {"id": "30023", "name": "\u7cd6\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30033", "name": "\u805a\u9178\u916f\u7ec4", "rarity": 2, "count": 1, "weight": 50}, {"id": "30043", "name": "\u5f02\u94c1\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30053", "name": "\u916e\u51dd\u96c6\u7ec4", "rarity": 2, "count": 1, "weight": 40}, {"id": "30063", "name": "\u5168\u65b0\u88c5\u7f6e", "rarity": 2, "count": 1, "weight": 30}, {"id": "30073", "name": "\u626d\u8f6c\u9187", "rarity": 2, "count": 1, "weight": 45}, {"id": "30083", "name": "\u8f7b\u9530\u77ff", "rarity": 2, "count": 1, "weight": 40}, {"id": "30093", "name": "\u7814\u78e8\u77f3", "rarity": 2, "count": 1, "weight": 36}, {"id": "30103", "name": "RMA70-12", "rarity": 2, "count": 1, "weight": 30}, {"count": 1, "id": "31013", "name": "\u51dd\u80f6", "rarity": 2, "weight": 36}, {"count": 1, "id": "31023", "name": "\u70bd\u5408\u91d1", "rarity": 2, "weight": 40}, {"id": "30133", "name": "\u6676\u4f53\u5143\u4ef6", "rarity": 2, "count": 1, "weight": 30}], "totalWeight": 527}, {"id": "31035", "name": "\u6676\u4f53\u7535\u5b50\u5355\u5143", "goldCost": 400, "costs": [{"id": "31034", "name": "\u6676\u4f53\u7535\u8def", "rarity": 3, "count": 1}, {"id": "31014", "name": "\u805a\u5408\u51dd\u80f6", "rarity": 3, "count": 2}, {"id": "31024", "name": "\u70bd\u5408\u91d1\u5757", "rarity": 3, "count": 1}], "extraOutcome": [{"id": "30014", "name": "\u63d0\u7eaf\u6e90\u5ca9", "rarity": 3, "count": 1, "weight": 84}, {"id": "30024", "name": "\u7cd6\u805a\u5757", "rarity": 3, "count": 1, "weight": 63}, {"id": "30034", "name": "\u805a\u9178\u916f\u5757", "rarity": 3, "count": 1, "weight": 63}, {"id": "30044", "name": "\u5f02\u94c1\u5757", "rarity": 3, "count": 1, "weight": 56}, {"id": "30054", "name": "\u916e\u9635\u5217", "rarity": 3, "count": 1, "weight": 56}, {"id": "30064", "name": "\u6539\u91cf\u88c5\u7f6e", "rarity": 3, "count": 1, "weight": 42}, {"id": "30074", "name": "\u767d\u9a6c\u9187", "rarity": 3, "count": 1, "weight": 72}, {"id": "30084", "name": "\u4e09\u6c34\u9530\u77ff", "rarity": 3, "count": 1, "weight": 63}, {"id": "30094", "name": "\u4e94\u6c34\u7814\u78e8\u77f3", "rarity": 3, "count": 1, "weight": 63}, {"id": "30104", "name": "RMA70-24", "rarity": 3, "count": 1, "weight": 56}, {"count": 1, "id": "31014", "name": "\u805a\u5408\u51dd\u80f6", "rarity": 3, "weight": 72}, {"count": 1, "id": "31024", "name": "\u70bd\u5408\u91d1\u5757", "rarity": 3, "weight": 63}, {"id": "30134", "name": "\u6676\u4f53\u7535\u8def", "rarity": 3, "count": 1, "weight": 56}], "totalWeight": 809}] -------------------------------------------------------------------------------- /MaterialPlanning.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import urllib.request, json, time, os, copy, sys 3 | from scipy.optimize import linprog 4 | from utils import Price, Credit, 凝胶_group, 凝胶_update, 炽合金_group, 炽合金_update, Orange, CCStores, Purple 5 | from collections import defaultdict as ddict 6 | import pandas as pd 7 | 8 | global penguin_url 9 | penguin_url = 'https://penguin-stats.io/PenguinStats/api/' 10 | 11 | class MaterialPlanning(object): 12 | 13 | def __init__(self, 14 | filter_freq=10, 15 | filter_stages=[], 16 | url_stats='v2/result/matrix?show_stage_details=true&show_item_details=true', 17 | url_rules='formula', 18 | path_stats='data/matrix.json', 19 | path_rules='data/formula.json', 20 | path_items='data/items.json', 21 | path_stages='data/stages.json', 22 | update=False, 23 | banned_stages={}, 24 | # expValue=30, 25 | ConvertionDR=0.18, 26 | printSetting='1111111111', 27 | costLimit=135, 28 | costType='stone', 29 | base_exp=0, 30 | base_gold=0, 31 | base_MTL_GOLD3=0, 32 | is_supply_lt_60=True, 33 | stone_per_day=0, 34 | display_main_only=True, 35 | SuiGuoHuaDeng=False, 36 | ExpFromBase=False, 37 | CCSeason=1, 38 | url_stages='v2/stages', 39 | url_items ='v2/items'): 40 | """ 41 | Object initialization. 42 | Args: 43 | filter_freq: int or None. The lowest frequence that we consider. 44 | No filter will be applied if None. 45 | url_stats: string. url to the dropping rate stats data. 46 | url_rules: string. url to the composing rules data. 47 | path_stats: string. local path to the dropping rate stats data. 48 | path_rules: string. local path to the composing rules data. 49 | """ 50 | try: 51 | material_probs, self.convertion_rules, self.item_list, self.stage_list = load_data(path_stats, path_rules, path_items, path_stages) 52 | except: 53 | print('获取本地文件失败...', end=' ') 54 | material_probs, self.convertion_rules, self.item_list, self.stage_list =\ 55 | request_data(penguin_url+url_stats, penguin_url+url_rules, penguin_url+url_items, 56 | penguin_url+url_stages, path_stats, path_rules, path_items, path_stages) 57 | print('done.') 58 | if update: 59 | print('强制更新...', end=' ') 60 | material_probs, self.convertion_rules, self.item_list, self.stage_list =\ 61 | request_data(penguin_url+url_stats, penguin_url+url_rules, penguin_url+url_items, 62 | penguin_url+url_stages, path_stats, path_rules, path_items, path_stages) 63 | print('done.') 64 | 65 | 66 | self.exp_factor = 1 67 | 68 | self.公招出四星的概率 = 0.186 69 | self.costLimit = costLimit #理智上限 70 | # self.convertion_rules = convertion_rules 71 | self.material_probs = material_probs 72 | self.banned_stages = banned_stages 73 | self.costType = costType 74 | self.display_main_only = display_main_only 75 | self.SuiGuoHuaDeng = SuiGuoHuaDeng 76 | self.stage_times = ddict(int) 77 | self.Notes = dict() 78 | self.best_stage = dict() 79 | self.ExpFromBase = ExpFromBase 80 | 81 | self.base_exp = base_exp 82 | self.base_gold = base_gold 83 | self.base_MTL_GOLD3 = base_MTL_GOLD3 84 | self.everyday_cost = (200-25*5)/7 + 240 + 60 * is_supply_lt_60 + stone_per_day*self.costLimit 85 | 86 | self.ccseason = CCSeason 87 | filtered_probs = [] 88 | excluded_stages = set() 89 | for dct in material_probs['matrix']: 90 | item, stage, times = self.item_list[dct['itemId']], self.stage_list[dct['stageId']]['code'], int(dct['times']) 91 | if item in filter_stages: continue 92 | if times > self.stage_times[stage] or self.stage_times[stage] == 0 and stage not in filter_stages: 93 | self.stage_times[stage] = times 94 | if times >= filter_freq and stage not in filter_stages: 95 | filtered_probs.append(dct) 96 | elif stage not in excluded_stages: 97 | print('%8s的 %s 未加入统计, 样本数%d'%(stage, item, times)) 98 | excluded_stages.add(stage) 99 | material_probs['matrix'] = filtered_probs 100 | 101 | self.ConvertionDR = ConvertionDR 102 | self._pre_processing(material_probs) 103 | self._set_lp_parameters() 104 | assert len(printSetting)==12, 'printSetting 长度应为10' 105 | assert printSetting.count('1') + printSetting.count('0') == 12, 'printSetting 中只能含有0或1' 106 | self.printSetting = [int(x) for x in printSetting] 107 | 108 | 109 | def _pre_processing(self, material_probs): 110 | """ 111 | Compute costs, convertion rules and items probabilities from requested dictionaries. 112 | Args: 113 | material_probs: List of dictionaries recording the dropping info per stage per item. 114 | Keys of instances: ["itemID", "times", "itemName", "quantity", "apCost", "stageCode", "stageID"]. 115 | convertion_rules: List of dictionaries recording the rules of composing. 116 | Keys of instances: ["id", "name", "level", "source", "madeof"]. 117 | """ 118 | # To count items and stages. 119 | additional_items = {'30135': u'D32钢', '30125': u'双极纳米片', 120 | '30115': u'聚合剂', '00010':'经验', '4001':'龙门币', 121 | '31014':'聚合凝胶', '31024':'炽合金块', '31013':'凝胶', 122 | '31023':'炽合金', 123 | '3303':'技巧概要·卷3', '3302':'技巧概要·卷2', '3301':'技巧概要·卷1', 124 | '00030':'家具零件', '3003': '赤金', 125 | '3211': '先锋芯片', '3212': '先锋芯片组', '3213': '先锋双芯片', 126 | '3221': '近卫芯片', '3222': '近卫芯片组', '3223': '近卫双芯片', 127 | '3231': '重装芯片', '3232': '重装芯片组', '3233': '重装双芯片', 128 | '3241': '狙击芯片', '3242': '狙击芯片组', '3243': '狙击双芯片', 129 | '3251': '术师芯片', '3252': '术师芯片组', '3253': '术师双芯片', 130 | '3261': '医疗芯片', '3262': '医疗芯片组', '3263': '医疗双芯片', 131 | '3271': '辅助芯片', '3272': '辅助芯片组', '3273': '辅助双芯片', 132 | '3281': '特种芯片', '3282': '特种芯片组', '3283': '特种双芯片', 133 | '4006': '采购凭证', '7003': '寻访凭证', '32001': '芯片助剂', 134 | '7001': '招聘许可', 135 | '2004': '高级作战记录', '2003': '中级作战记录', '2002': '初级作战记录', '2001': '基础作战记录', 136 | '3112': '碳', '3113': '碳素', '3114': '碳素组', 137 | '4003': '合成玉', 138 | '31033': '晶体元件', '31034': '晶体电路', '30145': '晶体电子单元' 139 | } 140 | additional_items = {k: v for v, k in additional_items.items()} 141 | item_dct = {} 142 | stage_dct = {} 143 | 144 | for dct in material_probs['matrix']: 145 | item_dct[self.item_list[dct['itemId']]] = dct['itemId'] 146 | stage_dct[self.stage_list[dct['stageId']]['code']] = dct['stageId'] 147 | item_dct.update(additional_items) 148 | # To construct mapping from id to item names. 149 | item_array = [] 150 | item_id_array = [] 151 | for v, k in item_dct.items(): 152 | try: 153 | float(k) 154 | item_array.append(v) 155 | item_id_array.append(k) 156 | except: 157 | pass 158 | self.item_array = np.array(item_array) 159 | self.item_id_array = np.array(item_id_array) 160 | self.item_dct_rv = {v:k for k,v in enumerate(item_array)} 161 | self.item_id_to_name = {self.item_id_array[k]:item for k,item in enumerate(item_array)} 162 | self.item_name_to_id = {item:self.item_id_array[k] for k,item in enumerate(item_array)} 163 | 164 | # To construct mapping from stage id to stage names and vice versa. 165 | self.stage_array =[] 166 | for v, k in stage_dct.items(): 167 | if v not in self.banned_stages: 168 | self.stage_array.append(v) 169 | 170 | self.stage_dct_rv = {v: k for k, v in enumerate(self.stage_array)} 171 | 172 | # To format dropping records into sparse probability matrix 173 | self.cost_lst = np.zeros(len(self.stage_array)) 174 | 175 | self.update_stage() 176 | self.stage_array = np.array(self.stage_array) 177 | self.probs_matrix = np.zeros([len(self.stage_array), len(item_array)]) 178 | 179 | for dct in material_probs['matrix']: 180 | try: 181 | if dct['itemId'] == 'furni': continue 182 | item, stage, cost = self.item_id_to_name[dct['itemId']], self.stage_list[dct['stageId']]['code'], int(self.stage_list[dct['stageId']]['cost']) 183 | self.probs_matrix[self.stage_dct_rv[stage], self.item_dct_rv[item]] = dct['quantity'] / int(dct['times']) 184 | 185 | self.cost_lst[self.stage_dct_rv[stage]] = cost 186 | except Exception as e: 187 | print(f'材料{item}\t关卡{stage}({cost}) 添加失败 {e}') 188 | 189 | for k, stage in enumerate(self.stage_array): 190 | self.probs_matrix[k, self.item_dct_rv['龙门币']] = self.cost_lst[k]*12 191 | self.update_droprate() 192 | 193 | # To build equavalence relationship from convert_rule_dct. 194 | self.update_convertion() 195 | self.convertions_dct = {} 196 | convertion_matrix = [] 197 | convertion_outc_matrix = [] 198 | convertion_cost_lst = [] 199 | for rule in self.convertion_rules: 200 | convertion = np.zeros(len(self.item_array)) 201 | convertion[self.item_dct_rv[rule['name']]] = 1 202 | 203 | comp_dct = {comp['name']:comp['count'] for comp in rule['costs']} 204 | self.convertions_dct[rule['name']] = comp_dct 205 | for iname in comp_dct: 206 | convertion[self.item_dct_rv[iname]] -= comp_dct[iname] 207 | convertion[self.item_dct_rv['龙门币']] -= rule['goldCost'] 208 | convertion_matrix.append(copy.deepcopy(convertion)) 209 | 210 | outc_dct = {outc['name']:outc['count'] for outc in rule['extraOutcome']} 211 | outc_wgh = {outc['name']:outc['weight'] for outc in rule['extraOutcome']} 212 | weight_sum = float(rule['totalWeight']) 213 | for iname in outc_dct: 214 | convertion[self.item_dct_rv[iname]] += outc_dct[iname]*self.ConvertionDR*outc_wgh[iname]/weight_sum 215 | convertion_outc_matrix.append(convertion) 216 | convertion_cost_lst.append(0) 217 | 218 | 219 | # 处理新材料 220 | for stage, item in 凝胶_update.items(): 221 | if stage not in self.stage_array: 222 | continue 223 | 蓝色额外产物原掉率 = np.mean([self.probs_matrix[self.stage_dct_rv[stage]][self.item_dct_rv[x]]*w[0] for x, w in 凝胶_group.items() if x != item]) 224 | 蓝色额外产物实际掉率 = self.probs_matrix[self.stage_dct_rv[stage]][self.item_dct_rv['凝胶']]/(36/171*4) 225 | 修正值 = 蓝色额外产物实际掉率 - 蓝色额外产物原掉率 226 | for item, w in 凝胶_group.items(): 227 | self.probs_matrix[self.stage_dct_rv[stage]][self.item_dct_rv[item]] += 修正值*w[1] 228 | 229 | for stage, item in 炽合金_update.items(): 230 | if stage not in self.stage_array: 231 | continue 232 | 蓝色额外产物原掉率 = np.mean([self.probs_matrix[self.stage_dct_rv[stage]][self.item_dct_rv[x]]*w[0] for x in 炽合金_group if x != item]) 233 | 蓝色额外产物实际掉率 = self.probs_matrix[self.stage_dct_rv[stage]][self.item_dct_rv['炽合金']]/(4/17*4) 234 | 修正值 = 蓝色额外产物实际掉率 - 蓝色额外产物原掉率 235 | for item, w in 炽合金_group.items(): 236 | self.probs_matrix[self.stage_dct_rv[stage]][self.item_dct_rv[item]] += 修正值*w[1] 237 | 238 | 239 | convertions_group = (np.array(convertion_matrix), np.array(convertion_outc_matrix), convertion_cost_lst) 240 | self.convertion_matrix, self.convertion_outc_matrix, self.convertion_cost_lst = convertions_group 241 | 242 | def _set_lp_parameters(self): 243 | """ 244 | Object initialization. 245 | Args: 246 | convertion_matrix: matrix of shape [n_rules, n_items]. 247 | Each row represent a rule. 248 | convertion_cost_lst: list. Cost in equal value to the currency spent in convertion. 249 | probs_matrix: sparse matrix of shape [n_stages, n_items]. 250 | Items per clear (probabilities) at each stage. 251 | cost_lst: list. Costs per clear at each stage. 252 | """ 253 | assert len(self.probs_matrix)==len(self.cost_lst) 254 | assert len(self.convertion_matrix)==len(self.convertion_cost_lst) 255 | assert self.probs_matrix.shape[1]==self.convertion_matrix.shape[1] 256 | 257 | def update(self, 258 | filter_freq=20, 259 | filter_stages=[], 260 | url_stats='result/matrix?show_stage_details=true&show_item_details=true', 261 | url_rules='formula', 262 | path_stats='data/matrix.json', 263 | path_rules='data/formula.json'): 264 | """ 265 | To update parameters when probabilities change or new items added. 266 | Args: 267 | url_stats: string. url to the dropping rate stats data. 268 | url_rules: string. url to the composing rules data. 269 | path_stats: string. local path to the dropping rate stats data. 270 | path_rules: string. local path to the composing rules data. 271 | """ 272 | print('Requesting data from web resources (i.e., penguin-stats.io)...', end=' ') 273 | material_probs, self.convertion_rules = request_data(penguin_url+url_stats, penguin_url+url_rules, path_stats, path_rules) 274 | print('done.') 275 | 276 | if filter_freq: 277 | filtered_probs = [] 278 | for dct in material_probs['matrix']: 279 | if dct['times']>=filter_freq and dct['stage']['code'] not in filter_stages: 280 | filtered_probs.append(dct) 281 | material_probs['matrix'] = filtered_probs 282 | self._pre_processing(material_probs) 283 | self._set_lp_parameters() 284 | 285 | 286 | def _get_plan_no_prioties(self, demand_lst, outcome=False, gold_demand=True, exp_demand=True): 287 | """ 288 | To solve linear programming problem without prioties. 289 | Args: 290 | demand_lst: list of materials demand. Should include all items (zero if not required). 291 | Returns: 292 | strategy: list of required clear times for each stage. 293 | fun: estimated total cost. 294 | """ 295 | A_ub = (np.vstack([self.probs_matrix, self.convertion_outc_matrix]) 296 | if outcome else np.vstack([self.probs_matrix, self.convertion_matrix])).T 297 | if self.costType == 'time': 298 | timedata = pd.read_csv('data/time.csv') 299 | for k, v in enumerate(self.stage_array): 300 | for l, s in enumerate(timedata.stage): 301 | if s[1:-1] == v: 302 | self.cost_lst[k] = timedata.time[l] 303 | break 304 | self.farm_cost = (self.cost_lst) 305 | cost = (np.hstack([self.farm_cost, self.convertion_cost_lst])) 306 | assert np.any(self.farm_cost>=0) 307 | 308 | excp_factor = 1.0 309 | dual_factor = 1.0 310 | 311 | while excp_factor>1e-7: 312 | solution = linprog(c=cost, 313 | A_ub=-A_ub, 314 | b_ub=-np.array(demand_lst)*excp_factor, 315 | method='interior-point') 316 | if solution.status != 4: 317 | break 318 | 319 | excp_factor /= 10.0 320 | 321 | while dual_factor>1e-7: 322 | dual_solution = linprog(c=-np.array(demand_lst)*excp_factor*dual_factor, 323 | A_ub=A_ub.T, 324 | b_ub=cost, 325 | method='interior-point') 326 | if solution.status != 4: 327 | break 328 | 329 | dual_factor /= 10.0 330 | 331 | 332 | return solution, dual_solution, excp_factor 333 | 334 | def get_plan(self, requirement_dct, deposited_dct={}, 335 | print_output=False, outcome=False, gold_demand=True, exp_demand=True): 336 | """ 337 | User API. Computing the material plan given requirements and owned items. 338 | Args: 339 | requirement_dct: dictionary. Contain only required items with their numbers. 340 | deposit_dct: dictionary. Contain only owned items with their numbers. 341 | """ 342 | self.print_output = print_output 343 | status_dct = {0: 'Optimization terminated successfully. ', 344 | 1: 'Iteration limit reached. ', 345 | 2: 'Problem appears to be infeasible. ', 346 | 3: 'Problem appears to be unbounded. ', 347 | 4: 'Numerical difficulties encountered.'} 348 | 349 | demand_lst = np.zeros(len(self.item_array)) 350 | for k, v in requirement_dct.items(): 351 | demand_lst[self.item_dct_rv[k]] = v 352 | for k, v in deposited_dct.items(): 353 | demand_lst[self.item_dct_rv[k]] -= v 354 | solution, dual_solution, excp_factor = self._get_plan_no_prioties(demand_lst, outcome, gold_demand, exp_demand) 355 | x, status = solution.x/excp_factor, solution.status 356 | y, self.slack = dual_solution.x, dual_solution.slack 357 | self.y = y 358 | n_looting, n_convertion = x[:len(self.cost_lst)], x[len(self.cost_lst):] 359 | 360 | cost = np.dot(x[:len(self.cost_lst)], self.cost_lst) 361 | 362 | if status != 0: 363 | raise ValueError(status_dct[status]) 364 | 365 | self.stages = [] 366 | self.fullstages = [] 367 | self.effect = dict() 368 | for i, t in enumerate(n_looting): 369 | # if t >= 0: 370 | # self.effect[self.stage_array[i]] = sum([probsProb*self.item_values[self.item_array[[probsidx]]] for probsidx, probsProb in enumerate(self.probs_matrix[i])])/self.farm_cost[i] 371 | # if t >= 0.1: 372 | stage_name = self.stage_array[i] 373 | if stage_name[:2] in ['SK', 'AP', 'CE', 'LS', 'PR'] and self.display_main_only: 374 | continue 375 | target_items = np.where(self.probs_matrix[i]>0.01)[0] 376 | items = {self.item_array[idx]: float2str(self.probs_matrix[i, idx]*t) 377 | for idx in target_items if len(self.item_id_array[idx])<=5} 378 | stage = { 379 | "stage": self.stage_array[i], 380 | "count": float2str(t), 381 | "items": items 382 | } 383 | self.stages.append(stage) 384 | 385 | self.syntheses = [] 386 | for i,t in enumerate(n_convertion): 387 | if t >= 0.1: 388 | target_item = self.item_array[np.argmax(self.convertion_matrix[i])] 389 | if target_item in ['经验', '龙门币']: 390 | target_item_index = np.argmin(self.convertion_matrix[i]) 391 | materials = {self.item_array[target_item_index]:\ 392 | str(np.round(-self.convertion_matrix[i][target_item_index]*int(t+0.9),4))} 393 | else: 394 | materials = {k: str(v*int(t+0.9)) for k,v in self.convertions_dct[target_item].items()} 395 | synthesis = { 396 | "target": target_item, 397 | "count": str(int(t+0.9)), 398 | "materials": materials 399 | } 400 | self.syntheses.append(synthesis) 401 | elif t >= 0.05: 402 | target_item = self.item_array[np.argmax(self.convertion_matrix[i])] 403 | materials = { k: '%.1f'%(v*t) for k,v in self.convertions_dct[target_item].items() } 404 | synthesis = { 405 | "target": target_item, 406 | "count": '%.1f'%t, 407 | "materials": materials 408 | } 409 | self.syntheses.append(synthesis) 410 | 411 | self.values = [{"level":'1', "items":[]}, 412 | {"level":'2', "items":[]}, 413 | {"level":'3', "items":[]}, 414 | {"level":'4', "items":[]}, 415 | {"level":'5', "items":[]}, 416 | {"level":'0', "items":[]}] 417 | 418 | self.item_value = dict() 419 | 420 | for i,item in enumerate(self.item_array): 421 | if y[i]>=0: 422 | if y[i]>0.1: 423 | item_value = { 424 | "name": item, 425 | "value": '%.2f'%y[i] 426 | } 427 | else: 428 | item_value = { 429 | "name": item, 430 | "value": '%.5f'%(y[i]) 431 | } 432 | self.item_value[item] = y[i] 433 | self.values[int(self.item_id_array[i][-1])-1]['items'].append(item_value) 434 | self.item_value['寻访凭证'] = self.costLimit * 600 / 180 435 | self.item_value['合成玉'] = self.item_value['寻访凭证']/600 436 | self.item_value['芯片助剂'] = self.item_value['采购凭证'] * 90 437 | self.item_value['招聘许可'] = (20*self.公招出四星的概率+10)*self.item_value['糖组']/Price['糖组']+38/258*600/180*self.costLimit*self.公招出四星的概率 - self.item_value['龙门币']*774 438 | self.item_value['碳'] = (self.item_value['家具零件']*4-200*self.item_value['龙门币'])/(1-0.5*self.ConvertionDR) 439 | self.item_value['先锋皇家信物'] = self.item_value['采购凭证'] * 2000 440 | 441 | for group in self.values: 442 | group["items"] = sorted(group["items"], key=lambda k: float(k['value']), reverse=True) 443 | # self.values = sorted(self.values, key=lambda x: float(x['value']), reverse=True) 444 | for i, stage in enumerate(self.stage_array): 445 | self.effect[stage] = sum([probsProb*self.item_value[self.item_array[probsidx]] for probsidx, probsProb in enumerate(self.probs_matrix[i])])/self.farm_cost[i] 446 | self.res = { 447 | "cost": int(cost), 448 | "stages": self.stages, 449 | "syntheses": self.syntheses, 450 | "values": list(reversed(self.values)) 451 | } 452 | 453 | self.output() 454 | return self.res, x, self.effect 455 | 456 | def merge_droprate(self): 457 | self.droprate = ddict(dict) 458 | for itemIndex, item in enumerate(self.item_array): 459 | for stageIndex, stage in enumerate(self.stage_array): 460 | dr = self.probs_matrix[stageIndex, itemIndex] 461 | if dr > 0.0001: 462 | self.droprate[item][stage] = { 463 | 'droprate': dr, 464 | 'expected_cost': self.cost_lst[stageIndex]/dr, 465 | 'effect': self.effect[stage] 466 | } 467 | 468 | def stage_class(self, effect): 469 | if effect>0.99: 470 | return 'lowest_ap_stages' 471 | if effect>0.90: 472 | return 'balanced_stages' 473 | return 'drop_rate_first_stages' 474 | 475 | def output_best_stage(self, level='x'): 476 | ''' 477 | 筛选条件: 效率>0.99, 期望<1.2*最低期望 478 | 效率<0.99, 掉率>当前最大掉率 479 | 效率<0.99, 期望<当前最低期望 480 | ''' 481 | # 活动时和主线比较 482 | MainStageMap = { 483 | '异铁组': ['7-18'], 484 | '轻锰矿': ['R8-10'], 485 | '研磨石': ['7-17'], 486 | '酮凝集组': ['JT8-3'], 487 | 'RMA70-12': ['R8-9'], 488 | '装置': ['7-15'], 489 | '扭转醇': ['R8-2'], 490 | '糖组': ['4-2'], 491 | '凝胶': ['JT8-2'], 492 | '炽合金': ['R8-7'], 493 | '固源岩': ['1-7'], 494 | '聚酸酯组': ['7-4'], 495 | '晶体元件': ['R8-11'] 496 | } 497 | self.merge_droprate() 498 | for item in self.item_array: 499 | if len(self.item_id_array[self.item_dct_rv[item]]) != 5 or item == '芯片助剂': 500 | continue 501 | itemLevel = self.item_id_array[self.item_dct_rv[item]][-1] 502 | if itemLevel != level: 503 | continue 504 | 505 | self.best_stage[item] = ddict(list) 506 | # 根据效率排序 507 | sorted_stages = sorted(self.droprate[item].items(), key=lambda x: x[1]['effect'], reverse=True) 508 | maxDropRate = max([x['droprate'] for x in self.droprate[item].values() if x['effect'] > 0.99]+[0.1]) 509 | minExpect = min([x['expected_cost'] for x in self.droprate[item].values() if x['effect'] > 0.99]+[200 if self.costType == 'stone' else 2000]) 510 | for stage, data in sorted_stages: 511 | if (data['droprate'] >= 1.25*maxDropRate) or\ 512 | (data['expected_cost'] <= 0.85*minExpect) or\ 513 | (data['effect'] > 0.98 and data['droprate'] > 0.8*maxDropRate and level=='3')or\ 514 | (data['effect'] > 0.98 and data['expected_cost'] <1.2*minExpect and level=='3')or\ 515 | (data['effect'] > 0.99 and data['droprate'] >= 0.9*maxDropRate)or\ 516 | (item in MainStageMap and stage in MainStageMap[item]): 517 | maxDropRate = max(maxDropRate, data['droprate']) 518 | minExpect = min(minExpect, data['expected_cost']) 519 | toAppend = { 520 | 'code': stage, 521 | 'drop_rate': '%.3f'%data['droprate'], 522 | 'efficiency': '%.3f'%data['effect'], 523 | 'ap_per_item': '%.1f'%data['expected_cost'], 524 | 'extra_drop': list(self.output_main_drop(stage, item)) 525 | } 526 | self.best_stage[item][self.stage_class(data['effect'])].append(toAppend) 527 | 528 | def output_droprate(self, stage): 529 | assert stage in self.stage_array 530 | for i, prob in enumerate(self.probs_matrix[self.stage_dct_rv[stage]]): 531 | if prob != 0: 532 | print(self.item_array[i], '\t%.3f' % (100*prob)) 533 | 534 | def output_WeiJiHeYue(self): 535 | HeYue=CCStores[self.ccseason*2+2] 536 | HYO = CCStores[self.ccseason*2+3] 537 | 538 | self.HeYueDict = { 539 | # '龙门币': 85 * self.item_value['龙门币'] / 1, 540 | # '中级作战记录': self.item_value['中级作战记录'] / 12, 541 | # '技巧概要·卷2(刷CA3)': 20/(3 + 1.18/3) / 15 *(1-self.gold_unit*1*12), 542 | # '技巧概要·卷2(不刷CA3)': self.item_value['技巧概要·卷2'] / 15, 543 | # '技巧概要·卷2(不刷CA3)': 30/(4 + 3*1.18/3 + 3*1.18*1.18/3/3)*2/3*1.18 / 15*(1-self.gold_unit*1*12), 544 | # '芯片': (18-0.165*0.5*18/3)/(0.5 + 0.5*2/3)/60*(1-self.gold_unit*1*12) 545 | } 546 | self.HYODict = { 547 | '柏喙': self.item_value['采购凭证'] * 600 / 300 548 | # '龙门币': 2000 * self.gold_unit / 15, 549 | # '中级作战记录': self.exp_unit*5*2 / 15, 550 | # '零件': 1/1.8, 551 | # '皮肤': 21*self.costLimit/3000 552 | } 553 | for item, value in HeYue.items(): 554 | self.HeYueDict[item] = self.item_value[item] / value 555 | self.item_value['高级作战记录'] = 2*self.item_value['中级作战记录'] 556 | for item, value in HYO.items(): 557 | self.HYODict[item] = self.item_value[item] / value 558 | if not self.print_output: 559 | return 560 | print('\n机密圣所(合约商店):') 561 | for k, v in sorted(self.HeYueDict.items(), key=lambda x:x[1], reverse=True): 562 | print('%s:\t%.3f'%(k, v)) 563 | print('常规池') 564 | for k, v in sorted(self.HYODict.items(), key=lambda x:x[1], reverse=True): 565 | print('%s:\t%.3f'%(k, v)) 566 | 567 | def output(self): 568 | Print_functions = [ 569 | self.output_cost, 570 | self.output_stages, 571 | self.output_items, 572 | self.output_values, 573 | self.output_green, 574 | self.output_yellow, 575 | self.output_effect, 576 | self.output_best_stage, 577 | self.output_credit, 578 | self.output_WeiJiHeYue, 579 | self.output_orange, 580 | self.output_purple 581 | ] 582 | for i, function in enumerate(Print_functions): 583 | if self.printSetting[i]: 584 | Print_functions[i]() 585 | return 586 | 587 | def output_cost(self): 588 | print('消耗理智 %d = %d 天, 相当于碎石 %d 颗, %d 元'%\ 589 | (self.res['cost'], int(self.res['cost']/self.everyday_cost), np.round(self.res['cost']/self.costLimit), 590 | np.round(self.res['cost']/self.costLimit*648/185))) 591 | if self.costType == 'time': 592 | print('消耗时间 %d 秒 = %.2f天'%\ 593 | (self.res['cost'], self.res['cost']/86400)) 594 | 595 | def output_stages(self): 596 | print('Loot at following stages:') 597 | for stage in self.stages: 598 | if float(stage['count']) > 1: 599 | # print(stage['items']) 600 | display_lst = [k + '(%s) '%v for k, v in sorted(stage['items'].items(), key=lambda x: (float(x[1])*self.item_value[x[0]]), reverse=True)][:5] 601 | # if stage['stage'] not in ['LS-5', 'CE-5']: 602 | # display_lst = display_lst[1:] + [display_lst[0]] 603 | print(stage['stage'] + '(%s 次) ===> '%stage['count'] 604 | + ', '.join(display_lst)) 605 | 606 | def output_main_drop(self, stage_name, target_item, gate=0.1, output=False): 607 | stageID = self.stage_dct_rv[stage_name] 608 | farm_cost = self.farm_cost[stageID] 609 | itemPercentage = [(self.item_value[self.item_array[k]]*v/farm_cost, self.item_array[k]) 610 | for k,v in enumerate(self.probs_matrix[stageID])] 611 | display_lst = [x for x in sorted(itemPercentage, key=lambda x:x[0], reverse=True) if x[0] > gate] 612 | if output: 613 | print(display_lst) 614 | for value, item in display_lst: 615 | # sys.stdout.write('%.3f\t%s\n' % (value, item)) 616 | if item != target_item: 617 | if item == '初级作战记录': item = '基础作战记录' 618 | if item == '龙门币': continue 619 | yield {'name': item, 'id': self.item_name_to_id[item]} 620 | 621 | def output_items(self): 622 | print('\nSynthesize following items:') 623 | for synthesis in self.syntheses: 624 | display_lst = [k + '(%s) '%synthesis['materials'][k] for k in synthesis['materials']] 625 | print(synthesis['target'] + '(%s) <=== '%synthesis['count'] 626 | + ', '.join(display_lst)) 627 | 628 | def output_values(self): 629 | print('[collapse=材料价值]') 630 | for i, group in reversed(list(enumerate(self.values))): 631 | display_lst = ['%s:%.6s'%(item['name'], self.item_value[item['name']]) for item in group['items']] 632 | if i == 5: 633 | # display_lst.append('罗德岛物资补给:%.2f'%((self.effect['罗德岛物资补给'])*99-99*12*self.item_value['龙门币'])) 634 | print('特殊材料:') 635 | print(', '.join(display_lst)) 636 | continue 637 | print('%d级材料: '%(i+1)) 638 | print(', '.join(display_lst)) 639 | # for x in self.values: 640 | # print('%s:\t %s' % (x['name'], x['value'])) 641 | # print('特殊材料:\n罗德岛物资补给:%.2f'%(self.effect['罗德岛物资补给']*99)) 642 | sys.stdout.write('[/collapse]') 643 | 644 | def output_green(self): 645 | self.greenTickets = {'招聘许可': self.item_value['招聘许可'] / Price['招聘许可'], 646 | '寻访凭证': self.item_value['寻访凭证'] / Price['寻访凭证']} 647 | 648 | for item in self.values[2]['items']: 649 | try: 650 | self.greenTickets[item['name']] = self.item_value[item['name']] / Price[item['name']] 651 | except: 652 | pass 653 | for k, item in enumerate(sorted(self.greenTickets.items(), key=lambda x:x[1], reverse=True)): 654 | if k < 0.25*len(self.greenTickets): 655 | self.Notes[item[0]] = 'red' 656 | elif k < 0.5*len(self.greenTickets): 657 | self.Notes[item[0]] = 'yellow' 658 | elif k < 0.75*len(self.greenTickets): 659 | self.Notes[item[0]] = 'green' 660 | else: 661 | self.Notes[item[0]] = '' 662 | if not self.print_output: 663 | return 664 | print('[collapse=绿票商店]') 665 | for k, v in sorted(self.greenTickets.items(), key=lambda x:x[1], reverse=True): 666 | print('%s:\t%.3f'%(k, v)) 667 | sys.stdout.write('[/collapse]') 668 | 669 | def output_orange(self): 670 | self.orangeTickets = {} 671 | for item, value in Orange.items(): 672 | self.orangeTickets[item] = self.item_value[item] / value 673 | self.orangeNotes = {} 674 | for k, item in enumerate(sorted(self.orangeTickets.items(), key=lambda x:x[1], reverse=True)): 675 | if k < 0.25*len(self.orangeTickets): 676 | self.orangeNotes[item[0]] = 'red' 677 | elif k < 0.5*len(self.orangeTickets): 678 | self.orangeNotes[item[0]] = 'yellow' 679 | elif k < 0.75*len(self.orangeTickets): 680 | self.orangeNotes[item[0]] = 'green' 681 | else: 682 | self.orangeNotes[item[0]] = '' 683 | print('[collapse=橙票商店]') 684 | for k, v in sorted(self.orangeTickets.items(), key=lambda x:x[1], reverse=True): 685 | print('%s:\t%.3f'%(k, v)) 686 | sys.stdout.write('[/collapse]') 687 | 688 | def output_purple(self): 689 | self.purpleTickets = {} 690 | for item, value in Purple.items(): 691 | self.purpleTickets[item] = self.item_value[item] / value 692 | self.purpleNotes = {} 693 | # for k, item in enumerate(sorted(self.purpleTickets.items(), key=lambda x: x[1], reverse=True)): 694 | # if k < 0.25 * len(self.purpleTickets): 695 | # self.purpleNotes[item[0]] = 'red' 696 | # elif k < 0.5 * len(self.orangeTickets): 697 | # self.purpleNotes[item[0]] = 'yellow' 698 | # elif k < 0.75 * len(self.orangeTickets): 699 | # self.purpleNotes[item[0]] = 'green' 700 | # else: 701 | # self.purpleNotes[item[0]] = '' 702 | print('[collapse=紫票商店]') 703 | for k, v in sorted(self.purpleTickets.items(), key=lambda x: x[1], reverse=True): 704 | print('%s:\t%.3f' % (k, v)) 705 | sys.stdout.write('[/collapse]') 706 | 707 | 708 | def output_yellow(self): 709 | self.yellowTickets = {'芯片助剂': self.item_value['芯片助剂'] / Price['芯片助剂']} 710 | for item in self.values[3]['items']: 711 | try: 712 | self.yellowTickets[item['name']] = self.item_value[item['name']] / Price[item['name']] 713 | except: 714 | pass 715 | for k, item in enumerate(sorted(self.yellowTickets.items(), key=lambda x:x[1], reverse=True)): 716 | if k < 0.25*len(self.yellowTickets): 717 | self.Notes[item[0]] = 'red' 718 | elif k < 0.5*len(self.yellowTickets): 719 | self.Notes[item[0]] = 'yellow' 720 | elif k < 0.75*len(self.yellowTickets): 721 | self.Notes[item[0]] = 'green' 722 | else: 723 | self.Notes[item[0]] = '' 724 | if not self.print_output: 725 | return 726 | print('[collapse=黄票商店]') 727 | for k, v in sorted(self.yellowTickets.items(), key=lambda x:x[1], reverse=True): 728 | print('%s:\t%.3f'%(k, v)) 729 | sys.stdout.write('[/collapse]') 730 | 731 | def output_credit(self): 732 | self.creditEffect = dict() 733 | for item, value in Credit.items(): 734 | self.creditEffect[item] = self.item_value[item]/value 735 | 736 | for k, item in enumerate(sorted(self.creditEffect.items(), key=lambda x:x[1], reverse=True)): 737 | if k < 0.25*len(self.creditEffect): 738 | self.Notes[item[0]] = 'red' 739 | elif k < 0.5*len(self.creditEffect): 740 | self.Notes[item[0]] = 'yellow' 741 | elif k < 0.75*len(self.creditEffect): 742 | self.Notes[item[0]] = 'green' 743 | else: 744 | self.Notes[item[0]] = '' 745 | if not self.print_output: 746 | return 747 | print('[collapse=信用商店]') 748 | for item, value in sorted(self.creditEffect.items(), key=lambda x:x[1], reverse=True): 749 | print('%-20s:\t\t%.3f' % (item, value*100)) 750 | # sys.stdout.write('%s>'%item) 751 | sys.stdout.write('[/collapse]') 752 | 753 | def output_effect(self, filter=None): 754 | print('[collapse=关卡效率]') 755 | for k, v in sorted(self.effect.items(), key=lambda x:x[1], reverse=True): 756 | # if v < 0.9: 757 | # break 758 | if filter and filter not in k: 759 | continue 760 | if k[:2] in ['SK', 'AP', 'CE', 'LS', 'PR'] and self.display_main_only: 761 | continue 762 | if 'AF' in k[:2]: 763 | print('[b]%9s:\t%.2f\t(%d 样本)[/b]'%(k, v*100, self.stage_times[k])) 764 | else: 765 | print('%9s:\t%.2f\t(%d 样本)'%(k, v*100, self.stage_times[k])) 766 | sys.stdout.write('[/collapse]') 767 | 768 | def update_droprate_processing(self, stage, item, droprate, mode='add'): 769 | if stage not in self.stage_array: 770 | print('关卡%s被禁用, 材料%s添加失败.'%(stage, item)) 771 | return 772 | if item not in self.item_array: 773 | print('材料%s被禁用, 关卡%s添加失败.'%(item, stage)) 774 | return 775 | stageid = self.stage_dct_rv[stage] 776 | itemid = self.item_dct_rv[item] 777 | if mode == 'add': 778 | self.probs_matrix[stageid][itemid] += droprate 779 | elif mode == 'update': 780 | self.probs_matrix[stageid][itemid] = droprate 781 | else: 782 | print('关卡%s, 材料%s, 模式错误添加失败'%(stage, item)) 783 | 784 | def update_stage_processing(self, stage_name: str, cost: int): 785 | if stage_name not in self.stage_array: 786 | self.stage_array.append(stage_name) 787 | self.stage_dct_rv.update({stage_name: len(self.stage_array)-1}) 788 | self.cost_lst = np.append(self.cost_lst, cost) 789 | else: 790 | self.cost_lst[self.stage_dct_rv[stage_name]] = cost 791 | 792 | def update_droprate(self): 793 | self.update_droprate_processing('S4-6', '龙门币', 3228) 794 | self.update_droprate_processing('S5-2', '龙门币', 2484) 795 | self.update_droprate_processing('S6-4', '龙门币', 2700, 'update') 796 | self.update_droprate_processing('SK-1', '家具零件', 1, 'update') 797 | self.update_droprate_processing('SK-2', '家具零件', 3, 'update') 798 | self.update_droprate_processing('SK-3', '家具零件', 5, 'update') 799 | self.update_droprate_processing('SK-4', '家具零件', 7, 'update') 800 | self.update_droprate_processing('SK-5', '家具零件', 10, 'update') 801 | self.update_droprate_processing('CE-1', '龙门币', 1700, 'update') 802 | self.update_droprate_processing('CE-2', '龙门币', 2800, 'update') 803 | self.update_droprate_processing('CE-3', '龙门币', 4100, 'update') 804 | self.update_droprate_processing('CE-4', '龙门币', 5700, 'update') 805 | self.update_droprate_processing('CE-5', '龙门币', 7500, 'update') 806 | ''' 807 | self.update_droprate_processing('LS-1', '经验', 1600, 'update') 808 | self.update_droprate_processing('LS-2', '经验', 2800, 'update') 809 | self.update_droprate_processing('LS-3', '经验', 3900, 'update') 810 | self.update_droprate_processing('LS-4', '经验', 5900, 'update') 811 | self.update_droprate_processing('LS-5', '经验', 7400, 'update') 812 | ''' 813 | self.update_droprate_processing('AP-5', '采购凭证', 21, 'update') 814 | 815 | self.update_droprate_processing('PR-A-1', '重装芯片', 1/2, 'update') 816 | self.update_droprate_processing('PR-A-1', '医疗芯片', 1/2, 'update') 817 | self.update_droprate_processing('PR-B-1', '狙击芯片', 1/2, 'update') 818 | self.update_droprate_processing('PR-B-1', '术师芯片', 1/2, 'update') 819 | self.update_droprate_processing('PR-C-1', '先锋芯片', 1/2, 'update') 820 | self.update_droprate_processing('PR-C-1', '辅助芯片', 1/2, 'update') 821 | self.update_droprate_processing('PR-D-1', '近卫芯片', 1/2, 'update') 822 | self.update_droprate_processing('PR-D-1', '特种芯片', 1/2, 'update') 823 | self.update_droprate_processing('PR-A-2', '重装芯片组', 1/2, 'update') 824 | self.update_droprate_processing('PR-A-2', '医疗芯片组', 1/2, 'update') 825 | self.update_droprate_processing('PR-B-2', '狙击芯片组', 1/2, 'update') 826 | self.update_droprate_processing('PR-B-2', '术师芯片组', 1/2, 'update') 827 | self.update_droprate_processing('PR-C-2', '先锋芯片组', 1/2, 'update') 828 | self.update_droprate_processing('PR-C-2', '辅助芯片组', 1/2, 'update') 829 | self.update_droprate_processing('PR-D-2', '近卫芯片组', 1/2, 'update') 830 | self.update_droprate_processing('PR-D-2', '特种芯片组', 1/2, 'update') 831 | 832 | for i, stage in enumerate(self.stage_array): 833 | self.update_droprate_processing(stage, '龙门币', self.base_gold/self.everyday_cost*self.cost_lst[i], 'add') 834 | self.update_droprate_processing(stage, '赤金', -self.base_gold/500/self.everyday_cost*self.cost_lst[i], 'add') 835 | self.update_droprate_processing(stage, '经验', self.base_exp/self.everyday_cost*self.cost_lst[i], 'add') 836 | self.update_droprate_processing(stage, '赤金', self.base_MTL_GOLD3/500/self.everyday_cost*self.cost_lst[i], 'add') 837 | 838 | def update_convertion_processing(self, target_item: tuple, cost: int, source_item: dict, extraOutcome: dict): 839 | ''' 840 | target_item: (item, itemCount) 841 | cost: number of 龙门币 842 | source_item: {item: itemCount} 843 | extraOutcome: {outcome: {item: weight}, rate, totalWeight} 844 | ''' 845 | toAppend = dict() 846 | Outcome, rate, totalWeight = extraOutcome 847 | toAppend['costs'] = [{'count':x[1]/target_item[1], 'id':self.item_dct_rv[x[0]], 'name':x[0]} for x in source_item.items()] 848 | toAppend['extraOutcome'] = [{'count': rate, 'id': self.item_dct_rv[x[0]], 'name': x[0], 'weight': x[1]/target_item[1]} for x in Outcome.items()] 849 | toAppend['goldCost'] = cost/target_item[1] 850 | toAppend['id'] = self.item_dct_rv[target_item[0]] 851 | toAppend['name'] = target_item[0] 852 | toAppend['totalWeight'] = totalWeight 853 | self.convertion_rules.append(toAppend) 854 | 855 | def update_convertion(self): 856 | # 考虑 岁过华灯 的影响 857 | if self.SuiGuoHuaDeng: 858 | weight = {self.item_array[item]: dr for item, dr in enumerate(self.probs_matrix[self.stage_dct_rv['岁过华灯']]) if self.item_array[item] != '龙门币'} 859 | self.update_convertion_processing(('龙门币', 1), 1, {'岁过华灯': 1}, (weight, 1/0.18, 1)) 860 | self.update_convertion_processing(('技巧概要·卷3', 1), 0, {'技巧概要·卷2': 3}, ({'技巧概要·卷3':1}, 1, 1)) 861 | self.update_convertion_processing(('技巧概要·卷2', 1), 0, {'技巧概要·卷1': 3}, ({'技巧概要·卷2':1}, 1, 1)) 862 | self.update_convertion_processing(('经验', 200), 0, {'基础作战记录': 1}, ({}, 0, 1)) 863 | self.update_convertion_processing(('经验', 400), 0, {'初级作战记录': 1}, ({}, 0, 1)) 864 | self.update_convertion_processing(('经验', 1000), 0, {'中级作战记录': 1}, ({}, 0, 1)) 865 | self.update_convertion_processing(('经验', 2000), 0, {'高级作战记录': 1}, ({}, 0, 1)) 866 | self.update_convertion_processing(('经验', 400), 0, {'赤金': 1}, ({}, 0, 1)) 867 | self.update_convertion_processing(('家具零件', 4), 200, {'碳': 1}, ({'碳': 1}, 0.5, 1)) 868 | self.update_convertion_processing(('家具零件', 8), 200, {'碳素': 1}, ({'碳素': 1}, 0.5, 1)) 869 | self.update_convertion_processing(('家具零件', 12), 200, {'碳素组': 1}, ({'碳素组': 1}, 0.5, 1)) 870 | self.update_convertion_processing(('重装芯片', 2), 0, {'医疗芯片': 3}, ({'重装芯片': 1, '医疗芯片':1, 871 | '狙击芯片': 1, '术师芯片': 1, '先锋芯片': 1, '辅助芯片': 1, '近卫芯片': 1, '特种芯片': 1}, 0.165/0.18, 8)) 872 | self.update_convertion_processing(('医疗芯片', 2), 0, {'重装芯片': 3}, ({'重装芯片': 1, '医疗芯片':1, 873 | '狙击芯片': 1, '术师芯片': 1, '先锋芯片': 1, '辅助芯片': 1, '近卫芯片': 1, '特种芯片': 1}, 0.165/0.18, 8)) 874 | self.update_convertion_processing(('狙击芯片', 2), 0, {'术师芯片': 3}, ({'重装芯片': 1, '医疗芯片':1, 875 | '狙击芯片': 1, '术师芯片': 1, '先锋芯片': 1, '辅助芯片': 1, '近卫芯片': 1, '特种芯片': 1}, 0.165/0.18, 8)) 876 | self.update_convertion_processing(('术师芯片', 2), 0, {'狙击芯片': 3}, ({'重装芯片': 1, '医疗芯片':1, 877 | '狙击芯片': 1, '术师芯片': 1, '先锋芯片': 1, '辅助芯片': 1, '近卫芯片': 1, '特种芯片': 1}, 0.165/0.18, 8)) 878 | self.update_convertion_processing(('先锋芯片', 2), 0, {'辅助芯片': 3}, ({'重装芯片': 1, '医疗芯片':1, 879 | '狙击芯片': 1, '术师芯片': 1, '先锋芯片': 1, '辅助芯片': 1, '近卫芯片': 1, '特种芯片': 1}, 0.165/0.18, 8)) 880 | self.update_convertion_processing(('辅助芯片', 2), 0, {'先锋芯片': 3}, ({'重装芯片': 1, '医疗芯片':1, 881 | '狙击芯片': 1, '术师芯片': 1, '先锋芯片': 1, '辅助芯片': 1, '近卫芯片': 1, '特种芯片': 1}, 0.165/0.18, 8)) 882 | self.update_convertion_processing(('特种芯片', 2), 0, {'近卫芯片': 3}, ({'重装芯片': 1, '医疗芯片':1, 883 | '狙击芯片': 1, '术师芯片': 1, '先锋芯片': 1, '辅助芯片': 1, '近卫芯片': 1, '特种芯片': 1}, 0.165/0.18, 8)) 884 | self.update_convertion_processing(('近卫芯片', 2), 0, {'特种芯片': 3}, ({'重装芯片': 1, '医疗芯片':1, 885 | '狙击芯片': 1, '术师芯片': 1, '先锋芯片': 1, '辅助芯片': 1, '近卫芯片': 1, '特种芯片': 1}, 0.165/0.18, 8)) 886 | self.update_convertion_processing(('重装芯片组', 2), 0, {'医疗芯片组': 3}, ({'重装芯片组': 1, '医疗芯片组':1, 887 | '狙击芯片组': 1, '术师芯片组': 1, '先锋芯片组': 1, '辅助芯片组': 1, '近卫芯片组': 1, '特种芯片组': 1}, 0.165/0.18, 8)) 888 | self.update_convertion_processing(('医疗芯片组', 2), 0, {'重装芯片组': 3}, ({'重装芯片组': 1, '医疗芯片组':1, 889 | '狙击芯片组': 1, '术师芯片组': 1, '先锋芯片组': 1, '辅助芯片组': 1, '近卫芯片组': 1, '特种芯片组': 1}, 0.165/0.18, 8)) 890 | self.update_convertion_processing(('狙击芯片组', 2), 0, {'术师芯片组': 3}, ({'重装芯片组': 1, '医疗芯片组':1, 891 | '狙击芯片组': 1, '术师芯片组': 1, '先锋芯片组': 1, '辅助芯片组': 1, '近卫芯片组': 1, '特种芯片组': 1}, 0.165/0.18, 8)) 892 | self.update_convertion_processing(('术师芯片组', 2), 0, {'狙击芯片组': 3}, ({'重装芯片组': 1, '医疗芯片组':1, 893 | '狙击芯片组': 1, '术师芯片组': 1, '先锋芯片组': 1, '辅助芯片组': 1, '近卫芯片组': 1, '特种芯片组': 1}, 0.165/0.18, 8)) 894 | self.update_convertion_processing(('先锋芯片组', 2), 0, {'辅助芯片组': 3}, ({'重装芯片组': 1, '医疗芯片组':1, 895 | '狙击芯片组': 1, '术师芯片组': 1, '先锋芯片组': 1, '辅助芯片组': 1, '近卫芯片组': 1, '特种芯片组': 1}, 0.165/0.18, 8)) 896 | self.update_convertion_processing(('辅助芯片组', 2), 0, {'先锋芯片组': 3}, ({'重装芯片组': 1, '医疗芯片组':1, 897 | '狙击芯片组': 1, '术师芯片组': 1, '先锋芯片组': 1, '辅助芯片组': 1, '近卫芯片组': 1, '特种芯片组': 1}, 0.165/0.18, 8)) 898 | self.update_convertion_processing(('特种芯片组', 2), 0, {'近卫芯片组': 3}, ({'重装芯片组': 1, '医疗芯片组':1, 899 | '狙击芯片组': 1, '术师芯片组': 1, '先锋芯片组': 1, '辅助芯片组': 1, '近卫芯片组': 1, '特种芯片组': 1}, 0.165/0.18, 8)) 900 | self.update_convertion_processing(('近卫芯片组', 2), 0, {'特种芯片组': 3}, ({'重装芯片组': 1, '医疗芯片组':1, 901 | '狙击芯片组': 1, '术师芯片组': 1, '先锋芯片组': 1, '辅助芯片组': 1, '近卫芯片组': 1, '特种芯片组': 1}, 0.165/0.18, 8)) 902 | self.update_convertion_processing(('近卫双芯片', 1), 0, {'近卫芯片组': 2, '经验': 1000/3, '采购凭证': 90}, ({}, 0, 1)) 903 | self.update_convertion_processing(('重装双芯片', 1), 0, {'重装芯片组': 2, '经验': 1000/3, '采购凭证': 90}, ({}, 0, 1)) 904 | self.update_convertion_processing(('医疗双芯片', 1), 0, {'医疗芯片组': 2, '经验': 1000/3, '采购凭证': 90}, ({}, 0, 1)) 905 | self.update_convertion_processing(('特种双芯片', 1), 0, {'特种芯片组': 2, '经验': 1000/3, '采购凭证': 90}, ({}, 0, 1)) 906 | self.update_convertion_processing(('辅助双芯片', 1), 0, {'辅助芯片组': 2, '经验': 1000/3, '采购凭证': 90}, ({}, 0, 1)) 907 | self.update_convertion_processing(('术师双芯片', 1), 0, {'术师芯片组': 2, '经验': 1000/3, '采购凭证': 90}, ({}, 0, 1)) 908 | self.update_convertion_processing(('狙击双芯片', 1), 0, {'狙击芯片组': 2, '经验': 1000/3, '采购凭证': 90}, ({}, 0, 1)) 909 | self.update_convertion_processing(('先锋双芯片', 1), 0, {'先锋芯片组': 2, '经验': 1000/3, '采购凭证': 90}, ({}, 0, 1)) 910 | if self.ExpFromBase: 911 | self.update_convertion_processing(('经验', 1000), 0, {'龙门币': 625}, ({}, 0, 1)) 912 | 913 | 914 | def update_stage(self): 915 | self.update_stage_processing('PR-A-1', 18) 916 | self.update_stage_processing('PR-A-2', 36) 917 | self.update_stage_processing('PR-B-1', 18) 918 | self.update_stage_processing('PR-B-2', 36) 919 | self.update_stage_processing('PR-C-1', 18) 920 | self.update_stage_processing('PR-C-2', 36) 921 | self.update_stage_processing('PR-D-1', 18) 922 | self.update_stage_processing('PR-D-2', 36) 923 | self.update_stage_processing('CE-1', 10) 924 | self.update_stage_processing('CE-2', 15) 925 | self.update_stage_processing('CE-3', 20) 926 | self.update_stage_processing('CE-4', 25) 927 | self.update_stage_processing('CE-5', 30) 928 | self.update_stage_processing('LS-1', 10) 929 | self.update_stage_processing('LS-2', 15) 930 | self.update_stage_processing('LS-3', 20) 931 | self.update_stage_processing('LS-4', 25) 932 | self.update_stage_processing('LS-5', 30) 933 | self.update_stage_processing('SK-1', 10) 934 | self.update_stage_processing('SK-2', 15) 935 | self.update_stage_processing('SK-3', 20) 936 | self.update_stage_processing('SK-4', 25) 937 | self.update_stage_processing('SK-5', 30) 938 | self.update_stage_processing('AP-5', 30) 939 | 940 | 941 | 942 | def Cartesian_sum(arr1, arr2): 943 | arr_r = [] 944 | for arr in arr1: 945 | arr_r.append(arr+arr2) 946 | arr_r = np.vstack(arr_r) 947 | return arr_r 948 | 949 | def float2str(x, offset=0.5): 950 | 951 | if x < 1.0: 952 | out = '%.1f'%x 953 | else: 954 | out = '%d'%(int(x+offset)) 955 | return out 956 | 957 | def request_data(url_stats, url_rules, url_items, url_stages, 958 | save_path_stats, save_path_rules, save_path_items, save_path_stages): 959 | """ 960 | To request probability and convertion rules from web resources and store at local. 961 | Args: 962 | url_stats: string. url to the dropping rate stats data. 963 | url_rules: string. url to the composing rules data. 964 | save_path_stats: string. local path for storing the stats data. 965 | save_path_rules: string. local path for storing the composing rules data. 966 | Returns: 967 | material_probs: dictionary. Content of the stats json file. 968 | convertion_rules: dictionary. Content of the rules json file. 969 | """ 970 | headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36'} 971 | try: 972 | os.mkdir(os.path.dirname(save_path_stats)) 973 | except: 974 | pass 975 | try: 976 | os.mkdir(os.path.dirname(save_path_rules)) 977 | except: 978 | pass 979 | try: 980 | os.mkdir(os.path.dirname(save_path_items)) 981 | except: 982 | pass 983 | try: 984 | os.mkdir(os.path.dirname(save_path_stages)) 985 | except: 986 | pass 987 | page_stats = urllib.request.Request(url_stats, headers=headers) 988 | with urllib.request.urlopen(page_stats) as url: 989 | material_probs = json.loads(url.read().decode()) 990 | with open(save_path_stats, 'w') as outfile: 991 | json.dump(material_probs, outfile) 992 | 993 | page_rules = urllib.request.Request(url_rules, headers=headers) 994 | with urllib.request.urlopen(page_rules) as url: 995 | convertion_rules = json.loads(url.read().decode()) 996 | with open(save_path_rules, 'w') as outfile: 997 | json.dump(convertion_rules, outfile) 998 | 999 | page_stats = urllib.request.Request(url_items, headers=headers) 1000 | with urllib.request.urlopen(page_stats) as url: 1001 | item_list = json.loads(url.read().decode()) 1002 | item_list = {x['itemId']: x['name'] for x in item_list} 1003 | with open(save_path_items, 'w') as outfile: 1004 | json.dump(item_list, outfile) 1005 | 1006 | page_stats = urllib.request.Request(url_stages, headers=headers) 1007 | with urllib.request.urlopen(page_stats) as url: 1008 | stage_list = json.loads(url.read().decode()) 1009 | stage_list = {x['stageId']: {'code': x['code'], 'cost': x['apCost']} for x in stage_list} 1010 | with open(save_path_stages, 'w') as outfile: 1011 | json.dump(stage_list, outfile) 1012 | 1013 | return material_probs, convertion_rules, item_list, stage_list 1014 | 1015 | def load_data(path_stats, path_rules, path_items, path_stages): 1016 | """ 1017 | To load stats and rules data from local directories. 1018 | Args: 1019 | path_stats: string. local path to the stats data. 1020 | path_rules: string. local path to the composing rules data. 1021 | Returns: 1022 | material_probs: dictionary. Content of the stats json file. 1023 | convertion_rules: dictionary. Content of the rules json file. 1024 | """ 1025 | with open(path_stats) as json_file: 1026 | material_probs = json.load(json_file) 1027 | with open(path_rules) as json_file: 1028 | convertion_rules = json.load(json_file) 1029 | 1030 | with open(path_items) as json_file: 1031 | items = json.load(json_file) 1032 | with open(path_stages) as json_file: 1033 | stages = json.load(json_file) 1034 | 1035 | return material_probs, convertion_rules, items, stages --------------------------------------------------------------------------------