?? 怎樣編制黑白棋(3).txt
字號:
怎樣編制黑白棋(3)估值函數
這是一個程序中最重要的部分,如果這個模塊太弱,則就算算法再好也沒有用。這里將要敘述三種不同的估值函數范例。大多數的黑白棋程序都可以歸結于此。
棋格表
這種算法的意思是,不同的棋格有不同的值,角的值大而角旁邊的格子值要小。忽視對稱的話,棋盤上有10個不同的位置,每個格子根據三種可能性賦值:黑棋、白棋和空。更有經驗的逼近是在游戲的不同階段對格子賦予不同的值。例如,角在開局階段和中局開始階段比終局階段更重要。
一般認為,采用這種算法的程序總是很弱,但另一方面,它很容易實現,于是許多程序開始采用這種逼近。并且,對于許多程序設計者來說,它有能力使程序強到擊敗它的創造者...
基于行動力的估值
這種更久遠的接近有很強的全局觀,而不像棋格表那樣局部化。觀察表明,許多人類玩者努力獲得最大的行動力(可下棋的數目)和潛在行動力(臨近對手棋子的空格,見技巧篇)。如果代碼有效率的話,可以很快發現,它們提高棋力很多。和另一種人類的策略一樣,許多基于行動力估值的程序同時還有一些邊角配置的知識,試圖在中盤早期使棋子最少。
基于模版的估值
正如上面提及的,許多中等力量的程序經常合并一些邊角判斷的知識,最大行動力和潛在行動力是全局特性,但是他們可以被切割成局部配置,再加在一起。棋子最少化也是如此。 這導致了以下的概括:在估值函數中僅用局部配置(模版),通常單獨計算每一行、一列、斜邊和角落的模板,再線性疊加在一起來實現。并且,配置情況的值非常依賴于游戲的不同階段。比如,一條邊有3321種配置情況((3^8-3^4)/2+3^4),每種情況的分值好壞在游戲的不同階段都不相同。分值基于強力玩者和程序的游戲結果統計,他們存于數據庫中,游戲啟動時自動調入。
常見的有這樣一些模板: 名稱 類似區域 配置數 去掉對稱后的配置數
corner5x2 a1:e2 3^10=59049 (3^10-3^5)/2+3^5 = 29646
diag5 a5:e1 3^5 =243 (3^5 -3^3)/2+3^3 = 135
diag6 a6:f1 3^6 =729 (3^6 -3^3)/2+3^3 = 378
diag7 a7:g1 3^7 =2187 (3^7 -3^4)/2+3^4 = 1134
diag8 a8:h1 3^8 =6561 (3^8 -3^4)/2+3^4 = 3321
edge2x a1:h1 + b2 + g2 3^10=59049 (3^10-3^5)/2+3^5 = 29646
hor2 a2:h2 3^8 =6561 (3^8 -3^4)/2+3^4 = 3321
hor3 a3:h3 3^8 =6561 (3^8 -3^4)/2+3^4 = 3321
hor4 a4:h4 3^8 =6561 (3^8 -3^4)/2+3^4 = 3321
triangle a1:a4:d1 3^10=59049 (3^10-3^5)/2+3^5 = 29646
估值合并
一般程序的估值基于許多的參數,如行動力、潛在行動力、余裕手、邊角判斷、穩定子(見技巧篇)。但是怎么樣將他們合并起來得到一個估值呢?為了提高速度,一般的程序采用線性合并。設a1,a2,a3,a4為參數,則估值s:=n1*a1+n2*a2+n3*a3+n4*a4。其中n1,n2,n3,n4為常數,術語叫“權重”(weight),它決定了參數的重要性,來自于統計值。
一個基于棋格表和行動力估值的例子
function Evalution: Double;
var
i, j: Integer;
oppMobility, compMobility: Integer; //雙方行動力
oppValue, compValue: Integer; //雙方棋格表值
temp: Double;
Final: Boolean;
begin
oppValue := 0;
compValue := 0;
if Final then //如果是終局搜索
begin
for i := 1 to 8 do
for j := 1 to 8 do
begin
if Board[i, j] = compColor then
Inc(compValue); //電腦的棋子數
if Board[i, j] = oppColor then
Inc(oppValue); //對手的棋子數
end;
Result := compValue - oppValue;
Exit;
end;
oppMobility := 0;
compMobility := 0;
changeCost; //動態修正棋格表的值
for i := 1 to 8 do
for j := 1 to 8 do
begin
if (Board[i, j] = compcolor) then
compValue := compValue + cost[i, j]; //電腦的棋格表值
if (Board[i, j] = oppColor) then
oppValue := oppValue + cost[i, j]; //對手的棋格表值
end;
for i := 1 to 8 do
for j := 1 to 8 do
begin
if chessable(i, j, compColor) then //電腦在位置[i,j]可以下棋
inc(compMobility); //增加電腦的行動力
if chessable(i, j, oppColor) then //對手在位置[i,j]可以下棋
inc(oppMobility); //增加對手的行動力
end;
temp := sqrt(compMobility * 100) - sqrt(oppMobility * 100);
if compValue - oppValue >= 0 then //估值合并,不過這里用的并不是線性合并法
Result := round((sqrt(compValue - oppValue) * 2 + temp) * 100) / 100
else
Result := -round((sqrt(oppValue - compValue) * 2 - temp) * 100) / 100;
end;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -