用cocos2d-x 实现的带ai的五子棋

本文介绍了使用cocos2d-x开发五子棋游戏,并通过博弈树和alpha-Beta剪枝提高AI智能。分析了五子棋的计分系统和决策过程,探讨了如何通过搜索两步优化AI,并展示了alpha-Beta剪枝减少搜索的无效部分,提升游戏效率。
摘要由CSDN通过智能技术生成

做了几个场景切换,稍微美化了一下,大体效果如下






问题定义及分析

五子棋问题归结为一个寻找某状态下的棋盘的最佳落子点的问题,所以我们不如使用一个整型二维数组来代表棋盘状态,每个元素这一点的状态,0表示该处无子,1为黑子,2为白子。将下棋时棋落在哪一点 的决策标准抽象化为该点的得分

我们进一步分析两个人在下棋时的想法。落子时,考虑两方面的目的:

1.进攻,即设法使自己的局势朝向胜利方向转变;

2.防守,即设法阻止对家胜利(即若对家在改点落子可使对家走向成功,则我方应在此落子以阻碍对方取得胜利)。

故落子时必须综合考虑到上述两种因素:我们希望找到一点,当任意一方在此落子时,可造成对该方更容易达到五子连环的局面。而我们需要对“更容易达到五子连环的局面”的这一表达进行的界定:一是落子后所能达到的连环子数(这也是最直观的),二是下一个回何时是否能在此基础上继续加棋子(如:当该子下在了棋盘的边缘,则下一次最多只能下在连环的另一端,倘若另一端已有棋子,那么就不能在此继续造成更多的连环了)以及最多能加多少(1,2或0)。

将上述思想转化程序思想。对于上述“ 更容易达到五子连环的局面” 的这一表达进行的界定,采用计分的形式(如:当放置在此点可造成五子连环,便得到一个最大的分值,若只有四子连环,则得到一个小的分值,等等,再将各分值累加。

遍历棋盘所有空位(在某一位置,假设放上己方的棋子,计算此时己方得分,(此为进攻得分);假设放上对方棋子,计算此时对方得分(此为防守得分),二者相加即得最终得分。选取分值最大的点,即为要下的位置


下面是我从网上搜集到的计分表



参照上表,实现的计分函数score如下:

int ChessBox::score(int color) //1 black   2 white
{
char d[16][7] = { "OOOOO", "+OOOO+", "+OOO++", "++OOO+", "+OO+O+", "+O+OO+", "OOOO+", "+OOOO", "OO+OO", "O+OOO", "OOO+O", "++OO++", "++O+O+", "+O+O++", "+++O++", "++O+++" };
int s[16] = { 50000, 4320, 720, 720, 720, 720, 720, 720, 720, 720, 720, 120, 120, 120, 20, 20 };
int score = 0;
int i, j, k, l;
/*
检查行
*/
for (i = 0; i < 15; i++)
for (j = 0; j < 15; j++)
for (k = 0; k < 16; k++)
if (strlen(d[k]) + j - 1 <= 15)
{
int flag = 1;//flag==1 初始默认可行
for (l = 0; l < strlen(d[k]); l++)
if (((d[k][l] == 'O') && (a[i][j + l] != color)) || ((d[k][l] == '+') && (a[i][j + l] != 0)))
{
flag = 0;//发现不可行
break;
}
if (flag) score += s[k];
}


/*
检查列
*/
for (j = 0; j < 15; j++)
for (i = 0; i < 15; i++)
for (k = 0; k < 16; k++)
if (strlen(d[k]) + i - 1 <= 15)
{
int flag = 1;
for (l = 0; l < strlen(d[k]); l++)
if (((d[k][l] == 'O') && (a[i + l][j] != color)) || ((d[k][l] == '+') && (a[i + l][j] != 0)))
{
flag = 0;
break;
}
if (flag) score += s[k];
}
/*
检查斜
*/
for (i = 0; i < 15; i++)
for (j = 0; j < 15; j++)
for (k = 0; k<16; k++)
{
int ii = i, jj = j;
int flag = 1;
for (l = 0; l<strlen(d[k]); l++)
{
if ((ii>15) || (jj>15))
{
flag = 0;
break;
}
if (((d[k][l] == 'O') && (a[ii][jj] != color)) || ((d[k][l] == '+') && (a[ii][jj] != 0)))
{
flag = 0;
break;
}
ii++; jj++;
}


if (flag) score += s[k];
}


/*
检查斜
*/
for (i = 0; i < 15; i++)
for (j = 0; j < 15; j++)
for (k = 0; k < 16; k++)
{
int ii = i, jj = j;
int flag = 1;
for (l = 0; l<strlen(d[k]); l++)
{
if ((ii>15) || (jj < 1))
{
flag = 0;
break;
}
if (((d[k][l] == 'O') && (a[ii][jj] != color)) || ((d[k][l] == '+') && (a[ii][jj] != 0)))
{
flag = 0;
break;
}
ii++; jj--;
}


if (flag) score += s[k];
}
return score;
}

进一步提高AI智能——应用博弈树

原先的算法只从电脑落子的角度考虑了一步。我们可以从玩家落子的角度再考虑一步,搜索两步。第一步搜电脑落子在该点的score[i][j],记为s1;第二步搜电脑在(i,j)落完子后,玩家落子所能获得的最大score[x][y],记为s2.取使得(s1-s2)的值最大的(i,j)作为电脑该步的落子点。这样我们综合考虑了两点:1.电脑在该步的下法优秀(s1尽量大);2.玩家在该步的最优下法差(s2尽量小),即(s1-s2)的值尽量大。同理可再向下搜第三步(s3尽量大),第四步(s4尽量小)……使(s1-s2+s3-s4……)尽量大,但是综合考虑时间效率,如果向下搜索太多步,程序运行时间较长,搜索两步时从运行时间和下棋智能两个方面综合考虑效果较好。

 

提高AI效率——alpha-Beta剪枝

在博弈树的搜索过程中有些搜索是可以舍弃的,但是博弈树的计分方法必须修改,舍弃(s1-s2+s3-s4……)的计分方式,改为最大/最小的计分方法,只计算底层搜索的分数并且某个父节点的分数等于由它的某个子节点,在这个基础上,我们成功应用了alpha-Beta剪枝,我们通过如下图的启发策略减少了不必要的搜索

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值