翻子是一次决策加一次掷骰
暗棋里一半的着法是翻开一枚背面朝下的棋子。一步棋,两件事:选哪枚翻,以及翻出来是什么。揭棋的揭子和翻翻棋的翻子是同一个问题换了棋子;全文用暗棋做例子,因为它的随机性最纯粹。
照搬国际象棋的复盘会给整步棋的胜率波动打分。翻开角落那枚棋,翻出对方的将,复盘就记你一个漏着。可那是一枚坏棋子,不是一个坏决策。
这就是 Mistboard 的暗棋复盘不显示厘兵损失的原因:它没法和翻出的棋子分开,放在那些可以分开的数字旁边,就只是噪音。
西洋双陆棋几十年前就解决了这件事
西洋双陆棋的软件会把每次掷骰和平均掷骰作比较,报告一个剔除运气后的结果,所以一份战报可以告诉你:你下得更好,但你输了。GnuBG 和 eXtreme Gammon 都这么做。扑克里的 all-in EV 是同一个思路。
国际象棋从没造过这些东西,因为它没有骰子。暗棋是象棋家族里带骰子的一员,却继承了国际象棋的工具,而那些工具里没有运气这一栏。
剩下棋子里的平均一枚
暗棋的随机性是数得清的。双方都看得到哪些棋子还背面朝下,整副棋的构成也是公开的,所以任何一次翻子,你都能列出那个格子上可能翻出的每一枚棋。这让诚实的基准变得可以计算:
对这个格子可能是的每一枚棋:
把那枚棋放到格子下
走这步翻子
评估局面
按数量加权,取平均这个平均值,就是你的决策在掷骰之前的价值。每次翻子三个数字:
| 每次翻子 | 含义 |
|---|---|
| played | 你所选翻子的平均价值 |
| best | 当前最佳着法的同一种平均 |
| realized | 实际翻出的棋子带来的结果 |
决策损失 decision loss = best - played (实力,恒 >= 0)
运气 luck = realized - played (骰子,带符号)运气为零,恰好就是翻出剩下棋子里的平均一枚。这是由构造保证的事实,不是引擎的看法。
开头那次翻子,逐一枚举
本文开头那盘棋的第 6 个半回合:我翻开 g3 上的棋子。此时还有二十七枚背面朝下,共十二种身份,每一种都通向一盘不同的棋。
| g3 这枚棋可能是什么 | 数量 | 黑方胜率 |
|---|---|---|
| 黑卒 | ×5 | 82% |
| 红卒 | ×4 | 46% |
| 红车 | ×2 | 45% |
| 红象 | ×2 | 44% |
| 红士 | ×2 | 43% |
| 红炮 | ×2 | 41% |
| 黑马 | ×2 | 34% |
| 黑车 | ×2 | 31% |
| 黑象 | ×1 | 29% |
| 黑士 | ×2 | 25% |
| 黑炮 | ×2 | 23% |
| 黑将 | ×1 | 13% |
同一次翻子的价值从 13%(翻出我自己的将,深陷争夺之地)到 82%(我自己的卒,在那里既安全又有用)不等。加权平均是 45%。这个数字才是决策本身,准确率打分打的就是它。
高亮的那一行就是实际翻出的结果。实际 82,决策 45,运气 +37,而这份运气没有一点是我挣来的。
引擎对自己的骰子有偏心
最省事的捷径,是直接问引擎一步翻子值多少,再把差值叫作运气。我们的揭棋引擎演示了为什么不行:它高估自己的揭子,下出贪婪、赌博式的着法。而对一组身份已经确定的固定局面取平均,让概率节点完全不进搜索,偏心就无处安身。
决定你执哪色的那次翻子
开局第一次翻子决定你执哪种颜色:翻出什么色,你就执什么色。这次翻子的反事实会改变你自己的整支军队,所以这套拆分把"我分到哪一边"也计成运气。乍听之下不太对劲,想上十来秒就完全对了。
复盘画出什么
优势图多了一条线。实线是实际发生的对局。虚线是同一盘棋,每次翻子都按平均的那一枚计分。两次翻子之间,两条线同步移动,因为普通着法对两个版本的影响完全一样。每到一次翻子,差距就恰好按那次翻子的运气变化,所以到终局时,两线的差距就是整盘棋的运气总和。
这也是为什么图里的虚线一路朝一个方向走,而实线上下翻腾。我的运气一次又一次落在同一侧,差距只增不减。只看决策的话,引擎几乎全程占优;一旦虚线认定这盘棋照理已经完胜,它就顶在最上沿不动了。
着法列表把这份拆分标到每一步上。每次翻子都带一个骰子标记,写着它的运气,就在评估值旁边;决策则单独打分:下图第 3 步就是那次 +37% 的翻子,虽然它帮我赢了棋,作为选择却被标为可疑。

