C++超详细五子棋游戏(AI实现人机对弈+双人对弈+EasyX图形化界面+详细介绍)
目录
一、准备工作
1、开发环境
2、EasyX的下载和安装
二、游戏规则
1、行棋顺序
2、判断胜负
3、四种重要棋型解释(重点)
4、禁手规则
三、双人对弈详细剖析
1、落子
2、判胜
四、人机对弈超详细剖析
1、整体代码分析
2、玩家落子
3、机器落子
4、判胜
五、图形化界面代码剖析
1、显示菜单
2、打印棋盘
3、右侧工具栏
六、完整代码及超详细注释
1、AI算法
2、AI的打分机制
3、搜索剪枝
4、代码实现
七、运行结果+视频演示
一、准备工作
1、开发环境
- Visual Studio 2013(其他C/C++开发环境也可以)
2、EasyX的下载和安装
1)EasyX简介
EasyX 是针对 C/C++ 的图形库,可以帮助使用C/C++语言的程序员快速上手图形和游戏编程。比如,可以用 VC + EasyX 很快的用几何图形画一个房子,或者一辆移动的小车,可以编写俄罗斯方块、贪吃蛇、黑白棋等小游戏,可以练习图形学的各种算法,等等。
总的来说,EasyX是一款用于C/C++语言的图形化界面的图形库,可以进行基本的图形绘制等。
2)EasyX的下载和安装
官网下载:https://easyx.cn/
下载好后是一个可执行程序,按照安装向导提示安装即可。注意如下问题:
3)EasyX使用
在安装是会有EasyX在线文档选项,建议下载保存,使用时直接查找文档即可。在编程时根据功能需求在网上搜相应的使用接口,在结合文档选择合适的接口即可(这个比较简单,不用花时间去学习,本人也是直接上手的),也可以参考底下原码,有详细注释。
二、游戏规则
了解基本的游戏规则,有助于后边进行AI实现人机对弈算法的理解。
1、行棋顺序
- 在双人对弈中,规定黑棋先行
- 在人机对弈中,规定人是黑子、电脑是白子,并且继续遵守“黑棋先行”规则
2、判断胜负
最先在棋盘横向、竖向、斜向形成连续的相同色五个棋子的一方为胜。黑棋禁手判负,白棋无禁手。黑棋禁手包括三三禁手,四四禁手,长连禁手(在4中进行解释)。如分不出胜负,则定为平局。
3、四种重要棋型解释(重点)
1)五连
五颗同色棋子连在一起,即4个方向的11111这种形式的棋型,当出现五连时必有一方已经获胜。例如:判断胜负中给出的图解的四种情况都算是五连
2)活四
有2个成五点的四颗棋子,即4个方向的011110这种形式的棋型,注意两边一定要有空格。
3)冲四
有1个成五点的四颗棋子,棋型有点多。
4)活三
可以形成活四的三颗棋子,要么是三连的形式,即4个方向的01110这种形式的棋型,要么是非三连的形式,即8个方向的010110这种形式的棋型
PS:这个三连描述的不准确,在01110的两端,必须至少有一个空格。
情况1:
情况2:
情况3:
4、禁手规则
1)三三禁手
由于黑方落一子,同时形成二个或二个以上黑方活三的局面
2)四四禁手
由于黑方落一子,同时形成二个或二个以上黑方四(活四或者冲四)的局面
3)长连禁手
由于黑方落一子,形成六个或者六个以上的同色连续棋子
三、双人对弈详细剖析
双人对弈很简单,只需要游戏双方遵守规则落子,当有一方获胜后提示获胜并选择重新开始或退出游戏。
1、落子
1)获取鼠标信息
落子的过程其实就是一个循环判断当前棋盘上是否有鼠标点击的信息
使用MOUSEMSG实例化出一个ms对象,该对象用于获取当前鼠标信息。注意当没有捕获到鼠标信息时,应一直进行循环检测鼠标信息,直到鼠标点击棋盘开始进行处理。
MOUSEMSG ms;//实例化一个ms对象
ms = GetMouseMsg();//获取鼠标信息保存在ms对象中
2)判断是否可以落子
当使用GetMouseMsg方法获取到鼠标信息时,应该对该信息进行判断,判断该信息到底是点击棋盘还是棋盘右侧的工具栏。当点击的是棋盘的时候,在利用循环判断点击位置是否在棋盘落子范围内,如果是则继续判断该位置是否已经落子。
ms.uMsg == VM_LBUTTONDOWN;表示鼠标点击屏幕
ms.x ms.y分别表示点击的x,y坐标
3)判断该落白子还是黑子
设置两个整型变量play1,play2分别表示白棋和黑棋,初始时play1=1、play2 = 0表示黑棋先行,当黑棋落子后play1=0,play2=1,由此判断当前应该哪一方进行落子。循环整个过程就完成了双人对弈的过程,具体代码如下:
while (win == 0){//判断是否点击右侧工具栏或者棋盘ms = GetMouseMsg();if (ms.uMsg == WM_LBUTTONDOWN){//判断是否点击右侧工具栏buttonRingth(m,ms,win);//判断是否点击棋盘for (int lie = 20; lie <= 490; lie += 30){if (ms.x <= lie + 15 && ms.x >= lie - 15){for (int hang = 20; hang <= 490; hang += 30){if (ms.y <= hang + 15 && ms.y >= hang - 15){if (play1 == 1 && a[hang / 30 - 1][lie / 30 - 1] == 0){setfillcolor(BLACK);solidcircle(lie, hang, 12);a[hang / 30 - 1][lie / 30 - 1] = 1;play1 = 0;break;}if (play1 == 0 && a[hang / 30 - 1][lie / 30 - 1] == 0){setfillcolor(WHITE);solidcircle(lie, hang, 12);a[hang / 30 - 1][lie / 30 - 1] = 2;play1 = 1;break;}}}}}}
2、判胜
在双人对弈中,还有一个重要的部分就是当一个棋子落下后需要判断是否有玩家获胜。具体判胜方法就是,暴力遍历棋盘,判断是否出现五连子的情况,这里五连子分为纵横方向、向左倾斜、向右倾斜三种情况,每种情况又包含了玩家1还是玩家2赢两种情况,因此一共有六中情况,暴力求解代码如下:
int win = 0;//判断是否赢for (int j = 0; j<16 && (win == 0); j++){for (int i = 0; i<16; i++){if ((a[j][i] == 1 && a[j][i + 1] == 1 && a[j][i + 2] == 1 && a[j][i + 3] == 1 && a[j][i + 4] == 1)|| (a[i][j] == 1 && a[i + 1][j] == 1 && a[i + 2][j] == 1 && a[i + 3][j] == 1 && a[i + 4][j] == 1))//横纵是5个子play1 win{win = 1;Sleep(100);break;}if ((a[j][i] == 2 && a[j][i + 1] == 2 && a[j][i + 2] == 2 && a[j][i + 3] == 2 && a[j][i + 4] == 2)|| (a[i][j] == 2 && a[i + 1][j] == 2 && a[i + 2][j] == 2 && a[i + 3][j] == 2 && a[i + 4][j] == 2))//横纵是5个子play2 win{win = 2;Sleep(100);break;}}}for (int j = 0; j<12 && (win == 0); j++){for (int i = 0; i<12; i++){if (a[j][i] == 1 && a[j + 1][i + 1] == 1 && a[j + 2][i + 2] == 1 && a[j + 3][i + 3] == 1 && a[j + 4][i + 4] == 1)//向右倾斜时候play1 win{win = 1;Sleep(100);break;}if (a[j][i] == 2 && a[j + 1][i + 1] == 2 && a[j + 2][i + 2] == 2 && a[j + 3][i + 3] == 2 && a[j + 4][i + 4] == 2)//向右倾斜时候play2 win{win = 2;Sleep(100);break;}}for (int i = 4; i<16 && (win == 0); i++){if (a[j][i] == 1 && a[j + 1][i - 1] == 1 && a[j + 2][i - 2] == 1 && a[j + 3][i - 3] == 1 && a[j + 4][i - 4] == 1)//向左倾斜时候play1 win{win = 1;Sleep(100);break;}if (a[j][i] == 2 && a[j + 1][i - 1] == 2 && a[j + 2][i - 2] == 2 && a[j + 3][i - 3] == 2 && a[j + 4][i - 4] == 2)//向左倾斜时候play2 win{win = 2;Sleep(100);break;}}}return win;
这时,再在落子部分加入判断输赢整个双人对弈就全部完成,其他就是图形化界面设置的了。
注意:判断落子的位置的循环代码中的循环条件的值和棋盘的格子数量和格子大小以及棋盘的和整体布局都由关系。
四、人机对弈超详细剖析
1、整体代码分析
1)利用循环判断玩家是否点击棋盘落子或者点击右侧工具栏
这里继续使用while循环判断玩家是否点击棋盘,当点击棋盘时捕获信息并保存。
2)对玩家的点击做出回应
如果玩家点击棋盘则需要判断是否该玩家落子,如果是正常落子并判断输赢;当玩家点击的是右侧工具栏时,做出相应的回应。
注意:当玩家点击重新开始游戏或者返回菜单时一定要注意置空a数组(后边详细解释)。
3)机器落子
当玩家落子完成后,及其根据一定的算法判断落子位置(需要考虑到该堵死对方棋局还是形成自己棋局)
框架代码如下:
while (win == 0){//判断是否点击右侧工具栏或者棋盘ms = GetMouseMsg();if (ms.uMsg == WM_LBUTTONDOWN){//判断是否点击右侧工具栏buttonRingth(m, ms, win);//判断是否点击棋盘并且判断是否该玩家落子PlayGame(ms,&play1,&play2);//判断玩家是否赢win = Play().Win();if (win == 1){//人赢displayWin(1, 0);break;}else if (win == 2){//电脑赢displayWin(1, 1);break;}}}
2、玩家落子
玩家落子不需要电脑做出过多的判断,程序中只需要判断玩家是否点击棋盘进行落子、落子位置是否合理、落子后玩家是否会赢等情况即可,其他情况均有玩家做出判断。具体实现和双人对弈区别不大:
for (int lie = 20; lie <= 490; lie += 30){if (ms.x <= lie + 15 && ms.x >= lie - 15){for (int hang = 20; hang <= 490; hang += 30){if (ms.y <= hang + 15 && ms.y >= hang - 15){if (*play1 == 1 && a[hang / 30 - 1][lie / 30 - 1] == 0){setfillcolor(BLACK);solidcircle(lie, hang, 12);a[hang / 30 - 1][lie / 30 - 1] = 1;*play1 = 0;break;}}}}}
3、机器落子
1)AI算法
基本思路为“堵”和“找”。堵的意思是当对方落子后,对可能产生上述的冲四、活三、长连禁手(三三禁手、四四禁手比较麻烦,暂不处理)等情况时要进行阻止;找的意思是,当该电脑落子时此时利用“堵”的思路没有落子那么电脑就要找合适的位置落下自己的棋子,这里的合适的位置指的是落下棋子后自己能产生哪几种情况或者说自己可以胜利的情况。如果上述情况都不存在,则随机找到一个没有落子的位置落子即可。
2)代码实现
堵的代码实现
bool chongsi(int *play1)
{//冲四---横纵、斜几个情况进行分析/*横向*/for (int i = 0; i < 16; i++){//判断当前行是否存在连续四个黑子,且该连续四个黑子的左侧或者右侧存在一个白子for (int j = 0; j < 16; j++){if (j <= 12 && a[i][j] == 1){//判断是否会从j开始出现连续四个if (a[i][j + 1] == 1 && a[i][j + 2] == 1 && a[i][j + 3] == 1){//判断该四连的左右是否有白子或者左右已经到达边界if (j + 3 == 15 && a[i][j - 1] == 0){a[i][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + i * 30, 12);return true;//赌成功了}else if (j == 0 && a[i][j + 4] == 0){a[i][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + i * 30, 12);return true;//赌成功了}else if (j < 12 && a[i][j - 1] == 2 && a[i][j + 4] == 0){a[i][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + i * 30, 12);return true;//赌成功了}else if (j > 0 && a[i][j + 4] == 2 && a[i][j - 1] == 0){a[i][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + i * 30, 12);return true;//赌成功了}}}}}/*纵向*/for (int i = 0; i < 16; i++){//判断当前行是否存在连续四个黑子,且该连续四个黑子的左侧或者右侧存在一个白子for (int j = 0; j < 16; j++){if (j <= 12 && a[j][i] == 1){//判断是否会从j开始出现连续四个if (a[j + 1][i] == 1 && a[j + 2][i] == 1 && a[j + 3][i] == 1){if (j == 0 && a[j + 4][i] == 0){a[j + 4][i] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + i * 30, 20 + (j + 4) * 30, 12);return true;//赌成功了}else if (j + 3 == 15 && a[j - 1][i] == 0){a[j - 1][i] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + i * 30, 20 + (j - 1) * 30, 12);return true;//赌成功了}else if (j > 0 && a[j + 4][i] == 2 && a[j - 1][i] == 0){a[j - 1][i] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + i * 30, 20 + (j - 1) * 30, 12);return true;//赌成功了}else if (j < 12 && a[j - 1][i] == 2 && a[j + 4][i] == 0){a[j + 4][i] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + i * 30, 20 + (j + 4) * 30, 12);return true;//赌成功了}}}}}/*左斜*/for (int i = 0; i < 13; i++){for (int j = 3; j < 16; j++){if (!((i == 0 && j == 3) || (i == 12 && j == 15))){if (a[i][j] == 1){if (a[i + 1][j - 1] == 1 && a[i + 2][j - 2] == 1 && a[i + 3][j - 3] == 1){if (i == 0 && a[i + 4][j - 4] == 0){a[i + 4][j - 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i == 12 && a[i - 1][j + 1] == 0){a[i - 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else if (j == 3 && a[i - 1][j + 1] == 0){a[i - 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else if (j == 15 && a[i + 4][j - 4] == 0){a[i + 4][j - 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i < 12 && a[i - 1][j + 1] == 2 && a[i + 4][j - 4] == 0){a[i + 4][j - 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i > 0 && a[i + 4][j - 4] == 2 && a[i - 1][j + 1] == 0){a[i - 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}}}}}}/*右斜*/for (int i = 0; i < 13; i++){for (int j = 0; j < 13; j++){if (!(i == 0 && j == 12) || (i == 12 && j == 0)){if (a[i][j] == 1){if (a[i + 1][j + 1] == 1 && a[i + 2][j + 2] == 1 && a[i + 3][j + 3] == 1){if (i == 0 && a[i + 4][j + 4] == 0){a[i + 4][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i == 12 && a[i - 1][j - 1] == 0){a[i - 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else if (j == 12 && a[i - 1][j - 1] == 0){a[i - 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else if (j == 0 && a[i + 4][j + 4] == 0){a[i + 4][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (j < 12 && a[i - 1][j - 1] == 2 && a[i + 4][j + 4] == 0){a[i + 4][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i > 0 && a[i + 4][j + 4] == 2 && a[i - 1][j - 1] == 0){a[i - 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}}}}}}return false;
}//活三
bool huosan(int* play1)
{//三连两边都有空格/*横向*/for (int i = 0; i < 16; i++){for (int j = 1; j < 13; j++){if (a[i][j] == 1){if (a[i][j + 1] == 1 && a[i][j + 2] == 1){if (a[i][j - 1] == 0 && a[i][j + 3] == 0){if (j == 1 || j != 12){//必然堵右边a[i][j + 3] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 3) * 30, 20 + i * 30, 12);return true;//赌成功了}if (j == 12){//必然堵左边a[i][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + i * 30, 12);return true;//赌成功了}}}}}}/*纵向*/for (int j = 0; j < 16; j++){for (int i = 1; i < 13; i++){if (a[i][j] == 1){if (a[i + 1][j] == 1 && a[i + 2][j] == 1){if (a[i - 1][j] == 0 && a[i + 3][j] == 0){if (i == 1 || i != 12){a[i + 3][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + (i+3) * 30, 12);return true;//赌成功了}else if (i == 12){a[i - 1][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + (i-1) * 30, 12);return true;//赌成功了}}}}}}/*左斜*/for (int i = 1; i < 13; i++){for (int j = 3; j < 15; j++){if (a[i][j] == 1){if (a[i + 1][j - 1] == 1 && a[i + 2][j - 2] == 1){if (a[i - 1][j + 1] == 0 && a[i + 3][j - 3] == 0){cout << i <<" "<<j<< endl;if (i == 12){//必然堵上边a[i - 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j+1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else{//赌下边a[i + 3][j - 3] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j-3) * 30, 20 + (i + 3) * 30, 12);return true;//赌成功了}}}}}}/*右斜*/for (int i = 1; i < 13; i++){for (int j = 1; j < 13; j++){if (a[i][j] == 1){if (a[i + 1][j + 1] == 1 && a[i + 2][j + 2] == 1){if (a[i + 3][j + 3] == 0 && a[i - 1][j - 1] == 0){if (i == 1){//赌下边a[i + 3][j + 3] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 3) * 30, 20 + (i + 3) * 30, 12);return true;//赌成功了}else{//堵上边a[i - 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}}}}}}//两连空一个在有一个且两边有空格/*横向*/for (int i = 0; i < 16; i++){for (int j = 1; j < 12; j++){if (a[i][j] == 1){if (a[i][j + 1] == 1 && a[i][j + 2] == 0 && a[i][j + 3] == 1){if (a[i][j - 1] == 0 && a[i][j + 4] == 0){a[i][j + 2] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 2) * 30, 20 + i * 30, 12);return true;//赌成功了}}else if (a[i][j + 1] == 0 && a[i][j + 2] == 1 && a[i][j + 3] == 1){if (a[i][j - 1] == 0 && a[i][j + 4] == 0){a[i][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + i * 30, 12);return true;//赌成功了}}}}}/*纵向*/for (int j = 0; j < 16; j++){for (int i = 1; i < 12; i++){if (a[i][j] == 1){if (a[i + 1][j] == 1 && a[i + 2][j] == 0 && a[i + 3][j] == 1){if (a[i - 1][j] == 0 && a[i + 4][j] == 0){a[i + 2][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + (i+2) * 30, 12);return true;//赌成功了}}else if (a[i + 1][j] == 0 && a[i + 2][j] == 1 && a[i + 3][j] == 1){if (a[i - 1][j] == 0 && a[i + 4][j] == 0){a[i + 1][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + (i+1) * 30, 12);return true;//赌成功了}}}}}/*左斜*/for (int i = 1; i < 12; i++){for (int j = 4; j < 15; j++){if (a[i][j] == 1){if (a[i + 1][j - 1] == 0 && a[i + 2][j - 2] == 1 && a[i + 3][j - 3] == 1){if (a[i - 1][j + 1] == 0 && a[i + 4][j - 4] == 0){a[i + 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j-1) * 30, 20 + (i + 1) * 30, 12);return true;//赌成功了}}else if (a[i + 1][j - 1] == 1 && a[i + 2][j - 2] == 0 && a[i + 3][j - 3] == 1){if (a[i - 1][j + 1] == 0 && a[i + 4][j - 4] == 0){a[i+2][j - 2] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j-2) * 30, 20 + (i + 2) * 30, 12);return true;//赌成功了}}}}}/*右斜*/for (int i = 1; i < 12; i++){for (int j = 1; j < 12; j++){if (a[i][j] == 1){if (a[i + 1][j + 1] == 0 && a[i + 2][j + 2] == 1 && a[i + 3][j + 3] == 1){if (a[i - 1][j - 1] == 0 && a[i + 4][j + 4] == 0){a[i + 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + (i + 1) * 30, 12);return true;//赌成功了}}else if (a[i + 1][j + 1] == 1 && a[i + 2][j + 2] == 0 && a[i + 3][j + 3] == 1){if (a[i - 1][j - 1] == 0 && a[i + 4][j + 4] == 0){a[i + 2][j + 2] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 2) * 30, 20 + (i + 2) * 30, 12);return true;//赌成功了}}}}}return false;
}//赌对方棋局---冲四、活三、长连禁手(三三禁手、四四禁手比较麻烦,暂不处理)
bool du(int* play1)
{//冲四---横纵、斜几个情况进行分析return chongsi(play1) || huosan(play1);
}
找的代码实现
随机落子的代码实现
4、判胜
这里判胜和双人对弈判胜一样,继续使用暴力搜索查找即可。
五、图形化界面代码剖析
1、显示菜单
利用EasyX将提前准备好的菜单图片显示在显示器,用户点击相应功能进行跳转。
initgraph初始化绘图窗口接口
/*设置背景图*/
IMAGE img;
//缩放因子,例如设置宽度为100的单元格,实际的绘制宽度为(100*缩放因子)
setaspectratio(1.1, 1);
//从图片文件获取图像(图像的image指针,图像名,资源名称,图片的拉伸宽度、高度,是否自适应图片大小)
loadimage(&img, "begin.jpg", 377, 624, 1);
putimage(0, 0, &img);
具体代码实现
while (true){m = GetMouseMsg();//获取鼠标消息//左键按下:WM_LBUTTONDOWNif (m.uMsg == WM_LBUTTONDOWN && (m.x >= 72 && m.x <= 307 && m.y >= 340 && m.y <= 400|| m.x >= 72 && m.x <= 307 && m.y >= 420 && m.y <= 480)){//uMsg鼠标信息 WM_MOUSEMOVE鼠标移动消息 x y表示鼠标位置坐标//当鼠标在"人机对战、双人对战"上时,显示红色边框if (m.x >= 72 && m.x <= 307 && m.y >= 340 && m.y <= 400){setlinecolor(YELLOW);setlinestyle(PS_SOLID | PS_JOIN_ROUND, 2);//空心矩形框rectangle(72, 340, 300, 400);}else if (m.x >= 72 && m.x <= 307 && m.y >= 420 && m.y <= 480){setlinecolor(YELLOW);//空心矩形框rectangle(72, 420, 300, 480);}Sleep(500);//清除屏幕内容cleardevice();//休眠五秒Sleep(300);//关闭窗口closegraph();//使用匿名对象打开棋盘界面Menu().ChessBoard(m);break;}}
2、打印棋盘
但因棋盘其实就是使用画线接口将棋盘分割成小方格即可。
setlinecolor(WHITE);//线条颜色
line(20,i,470,i);//线条位置及长度
line(i,20,i,470);
//绘制棋盘while (true){for (int i = 20; i <= 470; i+=30){setlinecolor(WHITE);line(20,i,470,i);line(i,20,i,470);}//如果左键双人,跳入双人游戏if (m.uMsg == WM_LBUTTONDOWN && m.x >= 72 && m.x <= 307 && m.y >= 420 && m.y <= 480){Play().TwoPlayerGame(m);}else{Play().ComputerUserGame(m);}}
3、右侧工具栏
棋盘一共分成左右两部分,右侧工具栏区要注意,当玩家点击重新开始时不仅要重新显示棋盘还需要将保存棋子位置的数组a置空,防止上次的数据还保存在a中,导致判断失败。
if (ms.x >= 500 && ms.x <= 655 && ms.y >= 30 && ms.y <= 80){memset(a, 0, sizeof(a));//重新开始setlinecolor(RED);//空心矩形框rectangle(500, 30, 655, 80);Sleep(300);Menu().ChessBoard(m);}else if (ms.x >= 500 && ms.x <= 655 && ms.y >= 115 && ms.y <= 165){memset(a, 0, sizeof(a));//返回菜单setlinecolor(RED);//空心矩形框rectangle(500, 115, 655, 165);Sleep(300);Menu().Display();}else if (win == 0 && ms.x >= 500 && ms.x <= 655 && ms.y >= 200 && ms.y <= 250){//悔棋setlinecolor(RED);//空心矩形框rectangle(500, 200, 655, 250);}
六、完整代码及超详细注释
头文件
#include<graphics.h>
#include<conio.h>
#include<windows.h>
#pragma warning(disable:4996)class Menu
{
public:void Display();void ChessBoard(MOUSEMSG m);
};class Play
{
public:void TwoPlayerGame(MOUSEMSG m);void ComputerUserGame(MOUSEMSG m);void buttonRingth(MOUSEMSG m,MOUSEMSG ms, int win);//判断是否点击右侧工具栏void displayWin(int n1, int n2);//显示哪一方赢了,n1为0表示双人为1表示人机,n2为0表示黑、人为1表示白、机void PlayGame(MOUSEMSG ms,int* play1,int* play2);int Win();
};
.cpp文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"Goban.h"int a[16][16] = {0};bool chongsi(int *play1)
{//冲四---横纵、斜几个情况进行分析/*横向*/for (int i = 0; i < 16; i++){//判断当前行是否存在连续四个黑子,且该连续四个黑子的左侧或者右侧存在一个白子for (int j = 0; j < 16; j++){if (j <= 12 && a[i][j] == 1){//判断是否会从j开始出现连续四个if (a[i][j + 1] == 1 && a[i][j + 2] == 1 && a[i][j + 3] == 1){//判断该四连的左右是否有白子或者左右已经到达边界if (j + 3 == 15 && a[i][j - 1] == 0){a[i][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + i * 30, 12);return true;//赌成功了}else if (j == 0 && a[i][j + 4] == 0){a[i][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + i * 30, 12);return true;//赌成功了}else if (j < 12 && a[i][j - 1] == 2 && a[i][j + 4] == 0){a[i][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + i * 30, 12);return true;//赌成功了}else if (j > 0 && a[i][j + 4] == 2 && a[i][j - 1] == 0){a[i][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + i * 30, 12);return true;//赌成功了}}}}}/*纵向*/for (int i = 0; i < 16; i++){//判断当前行是否存在连续四个黑子,且该连续四个黑子的左侧或者右侧存在一个白子for (int j = 0; j < 16; j++){if (j <= 12 && a[j][i] == 1){//判断是否会从j开始出现连续四个if (a[j + 1][i] == 1 && a[j + 2][i] == 1 && a[j + 3][i] == 1){if (j == 0 && a[j + 4][i] == 0){a[j + 4][i] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + i * 30, 20 + (j + 4) * 30, 12);return true;//赌成功了}else if (j + 3 == 15 && a[j - 1][i] == 0){a[j - 1][i] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + i * 30, 20 + (j - 1) * 30, 12);return true;//赌成功了}else if (j > 0 && a[j + 4][i] == 2 && a[j - 1][i] == 0){a[j - 1][i] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + i * 30, 20 + (j - 1) * 30, 12);return true;//赌成功了}else if (j < 12 && a[j - 1][i] == 2 && a[j + 4][i] == 0){a[j + 4][i] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + i * 30, 20 + (j + 4) * 30, 12);return true;//赌成功了}}}}}/*左斜*/for (int i = 0; i < 13; i++){for (int j = 3; j < 16; j++){if (!((i == 0 && j == 3) || (i == 12 && j == 15))){if (a[i][j] == 1){if (a[i + 1][j - 1] == 1 && a[i + 2][j - 2] == 1 && a[i + 3][j - 3] == 1){if (i == 0 && a[i + 4][j - 4] == 0){a[i + 4][j - 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i == 12 && a[i - 1][j + 1] == 0){a[i - 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else if (j == 3 && a[i - 1][j + 1] == 0){a[i - 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else if (j == 15 && a[i + 4][j - 4] == 0){a[i + 4][j - 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i < 12 && a[i - 1][j + 1] == 2 && a[i + 4][j - 4] == 0){a[i + 4][j - 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i > 0 && a[i + 4][j - 4] == 2 && a[i - 1][j + 1] == 0){a[i - 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}}}}}}/*右斜*/for (int i = 0; i < 13; i++){for (int j = 0; j < 13; j++){if (!(i == 0 && j == 12) || (i == 12 && j == 0)){if (a[i][j] == 1){if (a[i + 1][j + 1] == 1 && a[i + 2][j + 2] == 1 && a[i + 3][j + 3] == 1){if (i == 0 && a[i + 4][j + 4] == 0){a[i + 4][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i == 12 && a[i - 1][j - 1] == 0){a[i - 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else if (j == 12 && a[i - 1][j - 1] == 0){a[i - 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else if (j == 0 && a[i + 4][j + 4] == 0){a[i + 4][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (j < 12 && a[i - 1][j - 1] == 2 && a[i + 4][j + 4] == 0){a[i + 4][j + 4] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 4) * 30, 20 + (i + 4) * 30, 12);return true;//赌成功了}else if (i > 0 && a[i + 4][j + 4] == 2 && a[i - 1][j - 1] == 0){a[i - 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}}}}}}return false;
}//活三
bool huosan(int* play1)
{//三连两边都有空格/*横向*/for (int i = 0; i < 16; i++){for (int j = 1; j < 13; j++){if (a[i][j] == 1){if (a[i][j + 1] == 1 && a[i][j + 2] == 1){if (a[i][j - 1] == 0 && a[i][j + 3] == 0){if (j == 1 || j != 12){//必然堵右边a[i][j + 3] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 3) * 30, 20 + i * 30, 12);return true;//赌成功了}if (j == 12){//必然堵左边a[i][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + i * 30, 12);return true;//赌成功了}}}}}}/*纵向*/for (int j = 0; j < 16; j++){for (int i = 1; i < 13; i++){if (a[i][j] == 1){if (a[i + 1][j] == 1 && a[i + 2][j] == 1){if (a[i - 1][j] == 0 && a[i + 3][j] == 0){if (i == 1 || i != 12){a[i + 3][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + (i+3) * 30, 12);return true;//赌成功了}else if (i == 12){a[i - 1][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + (i-1) * 30, 12);return true;//赌成功了}}}}}}/*左斜*/for (int i = 1; i < 13; i++){for (int j = 3; j < 15; j++){if (a[i][j] == 1){if (a[i + 1][j - 1] == 1 && a[i + 2][j - 2] == 1){if (a[i - 1][j + 1] == 0 && a[i + 3][j - 3] == 0){//cout << i <<" "<<j<< endl;if (i == 12){//必然堵上边a[i - 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j+1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}else{//赌下边a[i + 3][j - 3] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j-3) * 30, 20 + (i + 3) * 30, 12);return true;//赌成功了}}}}}}/*右斜*/for (int i = 1; i < 13; i++){for (int j = 1; j < 13; j++){if (a[i][j] == 1){if (a[i + 1][j + 1] == 1 && a[i + 2][j + 2] == 1){if (a[i + 3][j + 3] == 0 && a[i - 1][j - 1] == 0){if (i == 1){//赌下边a[i + 3][j + 3] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 3) * 30, 20 + (i + 3) * 30, 12);return true;//赌成功了}else{//堵上边a[i - 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j - 1) * 30, 20 + (i - 1) * 30, 12);return true;//赌成功了}}}}}}//两连空一个在有一个且两边有空格/*横向*/for (int i = 0; i < 16; i++){for (int j = 1; j < 12; j++){if (a[i][j] == 1){if (a[i][j + 1] == 1 && a[i][j + 2] == 0 && a[i][j + 3] == 1){if (a[i][j - 1] == 0 && a[i][j + 4] == 0){a[i][j + 2] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 2) * 30, 20 + i * 30, 12);return true;//赌成功了}}else if (a[i][j + 1] == 0 && a[i][j + 2] == 1 && a[i][j + 3] == 1){if (a[i][j - 1] == 0 && a[i][j + 4] == 0){a[i][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + i * 30, 12);return true;//赌成功了}}}}}/*纵向*/for (int j = 0; j < 16; j++){for (int i = 1; i < 12; i++){if (a[i][j] == 1){if (a[i + 1][j] == 1 && a[i + 2][j] == 0 && a[i + 3][j] == 1){if (a[i - 1][j] == 0 && a[i + 4][j] == 0){a[i + 2][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + (i+2) * 30, 12);return true;//赌成功了}}else if (a[i + 1][j] == 0 && a[i + 2][j] == 1 && a[i + 3][j] == 1){if (a[i - 1][j] == 0 && a[i + 4][j] == 0){a[i + 1][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + (i+1) * 30, 12);return true;//赌成功了}}}}}/*左斜*/for (int i = 1; i < 12; i++){for (int j = 4; j < 15; j++){if (a[i][j] == 1){if (a[i + 1][j - 1] == 0 && a[i + 2][j - 2] == 1 && a[i + 3][j - 3] == 1){if (a[i - 1][j + 1] == 0 && a[i + 4][j - 4] == 0){a[i + 1][j - 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j-1) * 30, 20 + (i + 1) * 30, 12);return true;//赌成功了}}else if (a[i + 1][j - 1] == 1 && a[i + 2][j - 2] == 0 && a[i + 3][j - 3] == 1){if (a[i - 1][j + 1] == 0 && a[i + 4][j - 4] == 0){a[i+2][j - 2] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j-2) * 30, 20 + (i + 2) * 30, 12);return true;//赌成功了}}}}}/*右斜*/for (int i = 1; i < 12; i++){for (int j = 1; j < 12; j++){if (a[i][j] == 1){if (a[i + 1][j + 1] == 0 && a[i + 2][j + 2] == 1 && a[i + 3][j + 3] == 1){if (a[i - 1][j - 1] == 0 && a[i + 4][j + 4] == 0){a[i + 1][j + 1] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 1) * 30, 20 + (i + 1) * 30, 12);return true;//赌成功了}}else if (a[i + 1][j + 1] == 1 && a[i + 2][j + 2] == 0 && a[i + 3][j + 3] == 1){if (a[i - 1][j - 1] == 0 && a[i + 4][j + 4] == 0){a[i + 2][j + 2] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + (j + 2) * 30, 20 + (i + 2) * 30, 12);return true;//赌成功了}}}}}return false;
}//赌对方棋局---冲四、活三、长连禁手(三三禁手、四四禁手比较麻烦,暂不处理)
bool du(int* play1)
{//冲四---横纵、斜几个情况进行分析return chongsi(play1) || huosan(play1);
}bool zhao(int* play1)
{//思路:找到自己的棋子,连的最多的且可以组成五个的for (int i = 0; i < 16; i++){for (int j = 0; j < 16; j++){if (a[i][j] == 2){/*横向*/if (*play1 == 0){if (j < 12 && (i == 0 || a[i - 1][j] == 1)){//只能向右判断if (a[i][j+1] != 1 && a[i][j+2] != 1 && a[i ][j+3] != 1 && a[i][j+4] != 1){for (int k = j + 1; k <= j + 4; k++){if (a[i][k] == 0){a[i][k] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + k * 30, 20 + i * 30, 12);return true;//找成功了}}}}else if ((j > 3) && (i == 15 || a[i+1][j] == 1)){//只能向左判断if (a[i][j - 1] != 1 && a[i][j - 2] != 1 && a[i][j - 3] != 1 && a[i][j - 4] != 1){for (int k = j - 1; k >= j - 4; k--){if (a[i][k] == 0){a[i][k] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + k * 30, 20 + i * 30, 12);return true;//找成功了}}}}}}}}return false;
}void Play::PlayGame(MOUSEMSG ms, int* play1, int* play2)
{//人走int success = 1;while (success){ms = GetMouseMsg();for (int lie = 20; lie <= 490; lie += 30){if (ms.x <= lie + 15 && ms.x >= lie - 15){for (int hang = 20; hang <= 490; hang += 30){if (ms.y <= hang + 15 && ms.y >= hang - 15){if (*play1 == 1 && a[hang / 30][lie / 30] == 0){setfillcolor(BLACK);solidcircle(lie, hang, 12);a[hang / 30][lie / 30] = 1;cout << hang / 30 << " " << lie / 30 << endl;*play1 = 0;success = 0;break;}}}}}}//电脑走/*思路:遍历棋盘查找对方是否存在成功的可能,如果有堵住对方;如果没有,找自己即将能成功的位置落子*/if (du(play1) == false){//找自己可以成的位置,如果没有随机落子if (zhao(play1) == false){//cout << *play1 << endl;for (int i = 7; i < 16; i++){for (int j = 7; j < 14; j++){if (a[i][j] == 0){a[i][j] = 2;*play1 = 1;setfillcolor(WHITE);solidcircle(20 + j * 30, 20 + i* 30, 12);return;}}}}}
}void Menu::Display()
{//初始化绘图窗口initgraph(416, 624, SHOWCONSOLE);/*设置背景图*/IMAGE img;//缩放因子,例如设置宽度为100的单元格,实际的绘制宽度为(100*缩放因子)setaspectratio(1.1, 1);//从图片文件获取图像(图像的image指针,图像名,资源名称,图片的拉伸宽度、高度,是否自适应图片大小)loadimage(&img, "begin.jpg", 377, 624, 1);putimage(0, 0, &img);/*控制鼠标移动操作*/MOUSEMSG m;//鼠标操作while (true){m = GetMouseMsg();//获取鼠标消息//左键按下:WM_LBUTTONDOWNif (m.uMsg == WM_LBUTTONDOWN && (m.x >= 72 && m.x <= 307 && m.y >= 340 && m.y <= 400|| m.x >= 72 && m.x <= 307 && m.y >= 420 && m.y <= 480)){//uMsg鼠标信息 WM_MOUSEMOVE鼠标移动消息 x y表示鼠标位置坐标//当鼠标在"人机对战、双人对战"上时,显示红色边框if (m.x >= 72 && m.x <= 307 && m.y >= 340 && m.y <= 400){setlinecolor(YELLOW);setlinestyle(PS_SOLID | PS_JOIN_ROUND, 2);//空心矩形框rectangle(72, 340, 300, 400);}else if (m.x >= 72 && m.x <= 307 && m.y >= 420 && m.y <= 480){setlinecolor(YELLOW);//空心矩形框rectangle(72, 420, 300, 480);}Sleep(500);//清除屏幕内容cleardevice();//休眠五秒Sleep(300);//关闭窗口closegraph();//使用匿名对象打开棋盘界面Menu().ChessBoard(m);break;}}
}void Menu::ChessBoard(MOUSEMSG m)
{//初始化绘图窗口initgraph(665,490, SHOWCONSOLE);/*设置棋盘背景背景图*/IMAGE img;//缩放因子,例如设置宽度为100的单元格,实际的绘制宽度为(100*缩放因子)//setaspectratio(1.1, 1);//从图片文件获取图像(图像的image指针,图像名,资源名称,图片的拉伸宽度、高度,是否自适应图片大小)loadimage(&img, "chessBoard.jpg", 665,490);putimage(0, 0, &img);//绘制棋盘while (true){for (int i = 20; i <= 470; i+=30){setlinecolor(WHITE);line(20,i,470,i);line(i,20,i,470);}//如果左键双人,跳入双人游戏if (m.uMsg == WM_LBUTTONDOWN && m.x >= 72 && m.x <= 307 && m.y >= 420 && m.y <= 480){Play().TwoPlayerGame(m);}else{Play().ComputerUserGame(m);}}
}void Play::buttonRingth(MOUSEMSG m,MOUSEMSG ms, int win)
{if (ms.x >= 500 && ms.x <= 655 && ms.y >= 30 && ms.y <= 80){memset(a, 0, sizeof(a));//重新开始setlinecolor(RED);//空心矩形框rectangle(500, 30, 655, 80);Sleep(300);Menu().ChessBoard(m);}else if (ms.x >= 500 && ms.x <= 655 && ms.y >= 115 && ms.y <= 165){memset(a, 0, sizeof(a));//返回菜单setlinecolor(RED);//空心矩形框rectangle(500, 115, 655, 165);Sleep(300);Menu().Display();}else if (win == 0 && ms.x >= 500 && ms.x <= 655 && ms.y >= 200 && ms.y <= 250){//悔棋setlinecolor(RED);//空心矩形框rectangle(500, 200, 655, 250);}
}void Play::displayWin(int n1,int n2)
{memset(a,0,sizeof(a));//显示哪一方赢了,n1为0表示双人为1表示人机,n2为0表示黑、人为1表示白、机IMAGE img;// 读取图片至绘图窗口if (n1 == 0 && n2 == 0)loadimage(&img, "blackWin.jpg",306,141);if (n1 == 0 && n2 == 1)loadimage(&img, "whiteWin.jpg", 306, 141);if (n1 == 1 && n2 == 0)loadimage(&img, "youWin.jpg", 306, 141);if (n1 == 1 && n2 == 1)loadimage(&img, "computerWin.jpg", 306, 141);putimage(100, 200, &img);MOUSEMSG m;//鼠标操作while (1){m = GetMouseMsg();if (m.uMsg == WM_LBUTTONDOWN && m.x >= 215 && m.x <= 270 && m.y >= 285 && m.y <= 320){setlinecolor(YELLOW);//空心矩形框rectangle(215, 285, 270, 320);Sleep(300);Menu().Display();break;}else if (m.uMsg == WM_LBUTTONDOWN)exit(0);}
}void Play::TwoPlayerGame(MOUSEMSG m)
{int win = 0;int play1 = 1, play2 = 0;MOUSEMSG ms;一直获取鼠标信息,判断操做while (win == 0){//判断是否点击右侧工具栏或者棋盘ms = GetMouseMsg();if (ms.uMsg == WM_LBUTTONDOWN){//判断是否点击右侧工具栏buttonRingth(m,ms,win);//判断是否点击棋盘for (int lie = 20; lie <= 490; lie += 30){if (ms.x <= lie + 15 && ms.x >= lie - 15){for (int hang = 20; hang <= 490; hang += 30){if (ms.y <= hang + 15 && ms.y >= hang - 15){if (play1 == 1 && a[hang / 30 - 1][lie / 30 - 1] == 0){setfillcolor(BLACK);solidcircle(lie, hang, 12);a[hang / 30 - 1][lie / 30 - 1] = 1;play1 = 0;break;}if (play1 == 0 && a[hang / 30 - 1][lie / 30 - 1] == 0){setfillcolor(WHITE);solidcircle(lie, hang, 12);a[hang / 30 - 1][lie / 30 - 1] = 2;play1 = 1;break;}}}}}//判断玩家是否赢win = Play().Win();if (win == 1){//黑棋赢displayWin(0,0);break;}else if (win == 2){//白棋赢displayWin(0,1);break;}}}
}void Play::ComputerUserGame(MOUSEMSG m)
{int win = 0;int play1 = 1, play2 = 0;//play1表示玩家,play2表示电脑,每次玩家先落子MOUSEMSG ms;一直获取鼠标信息,判断操做while (win == 0){//判断是否点击右侧工具栏或者棋盘ms = GetMouseMsg();if (ms.uMsg == WM_LBUTTONDOWN){//判断是否点击右侧工具栏buttonRingth(m, ms, win);//判断是否点击棋盘并且判断是否该玩家落子PlayGame(ms,&play1,&play2);//判断玩家是否赢win = Play().Win();if (win == 1){//人赢displayWin(1, 0);break;}else if (win == 2){//电脑赢displayWin(1, 1);break;}}}
}int Play::Win()
{int win = 0;//判断是否赢for (int j = 0; j<16 && (win == 0); j++){for (int i = 0; i<16; i++){if ((a[j][i] == 1 && a[j][i + 1] == 1 && a[j][i + 2] == 1 && a[j][i + 3] == 1 && a[j][i + 4] == 1)|| (a[i][j] == 1 && a[i + 1][j] == 1 && a[i + 2][j] == 1 && a[i + 3][j] == 1 && a[i + 4][j] == 1))//横纵是5个子play1 win{win = 1;Sleep(100);break;}if ((a[j][i] == 2 && a[j][i + 1] == 2 && a[j][i + 2] == 2 && a[j][i + 3] == 2 && a[j][i + 4] == 2)|| (a[i][j] == 2 && a[i + 1][j] == 2 && a[i + 2][j] == 2 && a[i + 3][j] == 2 && a[i + 4][j] == 2))//横纵是5个子play2 win{win = 2;Sleep(100);break;}}}for (int j = 0; j<12 && (win == 0); j++){for (int i = 0; i<12; i++){if (a[j][i] == 1 && a[j + 1][i + 1] == 1 && a[j + 2][i + 2] == 1 && a[j + 3][i + 3] == 1 && a[j + 4][i + 4] == 1)//向右倾斜时候play1 win{win = 1;Sleep(100);break;}if (a[j][i] == 2 && a[j + 1][i + 1] == 2 && a[j + 2][i + 2] == 2 && a[j + 3][i + 3] == 2 && a[j + 4][i + 4] == 2)//向右倾斜时候play2 win{win = 2;Sleep(100);break;}}for (int i = 4; i<16 && (win == 0); i++){if (a[j][i] == 1 && a[j + 1][i - 1] == 1 && a[j + 2][i - 2] == 1 && a[j + 3][i - 3] == 1 && a[j + 4][i - 4] == 1)//向左倾斜时候play1 win{win = 1;Sleep(100);break;}if (a[j][i] == 2 && a[j + 1][i - 1] == 2 && a[j + 2][i - 2] == 2 && a[j + 3][i - 3] == 2 && a[j + 4][i - 4] == 2)//向左倾斜时候play2 win{win = 2;Sleep(100);break;}}}return win;
}
main函数
#define _CRT_SECURE_NO_WARNINGS 1
#include"Goban.h"int main()
{Menu m;m.Display();return 0;
}
七、运行结果+视频演示
需要原图片或者有问题可以关注私聊!!!
C++超详细五子棋游戏(AI实现人机对弈+双人对弈+EasyX图形化界面+详细介绍)相关推荐
- Win10安装Ubuntu子系统及图形化界面详细教程20210401
Win10安装Ubuntu子系统及图形化界面详细教程 WSL(Windows Subsystem for Linux),顾名思义就是Windows中可以用Linux了,当然命令也会丰富更多,尤其是WS ...
- Win10安装Ubuntu子系统及图形化界面详细教程
在准备进行安装之前,推荐C盘上至少有5G的空余空间. 1 win10设置 打开两个设置: 1.开发人员模式: 2.启用子系统功能 2 安装 打开Microsoft Store,搜索Ubuntu,出现如 ...
- 基于linux的qt五子棋小游戏下载,课内资源 - 基于Qt的图形化界面网络在线对战五子棋游戏...
一 需求分析 本软件是一款跨平台的网络实时五子棋对战软件,实现建立主机和连接主机.实时对战.判断输赢和危险提示等功能.支持Windows . Linux和OSX平台. 程序主要功能如下: 建立服务器 ...
- linux红帽系统、图形化界面详细安装教程
1.挂载光盘 mount /dev/cdrom /mnt/ #挂载光盘到/mnt/目录下 mkdir /opt/package/ #创建package目录 cp -rf /mnt/* /opt/pac ...
- 五子棋游戏Java代码简单实现(含活动图和类图设计)
五子棋游戏Java代码简单实现(含活动图和类图设计) 文章目录 五子棋游戏Java代码简单实现(含活动图和类图设计) 活动图设计 类图设计 代码实现 总结 OOA和OOD设计 代码设计 可改进部分 活 ...
- c语言编程游戏界面,震惊!!!一个关于c语言图形化界面编程的小游戏-Go语言中文社区...
关于C语言的图形化界面编程 第一个小程序<飞翔的小鸟> 效果图 本人也是小白,大家轻点喷!!!! 下面是源码 作者: @追风 #include #include #include #inc ...
- Python-Tkinter图形化界面设计(详细教程 )
原文链接:https://www.jianshu.com/p/91844c5bca78 声明:本篇文章为转载自https://www.jianshu.com/p/91844c5bca78,在原作者的基 ...
- 震惊!!!一个关于c语言图形化界面编程的小游戏
关于C语言的图形化界面编程 第一个小程序<飞翔的小鸟> 效果图 本人也是小白,大家轻点喷!!!! 下面是源码 作者: @追风#include<graphics.h> #incl ...
- 双人弹球小游戏 (基于Java图形化界面编程)
用户界面如下 : 玩法:双方玩家可以分别控制A-D键和←-→键来进行各自球拍的位置,如果某方没有接住小球,则对方获胜,游戏结束. 代码如下: import javax.swing.*; import ...
- 迷宫游戏(图形化界面)
迷宫游戏 本程序的功能为实现迷宫游戏.打开游戏,系统弹出游戏菜单界面.玩家可以选择开始游戏,游戏设置,退出游戏.玩家选择开始游戏时,系统自动生成一个规格为10*10,入口为左上角,出口为右下角且从入口 ...
最新文章
- Equifax再陷风波:一门户网站管理员密码是admin/admin
- 加密和解密算法 Asp.net
- 使用OpenCV玩家营造出一个视频控制(没有声音)
- flash写保护原理_为什么固态会掉盘?著名的30分钟大法修复是什么原理?
- css 清除浮动float 嗒嘀嗒滴 ----20181120
- 初学ActionScript 3.0(一):Hello World
- UVA 12716 GCD XOR(数论+枚举+打表)
- kvm 调试内核方法
- Python 实现进程间通信(网络编程)
- 关于JS特效的兼容问题。
- 麦克纳姆轮全向移动机器人速度分解
- linux内核中led驱动的分布,Linux内核模块驱动之---led驱动
- 正则表达式 10. 分组可选
- 转自《编程世界》一篇让我震憾的文章
- 360浏览器邮件扩展添加企业邮箱
- 千里达v1000时速_《美骑评测》第10期 千里达V1000山地车 评测
- 用于NIR-II成像的小分子染料(CH1055)
- 浅谈打印机驱动安装的常见方法及安全防护
- C64+系列DSP的总结
- 【MySQL】不建议使用分区表