象棋基本殘局:哪些結論已知,可靠程度如何
西洋棋有一張每位棋手都要學的基本殘局表。王加車能勝。王加雙馬無法強勝。王加主教是死局。象棋也有同一張表,如果你讀中文,你會以同樣方式學到它,從各家殘局手冊裡,而它們的結論全都一致。而在英文世界裡,你只能拿到碎片。
最好的碎片是英文維基百科象棋條目的殘局一節。三十幾條結論,以散文敘述,一條引註也沒有。中文的對應內容是一篇叫做象棋勝和定式(象棋勝和定式)的條目。它涵蓋同樣的範圍,每條結論配一張圖,並引用兩本書:金啓昌與楊典的《象棋殘局勝和定式》(北京體育大學出版社,2008),以及薛榮賢的《象棋入門實用指南》(2009)。這兩本書我都沒讀過。下文我說「手冊」時,指的就是那兩篇維基條目:一篇是手冊傳統的壓縮報告,另一篇讓你看見局面。
其中三十二條結論列在下面,每一條都做成一個局面並經過兩次核對,而且每一條都是一塊你可以對著核對它的引擎實際走下去的棋盤。這份研究放在Mistboard上,一條結論一章。
基礎:什麼能贏士象全
車是象棋最強的子力,也就是換了名字的 rook。標準的士象全保有四個防守子力:將在原位、雙士、雙象,且兩個士正排在將的前方,讓炮無法拿它們當炮架。
單車對上這樣的防守是和棋,而且現在是有證明的和棋:資料庫說和棋,Pikafish 給出的評估值正好是 0。
三卒能勝。15 步內強制將死。
雙馬也能勝,25 步。
和棋
15 步將死
同樣的防守,同樣的一方行棋。兩個結論都出自資料庫,而不是搜尋。任選一局執黑,試試能不能守住。
依你能找到的任何子力價值表,一個車都比三個卒值錢,也比兩個馬值錢。但在這個殘局裡,它比兩者都不值。卒不能後退,聽起來像弱點,結果卻成了它們取勝的原因:三個卒壓向九宮,無法被趕回去,而防方也沒有辦法把它們兌掉。
同樣的邏輯反過來也成立。五個兵全都停在底線,對上光將,是和棋。五子對零子。它們不能後退,而且已經貼著邊,所以既無法強制將死,連困斃也做不到。
和棋
五子對一子,而局面中不存在殺法。執紅方,試試能不能贏。
決定這些殘局的是子力位置,而英文那一節剛好有一對圖直接把這點呈現出來。
單車對馬雙象。防方擺在它的堡壘裡(馬在 e8,象在 i8 與 g6)就能守住,資料庫也確認守得住。把 g6 的象移到 g10,紅方就勝,從 1.Rb7 開始。
和棋
紅勝
全部差別只在盤面右側那個象往上挪了四格。守住第一個,攻破第二個。
雙方子力相同、攻方相同、行棋方相同,結果卻翻轉。這一對之所以能在翻譯中存活,是因為有人把它畫出來了。下面三節,則是沒有人畫的那些。
取勝的條件
三十二條結論中有三條,取決於英文並未傳達的一項指示。每一條裡都有一個子力位置決定結果,而點明它的那句話正是被漏掉的那句。
車對馬炮,和棋只在一格之間
英文那一節寫道:「車對雙小子、無防守子力:和棋,但需要良好的防守位置。」
我造了八個這樣的局面。Pikafish 在全部八個裡都找到強制將死,從我能構造出最頑強的那一個算起是 15 步。八個全部如此不可能是搜尋的假象,所以我把這一條寫成有爭議後就往下走了,那是錯誤的判斷。
中文條目畫出了局面,並多加了一句英文沒有傳達的指示:炮要正好擺在自己將的後面,而馬要盡量離將遠。
和棋
12 步將死
只差一格。左邊炮正好在自己將的後面,局面是和棋;右邊它移了一格,紅方 12 步將死。任選一局執黑。
那個局面在雙方任一方行棋時都是資料庫判定的和棋,而 Pikafish 搜到深度 40 讀出 +0.10。炮在將後既護住底線,又不會被貼著將抽吃,這就是整個堡壘。把它橫移一格,同一個局面就是 12 步將死,而我試過的其他每一格也都是負,從隔一格到最遠的角落都一樣。
結果車本身的位置完全不重要。我從 a10、e5、i1 和 a1 都測過,每一個依然是和棋,這正是它之所以是堡壘、而不是碰巧擺對的原因。馬的規則比手冊那句「盡量離將遠」寬鬆:它只要避開單一車著能攻擊的格子就好。在 b7、c7、d7、e7、d6、d4 或 d2,局面守得住。在 d5,也就是車自己那一線上,車直接吃掉它,5 步將死。
我那八個局面的炮全都擺在別處。英文裡的結論本身是對的。「需要良好的防守位置」承擔了整個結果,卻什麼也沒告訴你。
車炮對車,「中路」不是一個格子
英文那一節寫道:「只要防方的車佔住中路,車加炮無法勝單車。」
那讀起來像是一條可以核對的規則。我的局面符合它:黑方的車在中路、在原位、正好在自己將的前面。Pikafish 28 步將死。
它之所以能將死,是因為那句話沒提到的那個子。炮吃子要隔一個子跳,所以它需要炮架,而且不管炮架是誰的。紅方的炮滑到中路、落在黑車下方,立刻將軍,拿那個黑車當炮架,拿它後面的黑將當目標。防方賴以求和的子,正是那個炮車架。
把防方的車沿著那一路往下走,資料庫會在上頭畫出一條界線:
和棋
紅勝
兩局的防方車都佔住中路。只有較低的那一局是和棋。最後的殺法是海底撈月,在那一路的底部完成。
紅方如圖佈置時,防方的車在第 5 線及以下是和棋,深度 40 時 0.00,在第 6 線及以上則是負。只差一線。
紅方要取勝必須有兩件事成立,而兩件都跟紅方有關。炮必須能落到中路並在那裡存活,在圖中就是落在第 5 線,那裡有紅方自己的車保護它。把那個炮移離車所在的橫線,挪到第 3 或第 7 線,原本每一個勝局都變回和棋。而紅方需要中路的底部,因為這個殘局賴以取勝的殺法海底撈月(海底捞月)就在那裡執行:車走到那一路的底端,自己的帥在它後面,防方的車最後被夾在兩將之間,離開那一路就會造成白臉將,留在那裡就會被吃。
防方站在自己半邊的中路上,兩件事哪一件都擋不住。佔住一路,說的是一個子所控制的那些格子。我把它讀成關於它所站那一格的主張,造了一個符合字面的局面,結果被 28 步將死。
馬炮對馬,再深的搜尋也定不下來
英文那一節寫道:「馬+炮+四個防守子力對一個小子[加]四個防守子力:小子是馬則勝……小子是炮則和。」
十三個子。chessdb 只建過一張這麼大的表,而且是另一組十三子,對這一組做即時查詢回傳的是未知。但這並不代表只剩搜尋。減到十子的 KANCKAABBN,也就是強方留一個仕的那個簡化,這張表存在:24,251,768,055 個局面,紅方勝其中 85.48%。支撐這個結論的是這道階梯,而不是搜尋深度。
搜尋解決不了它。深度 26 給 +2.24。深度 42 給 +2.47,依然沒有殺,而防方馬的六種不同擺法落在 +2.32 到 +3.03 之間,沒有一個變成決定性的。一個漫長的技術性勝局在固定深度下看起來就是這樣,而一個紅方單純較優卻是和棋的局面也是這樣。
有兩項證據仍然指向書上是對的。引擎自己就把這條結論的兩半分開了:把防方的馬換成炮,也就是同一句話裡和棋的那一半,同樣的深度讀出 +1.26。那個落差就是書上的區分,出現在一個從未被告知這件事的數字裡。
接著我讓 Pikafish 在深度 32 自己把這個局面走完。紅方花了 33 步調度,雙方都沒有吃子,第 34 步吃掉一個士,四步後吃掉第二個,然後持續轉化到第 56 步,局面降到十子,回到資料庫的範圍內。黑方行棋,每一個合法應手都是負。
第一次吃子就是整個問題的關鍵,因為有一條在西洋棋裡沒有對應的規則:自然限着(自然限着)規定雙方各走 60 步而完全沒有吃子即判和。一個需要 70 步技術的例勝,不是你能走出來的勝局。這一個在第 34 步就突破了,還剩 26 步餘裕。
象棋也把另一扇門關上,而那一扇對西洋棋棋手咬得更深。長將在這裡算負:將軍的一方必須變著,否則判負。在西洋棋裡這是把敗勢救回來的標準手段,所以這個本能不只是幫不上忙,而是直接把分數送出去。這兩條規則一起框住了本文裡每一個殘局。防方無法靠將軍脫身,攻方也不能無限磨下去。兩者在西洋棋裡都沒有可以對譯的東西,這正是英文摘要會把它們漏掉的原因。
這仍然不是這一條的證明。黑方也是 Pikafish,早一點更好的防守也許能守住;這裡沒有任何東西排除這一點。它確定下來的,是過去要靠我信任的那一部分。最後的勝利不是引擎在深度 32 宣告的殺、而我選擇相信,而是一個可以被證明為負的局面,所以引擎的著法線轉化成精確的東西,而不是它自己的意見。引擎依然拒絕從根局面確認書上的結論。但它現在走進一個確定的局面。如果你想體會 34 步的擠壓有多薄,就執防方走這一條,而和棋的那一半只差一個子。
未解
十三個子,沒有任何殘局庫涵蓋的一條。黑方有 60 步的時間存活而不丟子。
把子力減下去,它就不再是搜尋問題。chessdb.cn 公布了這個殘局各種簡化的精確表,而它們改變了書上那句話的意思。把紅方自己的仕相拿掉,只留帥、炮、馬對士象全:5,492,247,706 個局面,紅方勝其中 22.31%。還給紅方一個仕,就升到 85.48%,共 24,251,768,055 個局面。第二個仕再加一個百分點。用一個相代替那個仕則加七個百分點。
所以那句話裡攻方那邊的「四個防守子力」是有實際作用的,而真正關鍵的數字是一。一個仕就撐起了勝局,相幾乎是白送的。我是先用 Pikafish 得到這個結論的,在知道那些表存在之前就在深度 30 跑了同一道階梯,而排序結果一樣。
把同一個局面從另一邊切,答案就翻轉。雙方都留著士象全,改成把防方的馬拿掉:十二個子,共 10,453,951,719 個局面,而 chessdb 建了這一張。紅方勝 92.71%,最長的殺是 69 個半著,而表中完全沒有記錄任何負。一個簡化說勝局靠的是紅方自己的仕。另一個說,一旦黑方沒有東西可以反抗,勝率就近乎全面。書上真正談的那組子力就落在兩者之間,不在那 8,705 張表的任何一張裡,而對它做即時查詢回傳的是未知。
六個詞,兩個桶
上面三節有兩節有一個共同點,而那就是詞彙。中文殘局手冊不會只把結果評為勝或和。它們用一把有六級的尺來評:
| 結論 | 它主張什麼 | 英文歸類 |
|---|---|---|
| 必勝 | 這組子力從任何局面都能勝 | 勝 |
| 例勝 | 以標準技術取勝 | 勝 |
| 巧勝 | 只有從特定局面才能勝 | 勝 |
| 難勝 | 難以取勝,但這和和棋不是一回事 | 勝 或 和棋 |
| 例和 | 以標準技術求和 | 和棋 |
| 必和 | 從任何局面都能求和 | 和棋 |
六個之中有五個能在翻譯中存活。第六個必須選一邊站,而上面三節裡有兩節就落在它身上。
中文條目把車對馬炮歸在第四級,難勝。英文那一節把它歸為「和棋」。殘局庫站在中文這邊:車在盤面上幾乎任何地方都能取勝,只被單一種防守陣形擋住。讀到「和棋」的棋手會隨意防守,然後 15 步被將死。讀到「難勝」的棋手知道,要找的東西就只有一個。
第二節從另一個方向落在同一級上。中文表把車炮對單車列為勝或和(胜/和),然後用一整段講哪種是哪種。英文保留了其中俐落的那一半,把那一段丟掉了,而那一段才是關鍵。
局面才是事實。結論只是有人從一整架標籤裡挑一個貼上去,而把標籤翻出來卻不帶那整架,就失去了它大部分的意義。
這些結論的可靠程度如何
這張表裡的結論屬於三個等級之一,而它們遠遠不等價。有些是已證明的:資料庫算完了整個殘局,答案是一次查表。有些是搜尋出來的:引擎在我跑的深度上同意。那是證據,不是證明。剩下的是斷言,出自一本沒有引註的手冊。
把它們分類花了兩輪。
我把英文那一節的 32 條結論取出來,為每一條做了一個代表性局面,然後在深度 26 問 Pikafish。
| 深度 26,32 條結論 | |
|---|---|
| 引擎同意 | 29 |
| 書上說和棋,引擎找到強制勝 | 2 |
| 書上說勝,引擎走不完 | 1 |
接著我用第二種方式再核對同一批局面。象棋有雲端殘局資料庫,是查答案而不是搜尋答案:chessdb.cn 對子力足夠少的局面回傳勝、和或負,外加一個距離數。我的 32 個裡有二十七個符合。這個門檻比聽起來寬鬆,因為一個盤上有八個士象的局面,受限程度幾乎和只有三個子的局面一樣:士只有五個合法格,象只有七個,而且都不能離開自己半邊。它也確實是查表。沿著它自己的最佳著法一步步走,結論從不翻轉,距離也從不上升,沒有任何搜尋會這樣。
上面三節裡有兩節現在帶著資料庫確認過的防守佈置,而兩次更正都是我的,不是手冊的。整輪掃過的結果是 32 條裡有 31 條與 Pikafish 一致、1 條偏向一邊,其中 32 個局面裡有 27 個小到能進資料庫,且全部 27 個都是精確答案。
核對在我造的局面裡抓到什麼
核對抓到的其餘問題都是我的。三個不合法的局面,我讓兩個將帥在一條開放的直線上互相照面,這在解析上沒問題、看起來也沒問題,但不是合法的象棋。兩個我標成例和的局面,Pikafish 宣告 2 步將死,結論是對的,是我的快照是垃圾。還有一個是局面沒問題,但我對它的解釋是錯的。
書上說三個高兵能勝士象全,也就是兵在第 7 線。把同樣三個兵退後一線,勝局就蒸發了。我把這寫成先手節奏的問題,差一步而差了全部。並不是。黑方的象在整個盤面上只能站在七個點上,而從 e8 出發,它正好能到 c6、g6、c10 和 g10。第 6 線上的三個兵裡有兩個正停在象位上。黑方在那裡不需要技術,只需要吃一子。
15 步將死
黑方吃一子
「高兵」所保護的,就是象的觸及範圍。第 7 線上的兵在棋局的任何時刻、從任何格子,都不可能被象吃掉。退後一線,就有兩個站在象能到的格子上。
我的六個局面有問題,而核對把六個全抓出來了。手冊的結論一條也沒有。
邊界
資料庫能把一個殘局定下來,是因為有人把它整個算完了。chessdb.cn 為象棋建了 8,705 張這樣的表。沒有任何英文頁面說明它們的規模,所以列在這裡。
| 子數 | 表數 | 局面數 |
|---|---|---|
| 3 | 4 | 18,858 |
| 4 | 36 | 690 萬 |
| 5 | 169 | 13 億 |
| 6 | 615 | 1880 億 |
| 7 | 1,582 | 7.0 兆 |
| 8 | 2,494 | 26.1 兆 |
| 9 | 2,169 | 33.9 兆 |
| 10 | 1,227 | 23.6 兆 |
| 11 | 368 | 10.4 兆 |
| 12 | 40 | 1.0 兆 |
| 13 | 1 | 304 億 |
102,230,279,715,348 個局面。磁碟上 25.56 TiB,把距離轉化表與 DTM(將死距離)表一起計入。數量在九個子時達到高峰,過了十一個子之後迅速下滑,這就是從內部看到的邊界模樣。整個語料庫裡最長的強制勝有 759 個半著:雙馬加一仕對雙象、一馬、一卒。
每方十三個子、雙方防守完整,已經超出那張表的最後一列。那就是馬炮這一條。手冊的例勝,它那句「常規取勝」,是對一個沒有人算過的局面下的結論。
chessdb 建過的那唯一一張十三子表是另一個殘局,也正是本文開頭那一個:三個兵在士象全之後,對上士象全。30,445,843,365 個局面,象棋裡有人解出的最深子力,而紅方勝其中 48.00%。那個數字計入子力的每一種擺法,而不只是好的那些,這也是為什麼書上的結論和勝率不是同一個主張。
這兩個數字都值得放在本頁頂端那張表旁邊一起看。基本殘局是小的那些,而其中大多數已被完整解決。一旦一條結論描述的是雙方全力,它描述的就是從來沒有人算過的子力,而在那裡手冊仍然是唯一的來源。
這 32 條,每一行都附上來源與出處,都在 xiangqi-endgame-corpus.ts 裡。核對工具是 verify-xiangqi-endgames.ts;把它指向一個 Pikafish 執行檔,它就會把書上的結論和引擎的讀數並排印出來,附上主要變著。加上 --tablebase,它會為每一個小到有精確答案的局面補上那個答案。
基本殘局是一個你可以測試的主張,這也是把它們放到棋盤上而不是放進表格裡的全部理由:執書上說是負的那一方,看看你能撐多久。32 個全都是 Mistboard 上的一份研究,一條一章,以該局面為起點,引擎的著法線作為主線,結論寫在下面。當事情走得不順時,Pikafish 就在對戰機器人階梯上以全力待著,下面還有八個 Fairy-Stockfish 等級,供全力不再有教學意義的時候使用。