Benedict Chess 沒有吃子。當你移動一枚棋子,它從落點所攻擊到的每一枚敵方棋子都會變色並加入你這一方。把敵方的王變色就算贏。W. D. Troyka 在 2002 年發表這個玩法,並以陣前易幟的 Benedict Arnold 為其命名。

就我能查到的資料,還沒有人把這條規則放到象棋盤上。Chess Variant Pages 收錄了 7,383 種遊戲,其中 43 個使用象棋棋盤的條目和十幾個變色類條目是互不相交的兩組;Ludii 的 2,330 種遊戲與 Fairy-Stockfish 的變體清單也是同樣的結論。幾個擦身而過的例子值得一提,因為多數都只差一個關鍵環節。Desertion Chess 是靠走到棋子旁邊來變色,而不是靠攻擊它,而且保留吃子。Andernach 翻轉的是吃子方而不是被吃方。Cleopatra Chess 則是 Troyka 自己的規則,但限定只對單一棋子生效。至於象棋本身的翻子遊戲,暗棋與揭棋,是把棋子翻過來揭示它是什麼,這和改變它屬於誰完全是兩回事。

象棋有隔著炮架吃子的炮、鎖在九宮九個點內的將帥,還有不能過楚河漢界的象,所以這個移植從一開始就不可能是機械式的。它逼出了四個沒有預設答案的設計決定。

接著我做了一個引擎來看看結果是否公平,答案是不公平。先行方贏下 78% 的對局,而一般象棋大約是 55%。這幾乎全都歸結於第一著就能走出的某一步炮,而這比一個本質上就失衡的遊戲要好修正得多。

規則

移動一枚棋子。它從落點所攻擊到的每一枚敵方棋子都會加入你這一方。

紅方走棋楚 河 漢 界
1 / 2

有件事要早點注意:既有的攻擊線什麼作用都沒有。只有移動的那枚棋子會造成變色,所以一支已經瞄住某枚棋子的車必須再走一著才能拿下它。威脅只能靠走子製造,等待永遠沒用。

試玩

雙方都由你操作,背後沒有引擎。它執行的是本文每一張圖都拿來對照檢查的同一套規則核心,所以它不可能允許本文說是不合法的著法。

楚 河 漢 界

棋盤下方的那個計數,是本文後面會一再回頭談的數字。它從零開始,而且不會一直待在零。

這對象棋造成了什麼影響

永遠沒有殘局。全部 32 枚棋子整局都留在盤上。沒有簡化,也沒有兌子,而殘局庫在原理上就不可能存在,因為狀態空間永遠不會縮小。象棋殘局理論,也就是象棋理論的大部分,完全無法轉移過來。

炮不再走弱。象棋的炮需要炮架才能吃子,所以棋盤越空它越弱。這裡棋盤永遠不會變空,第 80 著的炮和第 3 著的炮一樣兇。擬合出來的數值也印證了這點:炮算出來是 657,而象棋子力表通常把它放在 450 上下,這已經接近車的 900,足以改變你使用它們的方式。

士和象不再防守任何東西。它們的存在是為了防止被吃,而這裡沒有吃子。它們仍然能擋線、當炮架,所以不算全無用處,但它們原本被設計要做的事全都消失了。

對局很短,而且沒有人和棋。中位數 29 著,而象棋是 80 到 100 著。在最強設定下的 54 局裡一局和棋都沒有,完全隨機走子的 6,000 局裡也沒有出現和棋,而後者是更強的版本:不是說好手在這裡會避開和棋,而是局面除了走向勝負之外無處可去。沒有子可兌、也沒有殘局可磨的遊戲,不可能慢慢耗到沒力。

大約 28% 的合法著法會立刻輸掉。這是下面那些對局共 1,696 著的平均值,而且值得說精確一點,因為平均值並不代表典型局面:中位局面只有 10% 的著法會輸,平均值是由少數極為尖銳的局面拉高的。平均值也會攀升,從一局前五分之一的 24% 升到最後五分之一的 37%。真正不存在的是一個可以安穩布局的開局階段。就連前五分之一,平均也有四分之一的著法會當場輸掉。

設計這個遊戲

將帥依然不得照面。象棋禁止兩將處於同一直線且中間無子,我保留了這條。另一種做法是把白臉將設成勝利條件,聽起來更好,但會壞掉:在 Benedict 規則下只有「移動」的那枚棋子算數,所以把中間的子讓開並不構成勝利,結果就是兩將互相照面而對局繼續進行,直到有人把將沿著那條直線走一步來宣告勝利。

保留這個禁令不花任何代價,卻產生出象棋所沒有的一樣東西。被牽制在將帥直線上的棋子沒辦法用武力除掉,因為這裡什麼都不能除掉;把它變色也解不開,因為變色是原地換色。你可以贏得那枚棋子,卻依然動不了它。只有將帥自己走離那條線才能解放它,所以牽制會持續到牽制方把自己的將帥移開為止。

