炉石兄弟 DIY 汇总
2021.3.27 新版智能SIM转移,CardDB_cardIDEnum.cs生成脚本
|
|
为炉石兄弟增加祈求机制 3月15日
祈求机制的改法,我们是模仿着兄弟原有的青玉魔像(JadeGolem)的机制来修改,所以我们很多添加函数的位置都选择在JadeGolem旁边,话不多说,这里就直接贴代码了
我们在Hrtprozis.cs文件中
搜索代码public int anzEnemyJadeGolem = 0;
在下面添加两行
|
|
搜索代码
|
|
在下面添加一行
|
|
搜索代码
|
|
在下面添加我们的自定义函数updateInvokedInfo
|
|
然后修改silverfish_HB.cs文件 在
|
|
的下一行添加调用我们所写的的自定义函数updateInvokedInfo
|
|
最后修改Playfield.cs文件
搜索代码
|
|
在下面添加两行
|
|
搜索代码
|
|
在下面添加两行
|
|
搜索代码
|
|
在下面添加两行
|
|
搜索代码
|
|
修改为
|
|
搜索函数
|
|
在这个函数上面添加getGalakrondInvoke函数
|
|
还有调试相关修改,如果你不会调试,可以不进行修改 在BoardTester.cs文件
搜索代码
|
|
在下面添加两行
|
|
搜索
|
|
在上面添加代码
|
|
搜索
|
|
在下一行添加
|
|
到此修改结束,如果有卡要进行祈求则使用public void getGalakrondInvoke(bool own)
函数
如有不懂的地方,或者我写的不明白的地方请评论留言。
具体的文件位置可以看我另一篇文章。
炉石兄弟切换模式功能修复 3月20日
炉石发布会结束之后,兄弟的切换模式功能坏了 调试之后发现,问题主要存在于Option枚举被更新
解决方案 在主程序中替换新版Option(Triton.Game.Mapping.Option) 然后把Triton.Bot.Logic.Bots.DefaultBot.DefaultBot中对应的Option的值也改过去,因为就修改枚举,调用的Option值不会变化。 要修改的两个Option分别是 IN_WILD_MODE = 199 IN_RANKED_PLAY_MODE = 160
两种解决办法 1.直接用DnSpy修改IL代码(注意:直接用DnSpy修改代码会编译不通过) 2.用ILSpy反编译之后将代码复制到DnSpy中(原因好像是DnSpy的内置ILSpy版本比较老)
附:新版Option(2020-03-18)
|
|
深入探究炉石兄弟发现、抉择机制(第一篇:完美修复龙蹄的灾难选择) 3月25日
这是深入探究炉石兄弟发现、抉择机制的第一篇:完美修复龙蹄的灾难选择 先来看看龙蹄这张卡的牌面描述
那这个灾难究竟是怎么样的呢?我在网络上找了一张实战的图
可以发现这就是类似于抉择一样的选择卡牌之后使用对应的功能,关键代码如下
首先,通过调用makeChoice()
函数来确定要执行的动作,然后使用一个switch
语句根据返回的值选择相应的操作
case 0
:是选中间的一张牌case 1
:是选最左边的一张牌case 2
:是选最右边的一张牌
|
|
再来看看 makeChoice() 相关的代码
首先检查dirtychoice
变量的值,根据卡牌的属性(如是否为“发现”或“抉择”卡牌)设置choiceMode
。然后,根据当前时间和其他条件,调整dirtychoice
的值以决定最终的选择。特别是,通过交换dirtychoice
值0和1的逻辑,来调整选择的卡牌顺序。
|
|
再来看看 ChooseOneClickRight() 函数
在TritonHs.ChooseOneClickRight()
函数中,我们从右侧选择卡牌,这是通过获取所有可选卡牌的列表并选择列表末尾的卡牌来实现的,符合函数名称的直观理解。
|
|
最后,对于龙蹄这样四张牌的选择,我对原有的选择逻辑进行了调整,以支持不仅仅是三张卡的选择,而是可以根据实际的卡牌数量动态选择。我的思路是直接调用点击卡牌方法,并且我决定去掉"内部函数0转成1,把1转成0,到外部调用的时反常识的顺序(012对应中左右)“这样的操作 于是我直接把内部函数的
|
|
直接删掉了,并且学着TritonHs.ChooseOneClickRight()函数来编写外部调用,来替换原来的switch语句
|
|
原本以为一切顺利,直到我发现兄弟使用了抉择卡牌就会报错。
问题表现为:
- 内部逻辑显示选择左侧卡牌,兄弟却执行的是选择了右侧卡牌。
- 内部逻辑显示选择右侧卡牌,兄弟就直接报错了。
经过仔细分析,我发现了问题的根源。问题出在了我们之前未曾注意到的代码分支上,这一分支负责处理抉择卡牌的延迟选择:
|
|
是的,问题就在于前面我们一直没有注意的第二个分支,他所做的事情是用于抉择卡牌的延迟,当抉择时,dirtychoice
就传入此函数时就已经不为 0,表示已处理,且抉择选项的编号不是从0开始的,而是从1开始,即1代表左侧卡牌,2代表右侧卡牌。因为抉择卡牌只有两个选项,而按照原先的逻辑,返回1时程序错误地尝试选择第二张卡,返回2时则尝试选择第三张卡,从而导致错误。
为解决这个问题,我进行了一番调整。我重写了卡牌选择的逻辑,以确保程序能够正确处理抉择和发现机制:
|
|
通过这种方法,我们能够确保当dirtychoice
为0或1时,程序调用原有的函数进行选择;而对于其他值,则进行特殊处理,以区分是通过发现机制还是抉择机制进行的选择。
当然,只是修改了这个之后,还是会发现兄弟还是不会智能的选择卡牌,但是如果强制让其选择第四张牌已经不会报错了。 这个只是我们修复炉石兄弟发现、抉择机制的一个小小的铺垫,实战中还需要进一步的修改。
敬请期待 第二篇:如何更完美的获取发现卡牌的来源(目前兄弟的抉择必须是由兄弟自己打出才能正常的选择,如果你在选牌的界面才打开兄弟则就会提示:没有获得卡牌数据,这对于想要追求完美的我来说不能忍!) 第三篇:如何添加智能选牌数据库和修复类型识别问题
炉石新机制:休眠,流放 4月11日
休眠:双方玩家都无法触及。(感谢吧主) 流放:在手牌中的最左或最右侧使用时触发的额外效果。
最近有点忙,话不多说直接挂代码吧
Minion.cs中还有几处赋值需要新增,可以学习lifesteal进行增加
在silverfish_HB.cs的getMinions函数加入对dormant数据的读取
|
|
SimTemplate.cs中新增三个函数
|
|
这里解释一下,第一个onOutcast代表法术牌的流放事件 第二个onOutcast代表随从牌的流放事件,类似于战吼 onDormantEndsTrigger指代随从唤醒事件。
在Playfield.cs中的
|
|
函数下搜索
|
|
在这一行之下添加
|
|
搜索
|
|
函数下搜索
|
|
在这一行之下添加
|
|
搜索
|
|
函数下搜索
|
|
在这一行之下添加
|
|
至此添加结束,接下来是我写的几张SIM Sim_BT_004.cs
|
|
Sim_BT_009.cs
|
|
Sim_BT_121.cs
|
|
Sim_BT_127.cs
|
|
Sim_BT_211.cs
|
|
Sim_BT_305.cs
|
|
Sim_BT_934.cs
|
|
2020-05-16 记录对炉石兄弟的修复
今天刚到家,前几天就看到群里面闹得沸沸腾腾,大概是因为炉石使用mono2.0后而且导致了兄弟大面积不可用,本来以为是比较麻烦的问题,结果没想到二十几分钟就解决了,但是由于现在局势紧张,也确实不方便透露具体内容,所以我只能从从技术的角度大致的说一下解决办法
首先是由于更新Mono.dll导致的偏移更新。 mono.dll -> mono-2.0-bdwgc.dll 还有相应的偏移需要更新,但是这里发现有个偏移地址是找不着的,但是经过研究似乎兄弟也没用到这个地址。
只修复上面那个还会有问题,经过调试可以定位到报错的位置,利用CE里面的结构体分析,可以快速的得到新的结构体偏移大小。修改后,测试可用。
最后是自己的一点感想 不希望看到留言邮箱让我发一份文件
- 我希望对炉石兄弟更多的是一种技术上的研究而并非是当做一个工具,当然这个只是对于在我博客上学习的人来说的,对于大部分来说那肯定还是一个挂机刷金币的工具,就我自己而言研究炉石兄弟还是给自己带来蛮多的乐趣的,我希望大家也能体会到这种乐趣。
- 不要对大神产生依赖性,就像是大家期待的吧主修复,或者说贴吧里哪一位大神来修复,我认为等别人修复使用这肯定不是一个长久之计,除非你愿意掏钱到淘宝上买服务,只要是白嫖,那肯定要做好哪一天不能用的准备。与其等别人修复,还不如尝试着自己动手,我这里给出一个时间数据,我用19年10月左右的那个版本,从头到尾修复可用,差不多花费了三天的时间,这个时间比我想象中的要短了很多,我给出这个数据的目的是为了告诉大家,其实找到一个老版本修复一下并不是什么难事,起码没有想象中的那么难,现在贴吧里,各种博客里也充满了兄弟的资料,现在研究比起早期研究兄弟的人简单太多了,只要你肯花心思花时间去学习。由于一些个人原因,接下来的两三个月里,我对兄弟的研究肯定要停止一段时间了。
- 这个博客的不是为了炉石兄弟而开设的,是作为一个个人博客的形象来呈现的,之所以现在的内容都关于炉石兄弟,因为这确实是我前段时间花了很大心思研究的东西,而之后我会分享自己其他方面的编程内容,炉石兄弟作为一个让自己入门C#的工具,其实到这里已经完成了我当时接触它时的使命了。
分享几个自用的用于整理卡牌数据的Python脚本 6月13日
修复换行问题,详情请见评论区
生成卡牌相关文件
|
|
对于炉石兄弟策略编写的一些感悟 7月30日
1. 关于惩罚
我看到很多策略的编写者,包括我刚入门的时候,喜欢用惩罚来调整兄弟出牌,因为当时我认为兄弟的AI算法就是一个简单的BFS搜索 + 剪枝,只会考虑当前场面最优解。 但现在发现其实兄弟并没有这么蠢,他是考虑了本回合 + 下一回合的操作(只要设置合理),这样前瞻的思路其实完全够用。所以我认为惩罚的作用应该是用于调整大于两回合,兄弟预料不到的前瞻操作。 比如:
- 休眠随从的一些特效。
- 一些卡牌为打出一些Combo而留牌。
- 为了赚取更大场面优势而留牌(比如图腾潮涌,有图腾时直接打出是对场面有益的,但是为了更好的场面所以要通过惩罚留牌)。 那么惩罚该怎么写呢?下面是我的一些感想,希望能给大家提供一定的帮助。 之前看到弄的风风火火的破冰和火焰结界,但现在都没有看到一种合理的解决方法,这是为什么呢? 我思考之后发现,很多人用惩罚去调整,反而效果适得其反。原因就是惩罚像是教小孩子的时候你对他施暴,而策略就是合理的教学,教给他怎么样才是对的。 比如:火焰结界现在流行的版本添加的位置都是错误的,都是和猎人奥秘爆炸陷阱放在同一个地方,这个就属于模拟特效的问题,火焰结界是随从攻击后触发,而爆炸陷阱是攻击前触发,这两个放在一起,问题就出现了,兄弟认为用任意一个随从去攻击效果是一样的,反正都是无法造成伤害,而不是我们一般的思路,用攻击最高的随从去攻击。 还有就是通过惩罚的一些弊端,比如你写惩罚,低血量的时候使用某个有治疗效果的卡牌,返回的是负数的惩罚值。其实返回负数的惩罚值就违背了惩罚的概念。当时这样写的时候只考虑到了低血量的时候使用可以快速的回血,符合我们平常打牌的思维,但是你没有想到的是,兄弟会想办法去构造这种低血量来为了得到这个负数的惩罚(比如火球术打脸),当然这种惩罚如果数额写小一点那还无所谓,因为会被策略中所调整,但是如果数额较大,比如30、50这种程度,那就非常不好了。 所以我推荐惩罚值的编写最好是反常的思路,比如你正常思路中是低血量使用回血牌,而在惩罚值的编写中应当是高血量不使用回血牌,给一个正数的惩罚值,让兄弟知道这样是错误的,我认为这样才是正常的惩罚使用方法。 当然这也还是有一些问题,我还是更加推荐使用策略中血量低于一定的血线则给出一定低的评分更好一些。
2. 关于策略
这里的策略指的是behavior文件夹中的策略文件,这些策略大多用来给场面一个合理的评分。 那么有些兄弟就会说了,我的兄弟打出伏笔操作了,又不能通过惩罚来调整,那该怎么办呢? 我这里有两种方法:
- 检查SIM是否编写正确,是否按照真实情况去模拟了
- 调整策略中的对战场的评分,比如要加强留牌,那么就给手牌数量的权重调大,如果要加强场面,那就给单个随从的价值调大。 确定SIM的正确性是非常重要的,包括早期兄弟官方写的卡牌也是错误频出,问题就在于没有测试,我认为写一张卡牌首先要保障其语法的正确性,再要保证其模拟的正确性,这才是一张合理正确的卡牌。而出牌速度的问题也是因为模拟错误所导致的,正是因为模拟错误从而导致兄弟认为场面和模拟的不一致,而重新计算。而这个场面模拟是很严格的,就连随从的位置顺序都很重要,比如亡语:召唤一个XXX随从,这样的卡牌的召唤位置一定要是m.zonepos - 1,才是正确的模拟,包括利用p.ownMinion.Count的都是不正确的,甚至有些随从战吼召唤是在随从的一左一右的,这种位置关系也一定要考虑。否则重新计算的时间是非常难熬的。 但是有些随机性的问题是难以模拟的,比如抽一张牌,按一下图腾召唤技能,这样的操作下一步是完全未知的。这种牌是兄弟非常难把控的,原因就在于兄弟只能固定一种随机操作而围绕这种随机的操作的固定结果而计算出的定性结果,这样持续下去兄弟把这一回合的操作都计算完了,结果开始一操作就发现操作结果与模拟的不符合,然后又去重新计算。所以为什么兄弟不适合打弃牌术,我认为大概也是这个原因吧,这个问题来自于兄弟本身的算法架构,也很难修改。 所以,盲目的追求操作速度其实意义没那么大,操作并没有那么长时间,真正长的时间应该是在大场面的计算上,而计算的问题正如我上面所说,应该要尽量写对结果可预料的卡牌编写正常的SIM,而对于具有随机性的卡牌也应该要考虑多种情况分类讨论。最简单的就是对斩杀的判定。
3. 关于_settings.txt
其中的maxwide我想说明一下,这个参数表明的是计算的深度,也就是数值越大,计算的越深入,我认为如果随机性强的卡组,比如弃牌术,应该把这个数字调低一些,因为基于错误的随机模拟上的大量计算是没有意义的。而如果是随机性弱的卡组,比如奥秘法等,这个数字可以适当的调高。这个原因呢,仔细品味我这篇文章,就自然知道了。如果有疑问的可以在评论区提出,欢迎大家指出我的错误,一起讨论学习!