《對弈程式基本技術》專題
置換表bruce moreland / 文
乙個多功能的資料結構西洋棋的搜尋樹可以用圖來表示,而置換結點可以引向以前搜尋過的子樹上。置換表可以用來檢測這種情況,從而避免重複勞動。如果「
1. e4 d6 2. d4」以後的局面已經搜尋過了,那就沒有必要再搜尋「
1. d4 d6 2. e4」以後的局面了。 這個原因可能鼓舞著早期的電腦西洋棋程式的設計師們,而現在事實上這還是置換表的次要用途。在某些局面,例如在沒有通路兵的王兵殘局中,檢查到的置換的數量是驚人的,以至於搜尋可以在短達時間內達到很深的深度。 省去重複的工作,這是置換表的一大特色,但是在一般的中局局面裡,置換表的另乙個作用更為重要。每個雜湊項裡都有局面中最好的著法,我在「
迭代加深」這一章裡解釋過,首先搜尋好的著法可以大幅度提高搜尋效率。因此如果你在雜湊項裡找到最好的著法,那麼你首先搜尋這個著法,這樣會改進你的著法順序,減少分枝因子,從而在短的時間內搜尋得更深。
實現主置換表是乙個雜湊陣列,每個雜湊項看上去像這樣: #define hashfexact 0 #define hashfalpha 1 #define hashfbeta 2 typedef struct taghashe hashe; 這個雜湊陣列是以「
zobrist鍵值」為指標的。你求得局面的鍵值,除以雜湊表的項數得到餘數,這個雜湊項就代表該局面。由於很多局面都有可能跟雜湊表中同一項作用,因此雜湊項需要包含乙個校驗值,它可以用來確認該項就是你要找的。通常校驗值是乙個
64位的數,也就是上面那個例子的第乙個域。 你從搜尋中得到結果後,要儲存到雜湊表中。如果你打算用雜湊表來避免重複工作,那麼重要的是記住搜尋有多深。如果你在乙個結點上搜尋了
3層,後來又打算做
10層搜尋,你就不能認為雜湊項裡的資訊是準確的。因此子樹的搜尋深度也要記錄。 在
alpha-beta搜尋中,你很少能得到搜尋結點的準確值。
alpha和
beta的存在有助你裁剪掉沒有用的子樹,但是用
alpha-beta有個小的缺點,你通常不會知道乙個結點到底有多壞或者有多好,你只是知道它足夠壞或足夠好,從而不需要浪費更多的時間。 當然,這就引發了乙個問題,雜湊項裡到底要儲存什麼值,並且當你要獲取它時怎樣來做。答案是儲存乙個值,另加乙個標誌來說明這個值是什麼含義。在我上面的例子中,比方說你在評價域中儲存了
16,並且在標誌域儲存了「
hashfexact」,這就意味著該結點的評價是準確值
16;如果你在標誌域中儲存了「
hashfalpha」,那麼結點的值最多是
16;如果儲存了「
hashfbeta」,這個值就至少是
16。 當你在搜尋中遇到特定情況時,很容易決定評價和標誌應該儲存哪些內容。然而避免錯誤是非常重要的,雜湊表是非常容易犯錯誤的,而且一旦犯下錯誤就很難捕捉出來。 我的雜湊項的最後乙個域,儲存著上次搜尋到這個局面時的最佳著法。有時我沒有得到最佳著法,比如任何低出邊界的情況
(返回乙個小於或等於
alpha的值
),而其他情況必定有最佳著法,比如高出邊界的情況
(返回乙個大於或等於
beta的值
)。【譯註:只有葉子結點才沒有最佳著法,即便是
alpha
結點,所有的著法都是差的,也應該從中找乙個最好的著法,它對更深一層的搜尋會帶來很大的好處。】 如果找到最佳著法,那麼它應該首先被搜尋。 下面是示範程式,是根據
alpha-beta函式修改的,改動的地方用醒目的字標出: int alphabeta(int depth, int alpha, int beta) if (depth == 0) generatelegalmoves(); while (movesleft()) if (val > alpha) }
recordhash(depth, alpha, hashf); return alpha; } 以下就是兩個新的函式的**: int probehash(int depth, int alpha, int beta) if ((phashe->flags == hashfalpha) && (phashe->val <= alpha)) if ((phashe->flags == hashfbeta) && (phashe->val >= beta)) } rememberbestmove(); } return valunknown; } void recordhash(int depth, int val, int hashf) 你所看到的**,並不像航天科學一樣準確,而是很可能有錯誤的,而且細節上的問題我還沒有討論。如果你的程式中有錯誤,或許就是很嚴重的錯誤。
【以上**有個速度上的瓶頸,即「
zobristkey() % tablesize()
」這個表示式。由於「電腦一做除法就成了傻瓜」,所以「
tablesize
」最好是乙個
2n的常量,只有當除數是
2n時除法才可以由右移指令取代。最好的方法是設乙個「
tablesizemask
」的變數:
int tablesizemask = tablesize() - 1;
hashe *phashe = &hash_table[zobristkey() & tablesizemask];
而這裡「
tablesize()
」也必須是
2n。正是這個道理,在很多可以設定置換表大小的西洋棋程式中,允許的設定值總是呈倍數增長的,要麼是3m、
6m、12m、
24m等等
(如果每個雜湊項有
12位元組
),要麼是4m、
8m、16m、
32m等等
(如果每個雜湊項有
16位元組)。】
替換策略最主要的細節就包括,什麼時候該覆蓋雜湊項。在上面的例子中,我用了「始終替換」的策略,即簡單地覆蓋已經存在的值。這或許不是最好的策略,事實上已經有大量的工作試圖找出哪個策略是最好的。 另乙個策略是「同樣深度或更深時替換」。除非新局面的深度大於或等於雜湊表中已經有的值,否則已經存在的結點將被保留。 還有很多試驗的餘地。
2023年我在
usenet(新聞組網路系統
)的新聞組
rec.games.chess(如今是
rec.games.chess.computer)上問了這個問題,得到了
ken thompson的答覆。 他的回答是使用兩個雜湊表。乙個使用「始終替換」策略,另乙個使用「同樣深度或更深時替換」。當你做試探時,兩個雜湊表都去試探,如果其中乙個可以產生 截斷,那就可以了。如果兩者都不能產生截斷,那麼你可能至少得到乙個最佳著法,實際上更多的可能是得到兩個不同的著法,兩者都應該首先
(或第二個
)嘗試。 記錄的時候,你只要簡單地根據替換策略來執行。 如果你使用「同樣深度或更深時替換」的策略,那麼你的雜湊表可能最終會被過期的但很深的結點所佔滿。解決方案就是每次你走棋時都清除雜湊表,或者在雜湊項中加入「順序」這個域,從而使這個策略變成變成「同樣深度,或更深,或原來是舊的搜尋,才替換」。 我在我的程式
ferret中使用了
thompson的策略,並且執行得很好。另乙個程式
gerbil也使用這個策略,你可以去看它的源**。
【根據譯者研究的結果,只用「深度優先覆蓋」策略
(即「同樣深度或更深時替換」
),效果會比「始終替換」好得多,而**則並不複雜,只有醒目的部分是新增的:
void recordhash(int depth, int val, int hashf)
phashe->key = zobristkey();
phashe->best = bestmove();
phashe->val = val;
phashe->hashf = hashf;
phashe->depth = depth;
}如果使用這個**,那麼每走一步以前都必須把雜湊表中所有的標誌項置為「
hashfempty
」。】不穩定性的問題當你用置換表時,如果你允許搜尋過程根據雜湊項來截斷,那就會產生另乙個問題,你的搜尋會受「
不穩定性」的捆擾。 不穩定性至少是由以下因素引起的:
1. 你可能在做
6層的搜尋,但是如果你在雜湊項中得到
10層搜尋的結果,就可能根據這個值來截斷。在後來的搜尋中,這個雜湊項被覆蓋了,因此你在這個結點上得到了兩個不同的值。
2. zobrist鍵值無法記錄到達結點的線路,這個結點上不是每條線路都有相同結果的。如果某條線路遇到重複局面,那麼雜湊項的值就會跟路線有關。因為重複局面會導致和局的分值,或者至少不一樣的分值。 就我所知,還沒有什麼辦法能處理這些問題。
【另外,如果搜尋過程中找到殺棋,那麼評價值會接近「
infinity
」或「-
infinity
」,此時記錄雜湊表時不能簡單地記錄這些評價值,在後面介紹的「
勝利局面
」的處理中,會談到這個問題。】 原文:
譯者:黃晨
(返 回 象棋百科全書——電腦象棋
**:
基本搜尋技術 博弈樹
假定你的房間裡鋪有100塊地板,其中一塊底下有一塊金磚,而另一塊底下有一顆地雷。如果你翻開有金磚的那塊地板,你就可以成為百萬富翁 如果你翻開有地雷的那塊地板,你就可以到地獄旅行。在經歷了長期煎熬之後,你決定將這些地板逐一翻開,以找尋百萬富翁的生活。這個尋找命運答案的過程,就是搜尋 search 而將...
單錶置換加解密
0.3版本 該版本整合了caesar和單錶置換。修復了0.2版本的致命錯誤。writed by wintersun 2014 10 27 include include include define size 500 char x size y size int int key char str k...
技術與管理的博弈
例如 工作產品 整體解決方案 質量過程 評審 從結果來說,要達到整體解決方案的真材實料的目標。重中之重的是要有足夠能力的人寫出方案,並且和同等或更高水平的人一起,提供高質量的解決方案 評審這個管理過程,是乙個必要的管理過程,但絕不是質量達標的充分條件。不是說實施了評審過程,該解決方案就是真的高質量的...