炉石2019年荣誉室的消息公布后,很多人都在问荣誉室最优选择策略的问题。刚学了Python的基本语法,想试试手。因为对列表、字典这些基础类型的方法不太熟悉,写的时候遇到了好多问题,好在解决了大部分,目前所写的不是很健全,程序逻辑上有漏洞。如果有意向学习Python,可以自己动手写写这类项目,提高效果还是比较明显的。
返尘规则:
官网截图规则解释:
共9张非同名卡进了荣誉室,每套牌中可佩带1张同名传说品质卡,2张同名史诗\稀有\普通 品质卡。如果一张卡拥有金色与白色两种,则优先返还金色,其次白色。返还值为卡片的合成尘数,非分解尘数。本次9张卡中包括:2张非同名传说卡,2张非同名史诗卡,3张非同名稀有卡,2张非同名普通卡。
卡牌合成\分解尘数规则:
|
白色 |
金色 |
||
合成 |
分解 |
合成 |
分解 |
|
普通品质 |
40 |
5 |
400 |
50 |
稀有品质 |
100 |
20 |
800 |
100 |
史诗品质 |
400 |
100 |
1600 |
400 |
传说品质 |
1600 |
400 |
3200 |
1600 |
因为荣誉室返还的合成所需尘数,所以合成某卡就相当于白嫖该卡,原则上荣誉室只让玩家赚了所合成卡的分解尘数。但有特殊情况,当用户有某类卡的金色卡时,会发生赚不到分解尘数的情况(因为荣誉室返还的优先级:金色卡>白色卡)。
在上述逻辑下,如果玩家已经拥有了某卡,想通过荣誉室得到更高的利益,就相当于期望: 一顿操作后的返尘数 > 不操作返尘数。要达成这个条件,等同于 一顿操作后所合成卡的分解尘数 > 已有卡的合成尘数 。 按照这个条件,我们看下上面的 “卡牌合成\分解尘数规则” , 发现 只有当卡牌品质为普通品质时,满足这个要求(50-40=10,单卡可以赚10尘),其他品质下,二者是相等的关系。
由此,我们可以得到结论:(返还优先级:金色卡 > 白色卡 > 没有卡)
合成任何 返还优先级 比 你所拥有 高的卡都不会亏。
如果你拥有某张卡的白色卡,只有该卡的品质为 普通 时才需要合成金色卡,稀有\史诗\传说品质的都不会赚。
下面的代码没有过多加入上述分析过程,是逻辑上的遍历,把存在的所有方案都算了一遍,求出每个方案的最终收益尘数
共分解成了5个方法。(这个项目中的方法、变量的命名不规范,仅供参考学习,需注意此问题)
operation_card(oper, color, card) # 输入合成或分解 某种颜色的卡片,返回此项操作影响的尘数
fand(num) # 输入受返还影响的卡片总数,返回 所有方案的集合
fand_num(list_str, card) # 输入所有方案的集合、卡片的品质,返回该方案的尘数
color_sim(color) # 输入英文颜色,返回中文颜色(这个方法无关紧要,为了练习加的)
user_have(num, color, card, numx) # 输入用户拥有的某品质卡的总数量,以及卡片颜色、受返还影响的卡片总数 打印方案及尘数信息 (暂不支持用户同时拥有某个品质两种颜色的卡,这里需要再修改一下)
from functools import reduce
def operation_card(oper, color, card):
if color == 'ordinary':
if card == 'ordinary':
if oper == 'add':
return -40
elif oper == 'reduce':
return 5
elif card == 'rare':
if oper == 'add':
return -100
elif oper == 'reduce':
return 20
elif card == 'epic':
if oper == 'add':
return -400
elif oper == 'reduce':
return 100
elif card == 'legend':
if oper == 'add':
return -1600
elif oper == 'reduce':
return 400
else:
return print('请输入正确的品质!')
elif color == 'golden':
if card == 'ordinary':
if oper == 'add':
return -400
elif oper == 'reduce':
return 50
elif card == 'rare':
if oper == 'add':
return -400
elif oper == 'reduce':
return 100
elif card == 'epic':
if oper == 'add':
return -1600
elif oper == 'reduce':
return 400
elif card == 'legend':
if oper == 'add':
return -3200
elif oper == 'reduce':
return 1600
else:
return print('请输入正确的品质!')
else:
return print('请输入正确的颜色!')
def fand(num):
list_all = []
list_f = ['无', '白卡', '金卡']
for i in range(num):
list_all.append(list_f) # list_all 表示 本次荣誉室 总卡数 存在的情况,list格式
def funk(list1, list2):
List = []
for i in list1:
if i != '无':
for j in list2:
if j != '无':
List.append(i + ',' + j)
return List
List_m = reduce(funk, list_all) # 内含字符串格式
List_l = [L.split(sep=',') for L in reduce(funk, list_all)] # 内含列表格式
Kyy = []
for list in List_m:
Ky = {}
for i in range(num):
if Ky.get(list[i * 3:i * 3 + 2]):
Ky[list[i * 3:i * 3 + 2]] = Ky[list[i * 3:i * 3 + 2]] + 1
else:
Ky[list[i * 3:i * 3 + 2]] = 1
Kyy.append(Ky)
return Kyy
def fand_num(list_str, card):
number = []
for vk in list_str:
a = 0
b = 0
if vk.get('白卡'):
if vk.get('白卡') > 0:
a = vk.get('白卡') * operation_card('add', 'ordinary', card)
else:
a = vk.get('白卡') * operation_card('reduce', 'ordinary', card)
if vk.get('金卡'):
if vk.get('金卡') > 0:
b = vk.get('金卡') * operation_card('add', 'golden', card)
else:
b = vk.get('金卡') * operation_card('reduce', 'golden', card)
number.append(a + b)
return number
def color_sim(color):
if color == 'ordinary':
color_cn = '白卡'
elif color == 'golden':
color_cn = '金卡'
return color_cn
def user_have(num, color, card, numx):
# 荣誉室返尘数
if num >= numx:
honor_u = numx * -operation_card('add', color, card) # 用户原有返尘数
else:
honor_u = num * -operation_card('add', color, card)
sum_u = num * operation_card('reduce', color, card) # 用户原有尘数
print('现有卡分解后尘数:%s ,荣誉室可返还尘数:%s' % (sum_u, honor_u))
color_cn = color_sim(color)
card_ol = fand(num) # 方案具体情况
card_uh = {color_cn: num}
honor_f = []
# 方案纠偏
for card_uo in card_ol:
# print('循环%s次 \n %s' % (card_ol.index(card_uo), card_uo))
if card_uo.get(color_cn):
# card_on[card_on.index(card_uo)][color_cn] = card_uo.get(color_cn) - card_uh.get(color_cn)
honor_f.append(card_uo.get(color_cn) * -operation_card('add', color, card))
# print('第%s次 honor_f append success \n %s' % (card_ol.index(card_uo), honor_f))
card_uo[color_cn] = card_uo.get(color_cn) - card_uh.get(color_cn)
else:
honor_f.append(0)
pay = fand_num(card_ol, card)
# 拥有+返尘数
sum_user_ade = sum_u + honor_u
# 付出+方案返尘数
sum_f_ade = [pay[i] + honor_f[i] for i in range(len(honor_f))]
print('你所拥有情况:%s张%s%s' % (num, color_cn, card))
print('原有方案价值尘数:', sum_user_ade)
print('各种方案可得尘数:', sum_f_ade)
print('方案细节:', fand(num))
aaa = []
bb = sum_f_ade
cc = fand(num)
for i in range(len(bb)):
aaa.append([cc[i], bb[i]])
aaa.sort(key=lambda d: d[1], reverse=True)
for i in range(len(aaa)):
print(aaa[i])
user_have(5, 'ordinary', 'ordinary', 4) # 用户拥有5张白色普通品质的卡,此次荣誉室加了4张此品质的卡(包含同名卡)
'''
各字段输入内容
oper: add/reduce
color: ordinary/golden
card: ordinary/rare/epic/legend
'''
输出结果:
现有卡分解后尘数:25 ,荣誉室可返还尘数:160
你所拥有情况:5张白卡ordinary
原有方案价值尘数: 185
各种方案可得尘数: [200, -245, -245, -690, -245, -690, -690, -1135, -245, -690, -690, -1135, -690, -1135, -1135, -1580, -245, -690, -690, -1135, -690, -1135, -1135, -1580, -690, -1135, -1135, -1580, -1135, -1580, -1580, -2000]
方案细节: [{'白卡': 5}, {'白卡': 4, '金卡': 1}, {'白卡': 4, '金卡': 1}, {'白卡': 3, '金卡': 2}, {'白卡': 4, '金卡': 1}, {'白卡': 3, '金卡': 2}, {'白卡': 3, '金卡': 2}, {'白卡': 2, '金卡': 3}, {'白卡': 4, '金卡': 1}, {'白卡': 3, '金卡': 2}, {'白卡': 3, '金卡': 2}, {'白卡': 2, '金卡': 3}, {'白卡': 3, '金卡': 2}, {'白卡': 2, '金卡': 3}, {'白卡': 2, '金卡': 3}, {'白卡': 1, '金卡': 4}, {'金卡': 1, '白卡': 4}, {'金卡': 2, '白卡': 3}, {'金卡': 2, '白卡': 3}, {'金卡': 3, '白卡': 2}, {'金卡': 2, '白卡': 3}, {'金卡': 3, '白卡': 2}, {'金卡': 3, '白卡': 2}, {'金卡': 4, '白卡': 1}, {'金卡': 2, '白卡': 3}, {'金卡': 3, '白卡': 2}, {'金卡': 3, '白卡': 2}, {'金卡': 4, '白卡': 1}, {'金卡': 3, '白卡': 2}, {'金卡': 4, '白卡': 1}, {'金卡': 4, '白卡': 1}, {'金卡': 5}]
[{'白卡': 5}, 200]
[{'白卡': 4, '金卡': 1}, -245]
[{'白卡': 4, '金卡': 1}, -245]
[{'白卡': 4, '金卡': 1}, -245]
[{'白卡': 4, '金卡': 1}, -245]
[{'金卡': 1, '白卡': 4}, -245]
[{'白卡': 3, '金卡': 2}, -690]
[{'白卡': 3, '金卡': 2}, -690]
[{'白卡': 3, '金卡': 2}, -690]
[{'白卡': 3, '金卡': 2}, -690]
[{'白卡': 3, '金卡': 2}, -690]
[{'白卡': 3, '金卡': 2}, -690]
[{'金卡': 2, '白卡': 3}, -690]
[{'金卡': 2, '白卡': 3}, -690]
[{'金卡': 2, '白卡': 3}, -690]
[{'金卡': 2, '白卡': 3}, -690]
[{'白卡': 2, '金卡': 3}, -1135]
[{'白卡': 2, '金卡': 3}, -1135]
[{'白卡': 2, '金卡': 3}, -1135]
[{'白卡': 2, '金卡': 3}, -1135]
[{'金卡': 3, '白卡': 2}, -1135]
[{'金卡': 3, '白卡': 2}, -1135]
[{'金卡': 3, '白卡': 2}, -1135]
[{'金卡': 3, '白卡': 2}, -1135]
[{'金卡': 3, '白卡': 2}, -1135]
[{'金卡': 3, '白卡': 2}, -1135]
[{'白卡': 1, '金卡': 4}, -1580]
[{'金卡': 4, '白卡': 1}, -1580]
[{'金卡': 4, '白卡': 1}, -1580]
[{'金卡': 4, '白卡': 1}, -1580]
[{'金卡': 4, '白卡': 1}, -1580]
[{'金卡': 5}, -2000]
写的比较复杂,有很大的优化空间,记录下来自己的成长。喜欢玩炉石的朋友可以拿这个小项目当做学习Python的兴趣点开始入手。还有很多可以完善的地方,比如用户的策略倾向可能是不分解金卡,这样就不能简单的直接按照尘数计算收益率了;比如用户只有3000尘,在已有资源下的最优策略方案有哪些,这样的话最后一步输出方案时需要做个条件筛选,等等。这次原本是打算一天写完,赶快往下学习爬虫、数据所需的三方模块,结果中间因为排列组合、列表字典字符串的内置方法、三重循环时把数据类型搞蒙 这些种种原因查了3天才写了这个简单的项目,有很多不足,好在主流程能跑通,接下来要加紧进度了!