電腦會對暗子可能是的每一種棋子取平均
電腦考慮一步翻子時,會對暗子可能是的每一種棋子各走一次這步棋,分別打分,再按每種棋子剩餘的數量加權平均。一步翻子如果翻出車就贏、翻出兵就被將死,分數應該介於兩者之間。兩個錯誤破壞了這個平均。
對黑方來說,平均取了最好的那個棋子
取平均之前,程式會把每個分數換算到某一方的視角。它根據一個從未被賦值的設定來判斷是哪一方,所以總是當成紅方。對紅方的翻子,這樣沒有問題。對黑方的翻子,分數就是反的:一條本該在結果相差很大時取最差結果的規則,取了最好的結果。
AB-JChess 那篇文章最初開頭用的就是這盤棋。皮卡魚執黑,把 d10 的暗子翻開走到 e9,自評領先將近 19 個兵。只有 e9 上是士,才能擋住車在 f10 的將殺,而在它可能是的 11 個棋子裡,士只有 1 個。翻出來是車,黑方下一步就被將死。
被搜尋中途放棄的分數,被當成精確值取了平均
引擎為了節省時間,一旦知道某步棋不如目前最好的一步,就會放棄繼續搜尋它,返回一個界限,意思是「最多這麼多,或者更差」。如果接下來只是比較大小,這樣做是安全的。但這個電腦把這些界限當成精確分數放進了平均,於是一個會被將死的棋子可能返回「不超過 +7」,然後就按 +7 計算。
在 AB-JChess 那篇文章的第一盤棋裡,電腦執紅,把 b3 的暗子翻開走到 d3。用舊版電腦重新搜尋,這步棋評為紅方領先八個兵以上。這個棋子十次裡有六次是兵或相,黑炮立刻在 h1 將死。如實平均的話,這步棋對黑方來說價值大約三個兵。修復後的電腦看到了這個將殺,改走仕從 e2 到 f3,也就是 AB-JChess 推薦的著法。
錯誤在程式碼裡的位置
兩個錯誤都在我們複製的皮卡魚揭棋分支裡。簡化後,舊程式碼是這樣給翻子打分的:
# Before (simplified)
for piece in pieces_it_could_be:
# cut short, this returns the window's edge
s = -search(position_with(piece), window)
# set from a field nobody fills in
if mover_is_black:
s = -s
scores.add(s, weight = count[piece])
v = weighted_average(scores)
# for Black, "min" was really the best
if v - min(scores) > MAX_SPREAD:
v = min(scores)顏色翻轉在 misc.h 第 360 到 366 行,由 search.cpp 第 1310 行設定:它判斷走棋方是不是「先手方」,而這個欄位從來沒有被賦值。窗口問題在 search.cpp 第 1462 行:每種棋子都在上一層著法的窗口內搜尋,一個會被將死的棋子返回的是窗口的下沿。
我們透過列印翻子時每種棋子的分數找到了第二個錯誤。在一盤對抗賽對局裡,電腦可能翻出的四種棋子中有三種會被將死,而這三種返回的都恰好是 738,也就是窗口的下沿。第四種得 792。電腦把它們平均成 745,把這步棋評為勝勢。
# After
for piece in pieces_it_could_be:
s = -search(position_with(piece), window)
# only a bound: search again for the score
if at_root and s <= window.low:
s = -search(position_with(piece), no_lower_limit)
scores.add(s, weight = count[piece])
v = weighted_average(scores)
if v - min(scores) > MAX_SPREAD:
v = min(scores)顏色翻轉已經去掉,返回界限值的棋子會重新搜尋。全部改動是一次提交,28 行。
修復後的電腦對翻子的估值接近實際,棋力也基本不變
在 AB-JChess 對抗賽中決定皮卡魚輸棋的 71 步裡,舊版電腦把其中 16 步評得比實際好至少五個兵。修復後的電腦只有 3 步。它的棋力和舊版差不多,也許略弱一點:快棋 600 盤,它贏 264 盤、輸 300 盤;每步搜索量加到四倍後對下 200 盤,它贏 95 盤、輸 97 盤。
修復只涵蓋電腦正在選擇的那一步。在更深的搜尋裡,舊的平均方式依然存在,因為在所有地方都修復會讓電腦弱大約 150 Elo。
AB-JChess 也有第二個錯誤,但很少有影響
AB-JChess 基於皮卡魚,也用同樣的方式對翻子取平均。它有搜尋中途放棄的問題,沒有顏色的問題。在決定它輸給我們電腦的 60 步翻子中,它只高估了 2 步。
一個關於一步棋的問題發現了它
AB-JChess 那篇文章最初用第 108 盤來說明皮卡魚如何判斷翻子。發現這個錯誤的,是一個問題:電腦到底為什麼會走 d10-e9?正確的搜尋不可能在自己的最佳變化裡看到將殺,還把局面評為勝勢。我們當天就把那些例子從那篇文章裡刪掉了。