本尼迪克特象棋(中国象棋):先手胜率78%,原因只在一着
摘要
- 本尼迪克特象棋(中国象棋)把Benedict Chess的规则放到象棋棋盘上:没有吃子,你走动的棋子所攻击到的每一个敌方棋子都会加入你这一方。
- 它没有残局,炮永远不会变弱,也没有和棋:54局引擎对局和6000局随机对局中一局和棋都没有。约28%的合法着法走出去当场就输。
- 先手胜率78%,而象棋里约为55%。这几乎全部来自一种开局:把炮提到第五或第六横线。
- 饼干规则可以修正:黑方可以在第一着之后接管红方的局面,这会把红方逼向四种接近均势的开局。红方是否存在必胜着法尚无定论;13步以内不存在。
Benedict Chess没有吃子。当你走动一枚棋子时,它从落点攻击到的每一枚敌方棋子都会变色并加入你这一方。你通过把对方的王变成自己的来取胜。W. D. Troyka在2002年发表了它,并以倒戈的Benedict Arnold命名。
据我所能查到的,还没有人把这条规则放到象棋棋盘上。The Chess Variant Pages收录了7383种游戏,其中43个象棋棋盘条目和十来个转化类条目是互不相交的两组;Ludii的2330种游戏和Fairy-Stockfish的变体列表也是同样的结论。差一点的那些值得点名,因为它们大多只差一个关键点。Desertion Chess靠走到棋子旁边而不是攻击它来转化,并且保留吃子。Andernach翻转的是吃子方而不是被吃方。Cleopatra Chess就是Troyka自己的规则,只不过限定在单一棋种上。而象棋自己的翻子类游戏,暗棋和揭棋,是把棋子翻过来显示它是什么,这和改变它归谁所有完全是两回事。
象棋里有隔着炮架吃子的炮,有锁在九点九宫里的将帅,还有过不了楚河汉界的象,所以这次移植注定不可能是机械照搬。它逼出了四个没有默认答案的设计决策。
然后我做了一个引擎,来看看结果是否公平,结论是不公平。先手方胜率78%,而普通象棋约为55%。这几乎全部归结于第一着就能走出的一步炮,这比一个本身就彻底失衡的游戏要好修得多。
规则
走一枚棋子。它从落点攻击到的每一枚敌方棋子都加入你这一方。
有一点要早点注意:静止的攻击不起作用。只有走动的那枚棋子才会转化,所以一枚已经瞄着某物的车必须再走一步才能拿下它。威胁只能通过走动制造,绝不能靠等待。
来下一盘
双方都由你操作,背后没有引擎。它运行的是本文每张图所校验的同一套规则内核,所以它不会允许文中说是非法的着法。
棋盘下方的计数就是本文后面反复提到的那个数字。它从零开始,而且不会停在零。
这对象棋意味着什么
永远没有残局。 全部32枚棋子整局都留在棋盘上。没有简化,也没有兑子,而且残局库在原理上就不可能,因为状态空间从不收缩。象棋残局理论,也就是象棋理论的大部分,完全无法迁移。
炮不再贬值。 象棋的炮需要炮架才能吃子,所以随着棋盘变空它会变弱。这里棋盘永远不会变空,第80着的炮和第3着的炮一样危险。拟合出来的数值也印证了这点:炮的取值是657,而象棋的价值表通常给到450左右,已经接近车的900,足以改变你使用它们的方式。
士和象不再防守任何东西。 它们的存在是为了防止被吃,而这里没有吃子。它们仍然能挡线、能当炮架,所以并非毫无用处,但它们原本被设计出来要做的事全都没了。
对局很短,而且没人和棋。 中位数29步,而象棋是80到100步。在最强设置下的54局中没有一局和棋,6000局完全随机走法的对局里也没有一局,这是更强的版本:不是说高手在这里回避和棋,而是局面除了分出胜负无路可走。一个没有子力可兑、没有残局可磨的游戏,不可能后继无力。
约28%的合法着法走出去当场就输。 这是下面这些对局共1696步的平均值,值得说精确一点,因为平均值并不代表典型局面:中位局面里有10%的着法会输,而均值是被少数极其尖锐的局面拉高的。均值还在攀升,从一局前五分之一的24%升到最后五分之一的37%。不会出现的,是一个可以从容出子的平静开局阶段。即便是前五分之一,平均也有四分之一的着法走出去当场就输。
设计这个游戏
将帅仍然不得照面。 象棋禁止双方的将帅在同一直线上中间无子,我保留了这一条。另一种选择是把白脸将设为取胜条件,听上去更好,但会崩:在Benedict规则下只有走动的那枚棋子算数,所以打通这条线并不算赢,结果就是将帅互相照面而对局继续,直到有人把将沿着这条线挪一步来宣称胜利。
保留这条禁令不花任何代价,却产生了象棋所没有的一样东西。被牵制在将帅同线上的棋子无法被强行清除,因为这里没有任何东西能清除任何东西,而转化它也无法解放它,因为转化是原地变色。你可以赢下这枚棋子,却仍然无法移动它。只有将帅走离这条线才能解放它,所以这个牵制持续多久,完全取决于牵制方把自己的将帅留在那里多久。
士和象绑定于它们所处的区域,而不是主人的区域。 一枚被转化的士位于敌方九宫内,若按主人绑定的规则它就永远被冻在那里,那是一枚死子和一条无聊的规则。绑定到它所处的九宫,它就还能继续走。从起始摆放来看两种解读完全一致,因为每枚士本来就站在自己的九宫里,所以这种推广不花代价,还把一枚死子变成了进攻子力。
兵卒绑定于它的主人,这是相反的判断。 兵卒的前进方向必须跟随当前拥有它的一方,否则被转化的兵卒会永远朝着背离自己一方的方向前进。把这两条弄反,就是那种会悄无声息毁掉游戏的bug。
和棋需要一个进展计时。 由于没有吃子,几乎每一着都是可逆的。仅靠三次重复局面不够,所以计时只在两个不可逆事件上重置:一次转化,或一次兵卒的移动。
测试它
现有引擎都下不了这个。Pikafish、Fairy-Stockfish和我自己的迷雾引擎都写死了吃子规则,而Fairy-Stockfish唯一的转化机制(flipEnclosedPieces)翻转的是被落子包围的棋子,黑白棋式的,那是另一条规则。
于是:一个用Rust写的alpha-beta引擎,带置换表、主要变例搜索、后期着法缩减,以及针对转化的静态搜索。我没有照搬象棋的子力价值,而是用2500局自我对弈的结果做逻辑回归拟合,在一对一的对抗赛中它胜过了我手工选定的数值。
我不打算引用拟合出的具体数字。早先的草稿引用了,并把它们当作棋子价值的测量结果来解读,而这超出了在8000个相关局面上做逻辑回归所能支撑的范围:早前用四分之一数据做的拟合,有几个系数的符号后来反了过来。留存下来的是它所认同的排序,即士和象在这里几乎一文不值,而这一点不需要回归也能得出,因为它直接源于这里没有什么需要防守。
规则内核是链式验证的,这很重要,因为后来出问题的都在测量环节而不在规则上。一个JavaScript原型与我本来就在用的象棋库elephantops做了差分测试,覆盖720947次棋子几何比较,零分歧。Rust引擎在1.13亿个局面内完全复现了该内核的着法计数。一个TypeScript移植版同时复现了这两者。
有三个结果在后续的每一次改动中都保持不变,因为它们都不依赖引擎的判断:
| 测试 | 结果 |
|---|---|
| 随机对随机,6000局 | 先手方 50.1%,0和棋 |
| 从起始摆放做无缩减证明搜索,208亿节点 | 13步以内不存在必胜着法 |
| 合法着法中当场告负的比例 | 均值28%,中位数10%,覆盖1696步 |
这三项都不会随引擎变化而变动,所以我比相信胜率更相信它们。
这个引擎强到足以评判一个游戏吗? 它每秒搜索约160万个局面,几秒钟能到搜索深度8或9。远不及成熟的国际象棋引擎。它也不需要那么强。
上面三个结果完全不依赖它下得多好。一个是随机着法对照,一个是证明,一个是合法着法的计数。这个证明值得说精确一点,因为普通搜索做不出证明:这个引擎使用后期着法缩减,对靠后的着法搜索得更浅,所以一次没找到胜法的普通搜索,只说明它没有看遍所有地方。关掉缩减和静态搜索,并在将死阈值上以是/否的方式提问,才能真正证明,这就是上面13步的含义。而78%这个数字,是按这里真正重要的性质来检验的,即引擎变强时它会不会变。它几乎不变:每着30万节点时是77.8%,200万节点时是75.4%,相差七倍,而抽样误差本身就有好几个百分点。
跨引擎强度的稳定性是我信任的检验,但单靠它还不够。这项测量的早期版本用六步随机开局库来制造变化,得到52.7%,并且在跨越同样十倍范围的三种引擎强度下都保持不变。它之所以稳定,是因为开局库正好耗掉了被测量的那一先手:六步随机走法在任何一方引擎出手之前就把优势扔掉了,所以不管底下的游戏是什么样,结果都会漂向均势。一个坏掉的温度计在任何房间都读出室温。上面的78%不使用开局库,而是靠评估值抖动来制造变化。
更多算力能买到什么是有界而且相当清楚的。位棋盘和更好的着法排序能达到搜索深度12到14,那是我在谈论深度战术或真正的开局理论之前想达到的水平。学习式评估是昂贵的选项,而且多半是错的选项:在其他变体上的两次尝试都在还没赶上它们本要取代的手工评估之前就饱和了,两次失败都不是钱的问题。
所以本文描述的是俱乐部水平下的这个游戏。我保留下来的论断,都是在任何强度下都成立的。
引擎、内核和测试框架共几千行Rust和TypeScript代码,放在GitHub上:github.com/brianhliou/benedict-xiangqi,同时附有那54局对局和完整的开局表。本文的每一个数字都出自cargo run。
一步炮决定一切
先手方胜率 78%。这是从起始摆放、不使用开局库、双方轮流执先的在线策略测量:每着30万节点时,红先得分80.5%,黑先75.0%,各100局;200万节点时为82.5%和68.3%,各60局。两个方向在两种预算下都远高于均势,所以优势跟着先手走而不是跟着颜色走,这才使它成为关于游戏本身而非关于我代码的事实。在较高预算下红方看起来确实是这对搭配里更好的一半,但60局的误差约有十二个百分点,所以我暂时不会从中读出什么。
然后我分别测量了红方全部42种合法的第一着,诊断结果的形态变了。
全部42种合法首着,各24局,按红方随后的得分排序。
| 着法 | 红方得分 | 着法 | 红方得分 | 着法 | 红方得分 | ||
|---|---|---|---|---|---|---|---|
| c1a3 | 0.0% | h1g3 | 25.0% | a4a5 | 41.7% | ||
| e1e2 | 0.0% | a1a3 | 27.1% | g4g5 | 43.8% | ||
| g1i3 | 0.0% | b3b2 | 27.1% | b3b4 | 45.8% | ||
| b3a3 | 4.2% | h3h2 | 29.2% | b3b7 | 50.0% | ||
| b3c3 | 8.3% | b3d3 | 29.2% | d1e2 | 54.2% | ||
| h1i3 | 12.5% | i4i5 | 29.2% | e4e5 | 54.2% | ||
| h3f3 | 16.7% | b3f3 | 33.3% | a1a2 | 58.3% | ||
| b3g3 | 18.8% | b1a3 | 35.4% | h3h7 | 60.4% | ||
| h3c3 | 20.8% | c1e3 | 35.4% | h3h4 | 60.4% | ||
| i1i2 | 20.8% | b3e3 | 35.4% | b3b6 | 70.8% | ||
| h3g3 | 22.9% | c4c5 | 35.4% | f1e2 | 72.9% | ||
| i1i3 | 25.0% | h3e3 | 37.5% | h3h5 | 79.2% | ||
| h3i3 | 25.0% | h3d3 | 39.6% | b3b5 | 87.5% | ||
| g1e3 | 25.0% | b1c3 | 41.7% | h3h6 | 91.7% |
最好的两着是同一个思路:把炮提到第五或第六横线。得分为零的三着分别是走象、马走边路,以及将帅沿中路上一步。
红方的第一着价值可以从零一直到92%,42着里有3着24局全输。所以78%并不是「在这个游戏里一先值78%」。它是「引擎每次都能找到那唯一的强力开局」。
象棋的炮需要它与目标之间正好有一枚棋子。黑方的起始局面白送了这枚棋子,而且位置正好。这个威胁之所以存在,是因为象棋的起始摆放恰好落在Benedict规则能加以利用的地方。
它下过的每一局
最强设置下的全部54局,未经筛选。先手方赢了其中46局,输掉的那8局才是值得打开看的。
对局结束不是因为有人出错。它们结束,是因为一方再也没有不会输的着法可走,而这类着法的数量在棋盘上出现任何可见变化之前,已经连涨了二十步。
用饼干规则让它公平
那42种开局之间的落差正是让这件事还有救的原因,而修法在别的游戏里早已存在。
饼干规则的运作方式,就像两个小孩分蛋糕:一人切,另一人挑。红方走第一着。黑方随后选择是继续执黑,还是改为接管红方的局面。这个选项改变了红方的优化目标,因为当黑方可以直接拿走时,走出最强的开局就变得毫无意义。
于是红方被推向最接近均势的那一着,42着里有4着落在那里。其中两着是炮拒绝走向自己的最佳点位,另外两着是棋盘上最平静的出子着法。
炮向前一步,远未到能造成杀伤的第五路。
炮一路推到底,此刻兑子,放弃了原有的持续威胁。
仕出动,腾空d1。将帅同线从第一着起就已生效。
中兵:唯一一步不算失误的安静开动着法。
被迫走其中之一,对局就会落在50%附近。不是靠把优势削弱下去,而是靠剥夺红方使用它的能力,这是一种比听上去更干净的修法。Hex在任何棋盘尺寸下都是可证明的先手必胜,却在全世界都有竞技比赛,完全靠的就是交换规则。
诚实的保留是样本量。那四个数字各来自24局,宽到我不会把它们互相排名,又窄到足以说明从0%到83%的落差是真实的。在合适的样本量下确认其中之一确实保持在50%附近,是尚待完成的工作。
饼干规则在不触动锐度的前提下修正了公平性。当场告负着法的比例是规则的属性,而不是谁占优的属性,所以它完全不变。它让较量变得均势。它并没有让较量变得平静,而这是否是人们愿意下的游戏,是另一个我无法从胜率里回答的问题。
目前的状态
作为竞技游戏还不能发布。先手四局赢三局,没有哪个等级分天梯撑得住。
这一点值得和一个听上去相似的论断区分开。不公平不等于不能下:反棋(自杀棋)是已被证明的先手必胜,而且每天都有人在比赛,因为那个证明花了五年、八台机器,走的是人类找不到的变例。Hex在任何棋盘尺寸下都是已被证明的先手必胜,靠交换规则照样在下。先手优势本身并不会杀死一个游戏。
这里不同的是深度。这78%建立在一句话就能说清的一着上,把炮提到第五横线,而引擎每一次都能找到它。一个被证明却够不着的胜法是猎奇。一个能背下来的胜法就是这盘游戏本身。
饼干规则之外还有两种未经测试的修法。把将帅标记而不是转化,让防守方有一着来应对,可以直接钝化炮的威胁,而转化那枚进攻棋子本身就是一个合法的应手。或者改动起始摆放中中路兵卒的位置,因为这个威胁之所以存在,只是因为黑方的卒正好站在炮需要炮架的地方。
无论如何都留存下来的是这个设计。在象棋棋盘上做转化,得到的是一个没有残局、炮永不贬值、防守子力一文不值、被转化的士永远滞留在敌阵后方的游戏。这一点在测量的每一个版本中都成立,因为规则是我用四种不同方式验证过的那一部分。
下一步是一先规则:内核里二十行代码,再加上把已有的测试框架跑一遍。
尚未解决的问题是红方是否有必胜着法。 上面的一切都是胜率,那是关于两个特定引擎的陈述。它底下的问题是:在双方最佳着法下这个游戏是否是先手必胜,而这个问题的答案不依赖于任何东西下得多好。
我手上有的是一个下界:13步以内不存在必胜着法,用208亿节点、约半小时证明。这排除了廉价的胜法,而一个中位长度29步的游戏,也不过被它探索了一半出头。
有两点让这件事比看上去更难,有一点让它更容易。子力守恒,所以状态空间从不收缩,这意味着没有残局数据库可建,正向搜索也没有东西可以在中间会合。逆向分析,也就是每一个已被解决的国际象棋残局背后的技术,在原理上就不可用,而不只是昂贵。策略窃取,即从对称起始得到超弱解的常用手法,同样不适用:棋子是移动而不是累积,所以先手方无法随便走一着然后把它丢掉。有帮助的是对局很短。中位数是29步,54局引擎对局和6000局随机对局中都没有和棋,所以这棵树很浅而且终局清晰,这正是证明数搜索擅长的形态。
下一级是14,而杠杆不在于更多硬件。上面的证明是按红方的42种首着切分的,它几乎完美地并行,恰恰是因为答案是否定的:既然没有必胜着法,就没有哪个分支会截断另一个,所以同时搜索它们不会有任何损失。这在一台笔记本上跑出了13。切到两步深会得到约1700个独立任务,这正是需要集群的形态;而证明数搜索,把力气花在证明树最狭窄的部分而不是均匀地往深里搜,还完全没有实现。最后这一点不是假想:反棋(自杀棋)就是这么被解决的。Mark Watkins在八台十六核机器上跑了五年多的证明数搜索,才证明1.e3是白方获胜,这既是这里需要的技术,也是关于把这件事做完要付出多少的一个中肯警告。
如果有人拿出一个弱解,甚至靠我没想到的论证拿出一个超弱解,那也就顺带解决了饼干规则的问题,因为已被证明的先手必胜正是交换规则被发明出来对付的情形。Hex在任何棋盘尺寸下都是已被证明的先手必胜,照样在竞技比赛。