本文共三个部分:
- 我用python玩炉石传说(1)-----炉石卡牌相关度分析的手动打分器
- 我用python玩炉石传说(2)-----炉石卡牌套牌爬取器及自动分析卡牌相关度
- 我用python玩炉石传说(3)-----炉石卡牌套牌自动构建算法
引言:
前面两部分已经完成了卡牌之间的相关度分析,现在需要完成我们的最终目的,构建一个套牌deck。
最初,想用最简单的方法,即选择相关度最高的来完成构建,例如:首先选择情势反转,最相关的是阿兰纳斯蛛后,最选择与蛛后最相关的,地狱烈焰,然后依次进行,直至选满30张卡牌。
但实际发现这样构建出的套牌,虽然看似相关度高,但实际非常分散与自闭(由于缺少尘与卡牌,所以并没有完全按选出的卡牌实测)。表现出非常卡手,或是combo往往难以达成,提前拆散,可以想象为自行车链条,每个节点高度相关,成链式。但如果某张卡牌不得不出于解场,除掉后,相关性就中断了。也就是虽然combo很多,但combo与combo之间的耦合度很低,套牌构建不完善。
所以需要一种能发现最佳套牌的算法。需要两个‘器件’,迭代器以及打分算法
autobuild.py
一,卡组记录类
class BDeck:
cardinfo = None
corrmat = None
def __init__(self, dicklist: list, cardnum: int, score: float):
self.dicklist = dicklist
self._cardnum = cardnum
self._score = score
def __len__(self):
return len(self.dicklist)
def __lt__(self, other):
return self.score < other.score
def appid(self, idn: int):
self._score = self._score + self._newscore(idn)
self._cardnum = self._cardnum + self.cardinfo.id2cardmaxnum(idn)
self.dicklist.append(idn)
def _newscore(self, idn):
newscore = 0.0
for n, i in enumerate(reversed(self.dicklist), 1):
s = self.corrmat.get_rmatrix[idn, i]
newscore += s / n
return newscore
类中记录卡组的卡牌,以及卡组的得分,卡牌数量。
func appid:为添加新卡进入卡组时,自动计算其总得分
分数计算方法改进:不只是计算新加入的卡牌与其之前的卡牌相关度得分(4-5),还要计算其与之前所有加入卡牌的相关度累加得分(1-5, 2-5,,,),其中会对其卡牌距离做一定的衰减,例如 1-5会除于其相距距离5,2-5除4。可以理解成,我们希望新加入的卡牌,能与之前的卡牌有一定的相关耦合关系,成为一个体系,而不是又节外生枝发展出另一个体系(例如,本来是ZOOLOCK的,但发展到后来又出现了handlock卡牌)。但是,我们知道一个卡组里不可能全部都与一张卡牌相关,那样耦合的过于紧密,类似于全部聚类在了一起,那样只要1卡牌出完,那整个体系就崩溃了,所以加入衰减使卡牌加入顺序相隔越远的,所受影响会越小。(但实际上最后实验效果还是出现了多分支)
二,遍历所有卡牌组合的递归算法
def recursion_trave(deck: BDeck, spreed, deep):
if deep < 1:
spreed = 20
elif deep == 1:
spreed = 15
elif deep == 2:
spreed = 10
elif deep == 3:
spreed = 5
elif deep == 4:
spreed = 5
elif 5 <= deep <= 6:
spreed = 5
elif 7 < deep <= 15:
spreed = 3
lastcard = deck.dicklist[-1]
scope = RM.get_rmatrix[lastcard, :]
scope[deck.dicklist] = 0
scopesort = np.argsort(scope)[::-1]
maxscoredeck = deck
for i in range(spreed):
if scope[scopesort[i]] > 0:
idn = scopesort[i]
else:
break
nextdeck = deepcopy(deck)
nextdeck.appid(idn)
if nextdeck.cardnum < 30:
nextdeck = recursion_trave(nextdeck, spreed, deep)
maxscoredeck = max(maxscoredeck, nextdeck)
return maxscoredeck
选定一张核心牌1,然后遍历其所有与之相关的卡牌(2,3,4,5,6),进一步,再分别遍历与(1-6)相关的(1-6-7,1-6-8,1-6-9.。。。),无限递归进行下去,直至加入卡牌数量达到30张。就这样遍历了基本所有可能性,然后总结出得分最高的卡组。
代码链接:https://github.com/GladosAI/hearthstone-card-correlation-analys
实验效果
莫瑞甘的灵界
烈焰小鬼
虚空行者
怪盗天才
残酷集结
双生小鬼
巨型小鬼
小鬼狱火
拉法姆的阴谋
恶魔法阵
至暗时刻
伊瑟拉
恶狼大法师
凯恩·血蹄
人偶大师多里安
邪能领主贝图格
情势反转
阿兰纳丝蛛后(默认是除了传说,其他都带两张,自己缺卡没试过,估计不行,算法还要改进,有条件的朋友可以试试)
(我个人觉得 换掉伊瑟拉 为一个效果不错的亡语或巨人 可能还能玩。恶狼大法师还是太卡,也换掉。把卡牌风格向zoo上靠,可能还救得活,毕竟反转+人偶大师/邪能 也能铺场)
这是算法自己生成的,有个问题,在恶魔法阵前本是恶魔zoo术的,后来由于至暗时刻与恶魔法阵与阴谋算是combo,导致后面节外生枝为另一个体系反转术。这里使用的是第二章里的相关度数据,来自400个构建好的卡组,估计使用自己手动打分会比较好,因为更加全面客观。