士和象綁定於它所站的區域,而不是擁有者的區域。一枚變色後的士會待在敵方九宮裡,若採用擁有者綁定的規則,它就永遠凍結在那裡,成為一枚死子和一條無趣的規則。綁定於它所站的九宮,它就還能繼續下。從起始擺法來看兩種解讀完全一致,因為每一枚士本來就站在自家九宮裡,所以這個一般化不花任何代價,還把一枚死子變成攻擊子力。

卒兵綁定於擁有者,這是相反的判斷。卒兵的前進方向必須跟隨現在的擁有者,否則變色後的卒兵會永遠朝著自己這一方的反方向前進。把這兩條搞反,就是那種會悄悄毀掉遊戲的臭蟲。

和棋需要一個進展計時。沒有吃子,幾乎每一著都是可逆的。單靠三次重複局面不夠,所以計時只在兩種不可逆事件時重置:發生變色,或走動卒兵。

測試它

沒有現成的引擎能下這個。Pikafish、Fairy-Stockfish 和我自己的迷霧引擎都內建了吃子規則,而 Fairy-Stockfish 唯一的變色機制(flipEnclosedPieces)翻轉的是被「落子」圍住的棋子,黑白棋那種方式,那是另一條規則。

所以:一個 Rust 寫的 alpha-beta 引擎,帶置換表、主要變例搜尋、後期著法縮減,以及針對變色的靜態搜尋。我沒有直接套用象棋的子力值,而是用 2,500 局自我對戰的結果做邏輯迴歸擬合出來,這組數值在正面對戰中打贏了我手工挑選的那組。

我不打算引用擬合出來的數字。早一版的草稿引用了,而且把它們當成棋子價值的量測結果來讀,那超出了一個對 8,000 個彼此相關局面所做的邏輯迴歸所能支撐的範圍:先前用四分之一資料做的擬合,有好幾個係數的正負號後來反轉了。留下來的是它所認同的那個排序,也就是士和象在這裡幾乎一文不值,而這一點根本不需要迴歸,因為既然沒有什麼要防守的,結論自然如此。

規則核心是用一條驗證鏈檢驗的,這很重要,因為後來出問題的地方都在量測而不在規則。一個 JavaScript 原型針對我本來就在用的象棋函式庫 elephantops 做了差異測試,跨 720,947 次棋子幾何比對,零分歧。Rust 引擎在 1.13 億個局面之內完全重現該核心的著法計數。一個 TypeScript 移植版重現了兩者。

有三個結果在後續每一次改動中都站得住,因為它們都不依賴引擎的判斷:

測試 結果
隨機走子對隨機走子,6,000 局 先行方 50.1%,0 局和棋
從起始擺法出發的無縮減證明搜尋,208 億個節點 13 著之內無必勝著法
當場輸掉的合法著法占比 平均 28%,中位數 10%,涵蓋 1,696 著

這三項在引擎改變時都不會動,這就是我比勝率更信任它們的原因。

這個引擎強到足以評判一個遊戲嗎?它每秒搜尋約 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 萬節點時,紅先各 100 局得分 80.5%,黑先 75.0%;200 萬節點時各 60 局,分別是 82.5% 和 68.3%。兩個方向在兩種預算下都遠高於五成,所以優勢跟著手一走,而不是跟著顏色走,這就使它成為關於這個遊戲的事實,而不是關於我程式碼的事實。在較高預算下紅方看起來確實是這組配對中較好的一半,但 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 種裡有三種直接輸掉全部 24 局。所以那 78% 並不是「在這個遊戲裡一手先值 78%」。而是「引擎總是找到那唯一的強力開局」。

開始楚 河 漢 界
1 / 4

象棋的炮需要在它和目標之間恰好有一枚棋子。黑方的開局擺法免費提供了那枚棋子,而且位置正好。這個威脅之所以存在,是因為象棋的起始擺法恰好落在 Benedict 規則能利用的地方。

它下過的每一局

最強設定下的全部 54 局,未經挑選。先行方贏了其中 46 局,而它輸掉的那八局才是值得打開來看的。

楚 河 漢 界
0

對局結束不是因為有人下錯。而是因為一方再也找不到不會輸的著法,而那個數字在盤面上出現任何可見變化之前就已經攀升了二十著。

用派餅規則讓它變公平

那 42 種開局之間的落差,正是讓這件事有救的原因,而修正方法在別的遊戲裡早就存在了。

派餅規則的運作方式就像兩個小孩分蛋糕:一個切,另一個挑。紅方走出首著。黑方接著選擇是要繼續當黑方,還是改為接手紅方的局面。這一個選項改變了紅方在最佳化的目標,因為當黑方可以直接把最強開局拿走時,走出最強開局就毫無意義了。

於是紅方被推向最接近五五波的那一著,而 42 種裡有四種落在那裡。其中兩種是炮放棄自己最好的那一格,另外兩種則是盤面上最平穩的布局著法。

