目录
一、准备工作
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)三三禁手
由于黑方落一子,同时形成二个或二个以上黑方活三的局面
由于黑方落一子,同时形成二个或二个以上黑方四(活四或者冲四)的局面
由于黑方落一子,形成六个或者六个以上的同色连续棋子
三、双人对弈详细剖析
双人对弈很简单,只需要游戏双方遵守规则落子,当有一方获胜后提示获胜并选择重新开始或退出游戏。
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_LBUTTONDOWN
if (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_LBUTTONDOWN
if (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;
}