博弈基本技術 置換表

2021-08-22 16:48:58 字數 4550 閱讀 3357

《對弈程式基本技術》專題

置換表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...

技術與管理的博弈

例如 工作產品 整體解決方案 質量過程 評審 從結果來說,要達到整體解決方案的真材實料的目標。重中之重的是要有足夠能力的人寫出方案,並且和同等或更高水平的人一起,提供高質量的解決方案 評審這個管理過程,是乙個必要的管理過程,但絕不是質量達標的充分條件。不是說實施了評審過程,該解決方案就是真的高質量的...