楚 河 漢 界
b3b4 45.8%
炮上一步,離造成殺傷的第五線還差得遠。
楚 河 漢 界
b3b7 50.0%
炮直接殺到底,此刻兌現,放棄了持續的威脅。
楚 河 漢 界
d1e2 54.2%
仕起動,讓出d1。將帥同線從第一著就已在局中。
楚 河 漢 界
e4e5 54.2%
中兵:唯一不算失著的安靜出動之著。

被迫走上其中一種,對局就落在 50% 附近。不是靠把優勢壓下來,而是靠拿掉紅方運用它的能力,這比聽起來要乾淨得多。Hex 在每一種棋盤尺寸下都是可證明的先行方必勝,卻在全世界都有競技對局,完全就是因為有交換規則。

誠實的保留意見在於樣本。那四個數字各來自 24 局,寬到我不會把它們拿來互相排名,又窄到足以說從 0% 到 83% 的落差是真的。在合適的樣本量下確認其中一種能維持在 50% 附近,是尚待完成的工作。

派餅規則修正了公平性,卻沒有碰到尖銳程度。輸著占比是規則的性質,而不是誰領先的性質,所以它完全不會動。它讓比賽變得均勢。它不會讓比賽變得平靜,而那是否是人們想下的遊戲,是另一個我沒辦法從勝率回答的問題。

目前的狀況

作為競技遊戲還不能出貨。沒有任何積分階梯撐得住先行方四局贏三局。

這點值得跟一個聽起來很像的說法區分開。不公平不等於不能下:反吃棋是「已證明」的先行方必勝,而且每天都有人在競技對局,因為那個證明花了五年、八台機器,而且走的是沒有人類找得到的變例。Hex 在每一種棋盤尺寸下都是已證明的先行方必勝,靠交換規則照樣在下。先手優勢本身不會殺掉一個遊戲。

這裡不同的地方在於深度。這個 78% 建立在一句話就能說完的一著上,把炮提到第五線,而引擎每一次都找得到。一個已被證明但無法企及的勝利只是奇聞。一個背得起來的勝利就是整個遊戲。

派餅規則之外還有兩種未經測試的修正。把將帥標記起來而不是讓它變色,讓防守方有一著可以應對,會直接鈍化炮的威脅,而把攻擊的那枚棋子變色本來就是一種合法的回應。或者移動起始擺法中的中路卒兵,因為那個威脅之所以存在,只是因為黑方的卒剛好站在炮需要炮架的位置。

不論怎麼修,存活下來的是這個設計。把變色規則放到象棋盤上,得到的是一個沒有殘局、炮永不走弱、防守棋子一文不值、變色後的士永遠困在敵陣後方的遊戲。這一點在量測的每一個版本中都成立,因為規則正是我用四種不同方式驗證過的那一部分。

下一步是一手先規則:核心裡二十行程式碼,再把已經存在的測試框架重跑一次。

尚未解決的問題是紅方是否有必勝著法。上面的一切都是勝率,而那是關於兩個特定引擎的陳述。底下的問題是:在雙方最佳著法下這個遊戲是否為先行方必勝,而那個問題的答案不取決於任何人下得多好。

我手上有的是一個下界:13 著之內無必勝著法,用 208 億個節點和大約半小時證明出來。這排除了廉價的勝利,而一個中位長度 29 著的遊戲,被它探索到的還不到一半。

有兩件事讓這比看起來更難,一件事讓它變容易。子力守恆,所以狀態空間永不縮小,這意味著沒有殘局資料庫可建,也沒有東西能讓正向搜尋在中間會合。逆向分析,也就是每一個已解決的西洋棋殘局背後的技術,在原理上就不可用,而不只是昂貴。策略竊取,也就是從對稱起點得出超弱解的常用手法,同樣不適用:棋子是移動而不是累積,所以先行方沒辦法隨便走一著然後把它丟掉。有幫助的是對局很短。中位數是 29 著,而 54 局引擎對局和 6,000 局隨機走子都沒有和棋,所以這棵樹很淺而且終局很尖銳,這正是證明數搜尋擅長的形狀。

下一階是 14,而槓桿不在更多硬體。上面的證明可以按紅方的 42 種首著切分,而它之所以能近乎完美地平行化,正是因為答案是否:既然沒有必勝著法,就沒有分支會剪掉另一個分支,所以同時搜尋它們不會損失任何東西。靠一台筆電這樣做到了 13。切到兩著深會得到大約 1,700 個獨立工作,那是需要叢集的形狀;而證明數搜尋,也就是把力氣花在證明樹最窄的部分而不是均勻往深處搜,根本還沒實作。最後那一項不是假設:反吃棋就是這樣被解決的。Mark Watkins 在八台十六核機器上跑了五年多的證明數搜尋,證明 1.e3 白方必勝,這既是這裡需要的技術,也是對完成這件事要付多少代價的合理警告。

如果有人做出弱解,或者甚至用我沒想到的論證做出超弱解,那也順帶解決了派餅規則的問題,因為已證明的先行方必勝正是交換規則被發明出來要處理的情況。Hex 在每一種棋盤尺寸下都是已證明的先行方必勝,照樣有人在競技對局。