QT五子棋项目详解之三:AI人机对战,策略表

时间:2024-04-11 16:15:02


QT五子棋项目详解之三:AI人机对战,策略表

界面都搞定了,专心分析逻辑。

五子棋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);
            }
        }
}

电脑需要判断某一空白点的得分,得分越高的就下在这个点上。但是我们看到上面的遍历五元组是不重复的。它只会判断向右向下的,不会又重复的计算向上向左的。


QT五子棋项目详解之三:AI人机对战,策略表

可能是由于懒,在上面的遍历五元组的基础上设计了一种办法,来计算一个点的得分,即这个点的分数加上图上红点的分数的和

QT五子棋项目详解之三:AI人机对战,策略表


具体代码如下:

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、对于五元组的高效的遍历等都是很考验基本功的,对于设计其他的策略表有启发意义。