界面都搞定了,专心分析逻辑。
五子棋AI最难的是分析整个棋局的局势。
一种办法是遍历五子棋的每一个点,判断每一个点的分数。
如何判断每一个点的得分?根据这个点组成的所有五元组。
比如,对于电脑黑棋=4,白旗=5来说,对于该点组成的每一个五元组,有如下策略表:见下面。。。
当case 0 意味着此无棋子。
当case 4 意味着有一个黑棋棋子。
当case 8 意味着有两个个黑棋棋子。
...
当case 20 意味着有4个白旗棋子或5个黑棋棋子。这个点的得分最高,那么这个点对于黑棋来说就是必须要下的一个点。
这就是通过此策略表电脑能够堵住人下的杀棋的原因。
在实际中发现,此策略表效果惊人。
我使用的策略表如下:
int Game::chart(int count)
{
if(computerColor==4)
{
switch(count)
{
case 0: temp=7;break;
case 4: temp=35;break;
case 8: temp=800;break;
case 12: temp=15000;break;
case 16: temp=800000;break;
case 5: temp=15;break;
case 10: temp=400;break;
case 15: temp=1800;break;
case 20: temp=100000;break;
default: temp=0;
}
}
}
如何遍历所有的五元组?
这里提供一种办法,结构清晰,代码风骚,效率恐怖。
typedef struct
{
int x,y,l,r;
}value;
value fiveValue[15][15];
//此函数能够将所有的五元组遍历出来
void Game::setFiveValue()
{
for(int i=0;i<15;i++)
for(int j=0;j<15;j++)
{
int count=0; //x
if(j<11)
{
for(int n=0;n<5;n++)
{
count+=chess[i][j+n];
}
fiveValue[i][j].x=chart(count);
}
count=0; //y
if(i<11)
{
for(int n=0;n<5;n++)
{
count+=chess[i+n][j];
}
fiveValue[i][j].y=chart(count);
}
count=0; //r
if(i<11&&j<11)
{
for(int n=0;n<5;n++)
{
count+=chess[i+n][j+n];
}
fiveValue[i][j].r=chart(count);
}
count=0; //l
if(j>=4&&i<11)
{
for(int n=0;n<5;n++)
{
count+=chess[i+n][j-n];
}
fiveValue[i][j].l=chart(count);
}
}
}
电脑需要判断某一空白点的得分,得分越高的就下在这个点上。但是我们看到上面的遍历五元组是不重复的。它只会判断向右向下的,不会又重复的计算向上向左的。
可能是由于懒,在上面的遍历五元组的基础上设计了一种办法,来计算一个点的得分,即这个点的分数加上图上红点的分数的和
具体代码如下:
QPoint Game::computerPutdown1()
{
int temp=0,x=0,y=0;
setFiveValue(); //函数实现在上面
getSiteValue();
for(int i=0;i<15;i++)
for(int j=0;j<15;j++)
{
if(chess[i][j]==0) //选出空白点分数最大的一个
if(siteValue[i][j]>=temp)
{
temp=siteValue[i][j];
x=i;
y=j;
}
}
if(player!=0)
{ chess[x][y]=player++%2+4;
chessPoint.push_back(QPoint(x,y));
}
else
{
chess[7][7]=player++%2+4;
chessPoint.push_back(QPoint(7,7));
}
return QPoint(x,y);
}
void Game::getSiteValue() //
{
for(int i=0;i<15;i++)
for(int j=0;j<15;j++)
{
siteValue[i][j]=fiveValue[i][j].l+fiveValue[i][j].r+fiveValue[i][j].x+fiveValue[i][j].y;
for(int n=1;n<5;n++)
{
if(j-n>=0)
siteValue[i][j]+=fiveValue[i][j-n].x;
if(i-n>=0)
siteValue[i][j]+=fiveValue[i-n][j].y;
if(i-n>=0&&j-n>=0)
siteValue[i][j]+=fiveValue[i-n][j-n].r;
if(i-n>=0&&j+n<=14)
siteValue[i][j]+=fiveValue[i-n][j+n].l;
}
}
}
总结:1、你可以设计一个更好的判断局势的函数,来表明电脑下在这里会得到更好的效果。
2、开发完成后,发现,此策略表的效果还是不错的,至少他还会封堵,并且还能够简单判断局势
3、他是不可能打败一个高手的,只能是简单难度。因为他没有考虑博弈。
4、对于五元组的高效的遍历等都是很考验基本功的,对于设计其他的策略表有启发意义。