第三天——进攻防守,视情况而定
在第二天,AI可以防守了,但是我们设计AI绝对不是为了让AI被动挨打,而是适时地主动出击。那么,是时候回答第二天的遗留问题——什么条件下进攻,什么条件下防守?
第二天,我们提出了阴线评估函数的概念,并且成功的利用阴线评估函数指导AI进行防守。那么是不是需要一个新的什么函数来指导进行呢?好吧,在试图构思这个新函数之前,让我们再看看阴线评估函数。
在阴线评估函数中,我们对每个棋子沿8个方向上的连续出现的一种颜色的棋子进行统计。同时将统计结果记录在qiju中,qiju[i][j][k][s]代表棋盘上(i,j)位置是空位置,那么它沿第k个方向连续出现的黑子数目记录在s=0中,白子数目记录在s=1中。然后分别对s=0和s=1进行统计,得到a1[i][j]和a2[i][j]。
好了,加入人先持黑,AI后手持白。那么,在第二天,AI选择的是a1中数值最大的位置落子,意思就是AI认为这个位置潜在威胁最大!!在这里落子可以降低对手的威胁。现在,设a1的最大值为Max1,对应的坐标为(x1,y1);a2的最大值为Max2,对应的坐标为(x2,y2)。
那么Max2对应的(x2,y2)是不是就是当前对AI最有利的落子位置呢?
就目前的评估函数来说是的。好了,经过简单的回顾阴线评估函数的定义,我们完全没有必要重新定义一个新的评估函数来指导AI进攻,而是充分挖掘一下阴线评估函数,利用Max1和Max2来决策是否进攻就好了。
当Max1>=Max2时,意味着威胁大于优势,AI最好选择防守,否则AI可以选择进攻。落子的位置,如果选择了防守,落子在(x1,y1),否则落子在(x2,y2)。
到目前为止,AI基于我们简陋的阴线评估函数可以自己决定是进攻还是防守,事实证明,基于这个方法,AI的水平算是基本入门了……
我们的AI终于入门了,那么,如何提高AI的决策水平呢?也就是说,仅仅使用阴线评估函数来支撑决策是不够的,我们需要另外一个评估函数来支撑AI决策。这个评估函数将是什么?如何使用,且听下回分解——MinMax算法。
--------------------分割线--------------------
AI的实现代码如下,
void CWuZiQi::AI_2( const int points[16][16], bool first, int oldp[16][16], int newp[16][16], int *nx, int *ny )
{
int i, j;
int x, y;
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
int qiju[16][16][8][2];
int a1[16][16], a2[16][16];
// current state quick save
for ( i = 1; i <= 15; i++ )
for ( j = 1; j <= 15; j++ )
{
oldp[i][j] = points[i][j];
newp[i][j] = points[i][j];
}
FillMatrix( qiju, 0 );
FillMatrix( a1, 0 );
FillMatrix( a2, 0 );
HowManyInLine( oldp, qiju );
ValueTheChessboardNaive( oldp, qiju, a1, a2 );
//PrintMatrix( qiju );
//PrintMatrix( oldp );
/****************算出分数最高的空位,填写坐标*********************/
for( i = 1; i <= 15; i++ )
for( j = 1; j <= 15; j++ )
{
if( a1[x1][y1] < a1[i][j] )
{x1 = i; y1 = j;} // black
}
for( i = 1; i <= 15; i++ )
for( j = 1; j <= 15; j++ )
{
if( a2[x2][y2] < a2[i][j] )
{x2 = i; y2 = j;} // white
}
if ( first )
{
if ( a1[x1][y1] > a2[x2][y2] )
{x = x1; y = y1;}
else
{x = x2; y = y2;}
newp[x][y] = 1;
}
else
{
if ( a2[x2][y2] > a1[x1][y1] )
{x = x2; y = y2;}
else
{x = x1; y = y1;}
newp[x][y] = 2;
}
*nx = x; *ny = y;
}