既然alpha-beta搜尋演算法是在「最大-最小」的基礎上引入「樹的裁剪」的思想以期提高效率,那麼它的效率就取決於樹的結構——如果搜尋了沒多久就發現可以「裁剪」了,那麼需要分析的工作量將大大減少,效率自然也就大大提高;而如果直到分析了所有的可能性之後才能作出「裁剪」判斷,那此時「裁剪」也已經失去它原有的價值(因為你已經分析了所有情況)。因而,要想保證alpha-beta搜尋演算法的效率就需要調整樹的結構,即調整待搜尋的結點的順序,保證「裁剪」可以盡可能早地發生。
我們可以根據部分已經搜尋的結果來調整將要搜尋的結點的順序。因為通常乙個局面經搜尋被認為較好時,在其後繼結點中往往有一些相似的局面(如某些無關緊要的棋子位置有所不同)也是較好的。「歷史啟發」就是建立在這樣一種觀點之上的。在搜尋的過程中,每當找到乙個好的走法,我們就給該走法累加乙個增量以記錄其「歷史得分」,乙個多次被搜尋並認為是好的走法的「歷史得分」就會較高。對於即將搜尋的結點,按 「歷史得分」的高低對它們進行排序,保證較好的走法(「歷史得分」高的走法)排在前面,這樣alpha-beta搜尋就可以盡可能早地進行「裁剪」,從而保證了搜尋的效率。
下面分別是歷史啟發部分historyheuristic.h以及著法排序部分sortmove.h的**實現,著法排序可以使用各種排序演算法,這裡我直接借用了王小春的《pc 遊戲程式設計(人機博弈)》中採用的「歸併排序」。
歷史啟發:
// historyheuristic.h著法排序:#include // for void *memset( void *dest, int c, size_t count );
/// data define ///
int historytable[90][90]; //歷史記錄表
/// function prototype
// 清空歷史記錄表(全置0)
inline void resethistorytable();
// 取給定走法(move)的歷史得分,返回該得分
inline int gethistoryscore( cchessmove *move );
// 為一最佳走法(move)增添歷史記錄得分,ndepth標誌該走法所屬的搜尋層數
inline void enterhistoryscore( cchessmove *move, int ndepth );
// programmer-defined function
inline void resethistorytable()
inline int gethistoryscore( cchessmove *move )
inline void enterhistoryscore( cchessmove *move, int ndepth )
// end of historyheuristic.h
// sortmove.h/// data define ///
cchessmove cmtargetbuffer[80]; //排序用的緩衝佇列
/// function prototype
// 對長度為ncount的著法佇列cmsource進行歸併排序
void mergesort( cchessmove *cmsource, int ncount );
// 為mergesort函式所呼叫,歸併排序首尾相接的兩個陣列,
void mergepass( cchessmove *cmsource, cchessmove *cmtarget,
int nlength, int ncount );
// 為mergepass函式所呼叫,歸併排序首尾相接的兩個陣列(這兩個陣列已分別排好序)
//!!!降序 !!!
// 兩個陣列為cmsource[beginone]--cmsource[endone];
//cmsource[begintwo]--cmsource[endtwo]. 其中begintwo = endone + 1
inline void merge_desc( cchessmove *cmsource, cchessmove *cmtarget,
int beginone ,int endone, int endtwo );
// programmer-defined function
void mergesort( cchessmove *cmsource, int ncount )
}void mergepass( cchessmove *cmsource, cchessmove *cmtarget,
int nlength, int ncount )
if( i + nlength < ncount ) //剩餘的元素個數小於兩個nlength長度,
else // 剩餘的元素個數小於等於乙個nlength長度 }
inline void merge_desc( cchessmove *cmsource, cchessmove *cmtarget,
int beginone ,int endone, int endtwo )
if( i <= endone ) // 第乙個陣列尚未完,則接上第乙個陣列的剩餘部分
else // j <= endtwo 第二個陣列尚未完,則接上第二個陣列的剩餘部分 }
// end of sortmove.h
中國象棋軟體 引擎實現(七)測試程式
之前我們已經講了實現乙個中國象棋軟體的所有要素,本篇我們只是粗略地建乙個工程再新增一點檔案使得我們能看到程式的運 況如何。在介面完成之前,我先建了乙個win32控制台專案 學生朋友們對這個最熟悉也最容易理解 根據前面所講的我們已經有了cchessdef.h cchessmove.h cchessse...
中國象棋軟體 引擎實現(二)棋局表示
對於棋盤的表示當前比較先進的思想是 位棋盤 位棋盤 用於西洋棋非常便捷,因為西洋棋的棋盤正好有64個格仔,可以將乙個棋盤的資訊用乙個64位的變數來表示。其基本思想就是用位上的值是1或0來表示棋子在棋盤相應位置上的存在與否,這樣做的好處是可以通過位操作運算來加快局面評估和著法生成的速度。當用於中國象棋...
中國象棋主流象棋引擎分析
象棋旋風與佳佳象棋,從出現以來就廣泛吸引住了人們的眼球。在那個奇兵與大聖逐漸沒落的年代,旋風與佳佳的接連出現為象棋軟體的發展注入了新的活力。兩個軟體都採取了新的演算法,使得棋力相比過去的軟體有了較大幅度的增長,一時間風靡網路。這兩個軟體都開發了很多個版本,直到現在也沒有停息。但新版本採用了非常先進的...