炉石机器人 AI 部分解释

Written on December 27, 2014 View on GitHub

炉石升级很久了,回去试试,发现原来的机器人用不了了。 简单调了一下可以用的,但是依然觉得乱糟糟的,于是就重构了。

代码整理中。

Program.cs

嵌入器的入口,依然使用 Mono.Cecil,暂时没什么好思路。

HearthrockUnity.cs

一个 MonoBehaviour,被作为 GameObject 嵌入到 Hearthstone 的 Unity bject 中,最主要的目的,就是游戏内显示一个小按钮。。。

HearthrockEngine.cs

包装了大部分和 Hearthstone 交互所需的行为,以及 Hearthrock 状态维护所需的逻辑。

HearthrockRobot.cs

机器人的决策部分。

现在比较矛盾的部分,就是 HearthrockRobot,我很希望能够使用动态修改的方式实现,无论是使用脚本语言,更换 dll,还是利用 Remoting。 除了更换 dll 以外,其他两者都是需要我自己对类进行包装了,但是卡片的 Entity 属性和状态十分复杂。 更换 dll 就需要使用 AppDomain,坑爹的是 Unity 使用的这个 Mono 版本 AppDomain.CreateDomain 必然失败,是个已知 bug 。。。 所以,暂时先还是不动态修改了,但是 HearthrockRobot 和 HearthrockEngine 之间尽量保证使用基本类型,如 int 和 string。

评估了一下现在的状况,炉石的牌越来越多,特效和法术配合,甚至赌牌都会影响战局,牌面的复杂度分析不亚于象棋。 而且由于一部分信息是隐藏的,无法像象棋那么做直观的牌面评估。 反正这东西不会做大,所以干脆放弃了。 力求在只使用基本牌、普通特效牌(如嘲讽、额外一张牌、队友攻击+1)、无目标法术(如。。银币)的情况下,能在天梯上保持50%的胜率。 实际上已经做到了,而且最高打到了天梯15级,一般稳定在18-19。

出牌顺序:

0、检测是否必要出硬币牌(出了硬币牌,是否能正好打出一张牌) 1、法术牌

理想出牌方式

理想出牌逻辑:

定义三种选牌方式:

  1. 尽量多出牌
  2. 尽量出大型嘲讽牌(针对危急情况)
  3. 尽量出高伤冲锋牌(针对对方危急情况)

  4. 使用方案 3 从池中选牌(将硬币考虑进去),估算伤害,判断能否斩杀,如果可以选用该方案。(奥秘、法强、攻击 +1 等可能会影响结果,不考虑)
  5. 计算对方总伤害能否在下一轮斩杀自己,如果可以,使用 方案 2。
  6. 使用方案 1
  7. 根据选择的方案,对选牌进行排序,一些牌(如飞刀杂耍者)应该拥有高优先级,其他牌按综合价值从小到大排序。
  8. 打出第一张牌,并且重新使用 使用方案 3、方案 1 估算。

理想进攻逻辑:

定义威胁值计算方式:(由于肯定没有理论最优值,所以差不多就得了)

  1. 通用方式,威胁值 = 攻击力 - 生命值。如果有风怒,攻击值翻倍,如果有圣盾,生命值翻倍。
  2. 对于拥有非战吼、非亡语特效的单位,威胁值给予不同修改,如食尸鬼。
  3. 有亡语特效的单位,威胁值适当降低。
  4. 对于一些已知常见牌、双方方英雄,再做额外调整。

定义价值计算方式。 价值跟威胁值相近,主要是帮助自己选择合适的随从进攻,跟威胁值区别如下。 圣盾加成为对方最低功绩值。 嘲讽有额外加成,比如 3。

根据威胁值,将对方小兵分类,并且按照威胁值高到低排序。

  1. 对方嘲讽小兵
  2. 对方非嘲讽高威胁小兵
  3. 对方非嘲讽威胁为正的小兵

我方小兵 价值排序

再定义小组进攻逻辑 如 组A 进攻 组B 组B选取一个随从,组A判断能否低价斩杀。 不能斩杀,则以威胁值低到高攻击。

然后 我方其他小兵 -> 敌方嘲讽小兵 如果不能斩杀对方英雄 我方其他小兵 -> 对方高威胁值小兵 如果不能斩杀对方英雄,并且对面下一轮斩杀我 我方其他小兵 -> 对方高威胁值小兵,对方非嘲讽威胁为正的小兵 如果能斩杀,或者已无高威胁值小兵 我方其他小兵 -> 对方英雄

理想综合逻辑:

第一步:循环 { 对方如果有奥秘,尝试对英雄攻击(本轮一次) 对方如果有奥秘,尝试对嘲讽单位攻击(本轮一次) 选牌 } 第二步:循环 攻击。