而准确率只按决策数字打分,翻得走运不会加分,翻得倒霉也不会扣分。这盘棋的总结和故事本身完全一致:引擎下得干净,我则不然,而结果却说了反话。

证据
开头那场胜利:对引擎的 156 个半回合,图把我供了出来。第 6 个半回合,那次值 45% 的翻子翻出了 82%。整盘棋里没有任何一个决策能把指针拨得这么远。
总账:我的翻子+76,引擎的 −12;翻子决策上我送掉 74 个百分点,引擎送掉 0。虚线里我大半盘都在输。实线里我赢了。棋子推翻了棋艺。整盘棋在 Mistboard 上公开,下方可以回放。
反过来也一样。在我输掉的另一盘棋里,光是第 19 个半回合的一次翻子,就烧掉了 34 个百分点的胜率。那盘棋我的决策平平。旧式复盘会把那次翻子记为致败漏着。新的复盘把它记为:胜负在此刻被一件不由你选择的事定了下来。
五十二盘棋的证据
我们把这套拆分跑遍了站上最近 52 盘人类对 Misty 的暗棋。
| 52 盘人类对 Misty 的对局 | 数值 |
|---|---|
| 人类战绩 | 14 胜 33 负 5 和 |
| 胜局中偏向人类的净运气 | 平均 +28 个百分点 |
| 负局中偏向人类的净运气 | 平均 −9 个百分点 |
引擎更强,赢它通常都借了棋子的力。如果你赢过它,现在复盘会告诉你借了多少。
揭棋掷的是另一种骰子
揭棋用同一套办法,只是抽取的范围不同。揭棋的揭子从你自己剩余的暗子里抽,所以你知道颜色,不知道身份。暗棋的棋子对双方都是暗的,连颜色也是。范围不同,算法相同,斗兽棋的翻棋版本(翻翻棋)是第三家。它们每一个都有那条虚线。
写给实现者
三个选择让这些数字保持诚实。第一,反事实不能改变剩下棋子的构成。把翻开的格子从卒改标成炮,你就悄悄往棋局里加了一枚炮、拿走了一枚卒,局面因此偏移两枚棋子的分量,平均值也被抬高。所以实现里用的是交换:让反事实身份和一个确实藏着这枚棋的背面格子对调,隐藏棋子的集合始终恰好等于这盘棋的集合。
第二,一把有界的尺子。一切都用翻子一方视角的胜率来计:它可以在整盘棋上累加;直接终局的翻子恰好计 100、50 或 0;而一步翻进杀局的棋本来就没有厘兵值可言。搜索预算按节点数而非时间计,同一盘棋在任何机器上打出的分都一样。
第三,故意往少里算。决策上限只考虑引擎的第一选择,被引擎排在第二的更好着法会被漏掉,所以决策损失只会被低估。复盘可能漏报一个失误,但绝不会凭空捏造一个。
数字到哪里为止
这些胜率出自我们的暗棋引擎在固定搜索预算下的评估,而这个引擎同时也是这些对局里的对手,所以它自己的翻子被打成近乎完美,部分原因不过是它在认同自己的选择。看到"引擎零损失"时,请记住这一点。人类一侧的数字没有这个问题。
还有一条诚实的边界:逐点扣除运气,等于把胜率当成线性的,而它并不是线性的。方向可信。小数点后第二位不可信。
拿你自己的棋试试
在 Mistboard 打开任何一盘下完的暗棋、揭棋或翻翻棋,你自己的,或观战页上任何人的,然后请求电脑分析。运气数字会逐翻子出现在着法列表里,虚线则画出棋子们本该给你的那盘棋。
有时它承认你是被抢了。有时它把你的胜利收走。在对我旧棋的一轮扫描里,这两件事它都做了。