目录
一、准备工作
1、开发环境
2、EasyX的下载和安装
二、游戏规则
1、行棋顺序
2、判断胜负
3、四种重要棋型解释(重点)
4、禁手规则
三、双人对弈详细剖析
1、落子
2、判胜
四、人机对弈超详细剖析
1、整体代码分析
2、玩家落子
3、机器落子
4、判胜
五、图形化界面代码剖析
1、显示菜单
2、打印棋盘
3、右侧工具栏
六、完整代码及超详细注释
1、AI算法
2、AI的打分机制
3、搜索剪枝
4、代码实现
七、运行结果+视频演示
1)EasyX简介
EasyX 是针对 C/C++ 的图形库,可以帮助使用C/C++语言的程序员快速上手图形和游戏编程。比如,可以用 VC + EasyX 很快的用几何图形画一个房子,或者一辆移动的小车,可以编写俄罗斯方块、贪吃蛇、黑白棋等小游戏,可以练习图形学的各种算法,等等。
总的来说,EasyX是一款用于C/C++语言的图形化界面的图形库,可以进行基本的图形绘制等。
2)EasyX的下载和安装
官网下载:https://easyx.cn/
下载好后是一个可执行程序,按照安装向导提示安装即可。注意如下问题:
3)EasyX使用
在安装是会有EasyX在线文档选项,建议下载保存,使用时直接查找文档即可。在编程时根据功能需求在网上搜相应的使用接口,在结合文档选择合适的接口即可(这个比较简单,不用花时间去学习,本人也是直接上手的),也可以参考底下原码,有详细注释。
了解基本的游戏规则,有助于后边进行AI实现人机对弈算法的理解。
最先在棋盘横向、竖向、斜向形成连续的相同色五个棋子的一方为胜。黑棋禁手判负,白棋无禁手。黑棋禁手包括三三禁手,四四禁手,长连禁手(在4中进行解释)。如分不出胜负,则定为平局。
1)五连
五颗同色棋子连在一起,即4个方向的11111这种形式的棋型,当出现五连时必有一方已经获胜。例如:判断胜负中给出的图解的四种情况都算是五连
2)活四
有2个成五点的四颗棋子,即4个方向的011110这种形式的棋型,注意两边一定要有空格。
3)冲四
有1个成五点的四颗棋子,棋型有点多。
4)活三
可以形成活四的三颗棋子,要么是三连的形式,即4个方向的01110这种形式的棋型,要么是非三连的形式,即8个方向的010110这种形式的棋型
PS:这个三连描述的不准确,在01110的两端,必须至少有一个空格。
情况1:
情况2:
情况3:
1)三三禁手
由于黑方落一子,同时形成二个或二个以上黑方活三的局面
2)四四禁手
由于黑方落一子,同时形成二个或二个以上黑方四(活四或者冲四)的局面
3)长连禁手
由于黑方落一子,形成六个或者六个以上的同色连续棋子
双人对弈很简单,只需要游戏双方遵守规则落子,当有一方获胜后提示获胜并选择重新开始或退出游戏。
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;
}
}
}
}
}
}
在双人对弈中,还有一个重要的部分就是当一个棋子落下后需要判断是否有玩家获胜。具体判胜方法就是,暴力遍历棋盘,判断是否出现五连子的情况,这里五连子分为纵横方向、向左倾斜、向右倾斜三种情况,每种情况又包含了玩家1还是玩家2赢两种情况,因此一共有六中情况,暴力求解代码如下:
int win = 0;
//判断是否赢
for (int j = 0; j<16 &&