📄 怎样编制黑白棋(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 + -