游戏效果预览:
百度云盘:链接:https://pan.baidu.com/s/1Ftun17GMOWwT2u0qk0TNdA 密码:3c1p
接触C语言刚好一年了,也步入了大二,正好学校有个基础项目体验开发(C语言)的小学期,就选择了五子棋这个项目。在学习C语言的过程之中,也是在网上受到不少前辈们的帮助。也正是有了这些前辈们的无私奉献,让我对编程有了浓厚的兴趣。于是写下此博客,想要像那些前辈们一样,助人为乐。需要强调的一点是,如果C语言基础薄弱,此前也没有接触过绘图库的同学,建议去看一看香蕉张老师的视频:http://xiangjiaodi.com/catalog.html,我在写五子棋的时候很多的灵感就是来源于香蕉张老师的“夜夜爱消除”的思想。学习C的话传智播客的很多资源也都是免费的。另外,一开始我是没有写出五子棋人机的代码来,后来在学校贾老师的鼓励下,又结合了罗磐前辈的这篇博客:https://blog.csdn.net/chinajane163/article/details/52599787。虽然代码和前辈的截然不同,但是思想完全一致。写代码差不多5、6个小时完成,但是在后期的代码调试优化阶段,却搞了接近一周的样子,也频繁用到PS技术,这样就勉勉强强的写出来了一个基础的人机五子棋。我的IDE是VS2013,绘图库是EasyX,软件打包用的是InstallShield 2018,结构图用的是XMind ,制作的时候把VS的字符集设置为多字节字符集,除此之外如果读者在实践代码的时候遇到了问题,第一时间请查看文档(上面百度云链接里)或者百度,基本上都是可以解决的。实在不行也可以联系我,上面的图片里有我的联系方式。第一次写博客,对于C语言的理解也尚未深刻,难免出现错误,还望读者见谅,批评指正。
/***************************************************
*
* 功能描述:欢乐五子棋
* 作者姓名:新鲜的大白菜
* 日 期:2019年9月22日
*
***************************************************/
#include
#include
#include
#include
#pragma comment(lib,"winmm.lib") //背景音乐
//游戏初始化
void initgame();
//人人游戏进行
void begingame();
//人机游戏进行
void renjibegingame();
//游戏结束释放资源
void gameover();
//游戏胜负的判定 返回1表示胜负已定 返回0表示胜负未分
int panduan(COLORREF, int, int);
//人人模式游戏结束显示下棋顺序
void arrayqizhi();
//人机模式游戏结束显示人机下棋顺序
void rjarrayqizhi();
//人机模式游戏结束显示人下棋顺序
void rrarrayqizhi();
//创建一个人机判断 死几活几的通解 参数分别是 颜色, x坐标, y坐标, 死活判断(1代表死,2代表活), 死几或者活几 返回1代表成立,返回0代表不成立
int shpanduan(COLORREF , int , int , int , int );
//人机每一步分析可用棋子上的分数值,返回分数最高的就是落子点
int scorepanduan(int, int);
//设置光标结构体类型
typedef struct
{
int x;
int y;
}post;
//设置人机结构体类型
typedef struct
{
int x;
int y;
int score;
}alph;
//设置光标
post xy;
//用一个数的奇偶性来判断产生棋子的黑白 偶数表示黑棋 当color == 225的时候表明平局
int color = 0;
//用一个开关来控制游戏的背景音乐; 奇数表示开
int bgm = 1;
//为了防止出现随意悔棋的情况 所以规定每个人只能悔当前下的棋 所以定义一个光标记录将要悔棋的地点
post huixy;
//人悔了一步棋,机器也要退回上一个的位置
alph rjhuixy;
//定义一个稍微大一点的结构体数组来存放每一步棋子顺序(人人)
post array[1000] = { 0 };
//定义一个稍微大一点的结构体数组来存放每一步棋子顺序(人机)
alph rjarray[1000] = { 0 };
int main()
{
initgame();
begingame();
gameover();
system("pause");
return 0;
}
void initgame()
{
//设置窗口大小
initgraph(500, 750);
//让窗口名称变成双人欢乐五子棋
// 获得窗口句柄
HWND hWnd = GetHWnd();
// 使用 API 函数修改窗口名称
SetWindowText(hWnd, "欢乐五子棋^_^");
B:;
//加载图片
IMAGE backgrand;
loadimage(&backgrand, "back.jpg", 500, 750);
putimage(0, 0, &backgrand);
//设置背景颜色
setbkcolor(RGB(249, 237, 225)); //目的是为了让显示的文字看起来没有边框
//设置五张图片来显示出颜色动态效果
IMAGE ch1, ch2, ch3, ch4, ch5 ,ch6;
loadimage(&ch1, "ch1.jpg", 500, 750);
loadimage(&ch2, "ch2.jpg", 500, 750);
loadimage(&ch3, "ch3.jpg", 500, 750);
loadimage(&ch4, "ch4.jpg", 500, 750);
loadimage(&ch5, "ch5.jpg", 500, 750);
loadimage(&ch6, "ch6.jpg", 500, 750);
//游戏界面选择
MOUSEMSG m; // 定义鼠标消息
while (true)
{
// 获取一条鼠标消息
m = GetMouseMsg();
//清除上一下鼠标缓存
FlushMouseMsgBuffer();
//避免黑屏
putimage(0, 0, &backgrand);
switch (m.uMsg)
{
case WM_MOUSEMOVE:
if (m.x >= 10 && m.x <= 200 && m.y >= 580 && m.y <= 620) //(10, 580, 200, 620) 开始游戏
{
putimage(0, 0, &ch1);
}
if (m.x >= 290 && m.x <= 480 && m.y >= 580 && m.y <= 620) // (290, 580, 480, 620) 退出游戏
{
putimage(0, 0, &ch2);
}
if (m.x >= 10 && m.x <= 200 && m.y >= 640 && m.y <= 680) // (10, 640, 200, 680) 游戏说明 温馨提示
{
putimage(0, 0, &ch3);
}
if (m.x >= 290 && m.x <= 480 && m.y >= 640 && m.y <= 680) // (290, 640, 480, 680) 联系我们
{
putimage(0, 0, &ch4);
}
if (m.x >= 10 && m.x <= 200 && m.y >= 700 && m.y <= 740) // (10,700,200,740) 进入人机挑战
{
putimage(0, 0, &ch5);
}
if (m.x >= 290 && m.x <= 480 && m.y >= 700 && m.y <= 740) // (290,700,480,740) 打赏我们
{
putimage(0, 0, &ch6);
}
break;
case WM_LBUTTONDOWN: //长是190 宽是40
if (m.x >= 10 && m.x <= 200 && m.y >= 580 && m.y <= 620) //(10, 580, 200, 620) 开始游戏
{
goto A;
}
if (m.x >= 290 && m.x <= 480 && m.y >= 580 && m.y <= 620) // (290, 580, 480, 620) 退出游戏
{
//先释放资源
closegraph();
exit(0);
}
if (m.x >= 290 && m.x <= 480 && m.y >= 640 && m.y <= 680) // (290, 640, 480, 680) 联系我们
{
IMAGE call;
loadimage(&call, "联系我们.jpg", 500, 750);
putimage(0, 0, &call);
system("pause");
goto B;
}
if (m.x >= 10 && m.x <= 200 && m.y >= 640 && m.y <= 680) // (10, 640, 200, 680) 游戏说明 温馨提示
{
IMAGE explain;
loadimage(&explain, "游戏说明.jpg", 500, 750);
putimage(0, 0, &explain);
system("pause");
goto B;
}
if (m.x >= 290 && m.x <= 480 && m.y >= 700 && m.y <= 740) // (290,700,480,740) 打赏我们
{
IMAGE help;
loadimage(&help, "打赏我们.jpg", 500, 750);
putimage(0, 0, &help);
system("pause");
goto B;
}
if (m.x >= 10 && m.x <= 200 && m.y >= 700 && m.y <= 740) // (10,700,200,740) 进入人机挑战
{
renjibegingame();
}
}
}
A:;
}
void begingame()
{
//加载背景音乐
mciSendString("open BGM1.mp3 alias bg", NULL, 0, NULL);
mciSendString("play bg repeat", NULL, 0, NULL);
C:
//显示背景音乐开关
IMAGE BGM;
loadimage(&BGM, "BGM.jpg", 500, 750);
putimage(0, 0, &BGM);
//棋盘加载
setlinecolor(BLACK);
setlinestyle(PS_SOLID);
setfillcolor(RGB(248, 203, 18));
fillrectangle(25, 325, 425, 725); //计算而来的
for (int i = 1; i < 15; i++)
{
for (int j = 1; j < 15; j++)
{
rectangle(25 + j * 25, 325 + i * 25, 50 + j * 25, 350 + i * 25); //棋盘左上是50 350
}
}
//黑子先手 游戏开始光标默认在正中间
//绘制光标
xy.x = 225;
xy.y = 525; // 这个坐标是推出来的 就是最中心的坐标
setlinecolor(RED);
setlinestyle(PS_DOT);
rectangle(xy.x - 15, xy.y - 15, xy.x + 15, xy.y + 15);
//定义一个有225个元素的结构体数组来代表光标的所有分布的可能性
post master[225];
//填充电脑位置 //棋盘左上是50 350
int index = 0; //定义结构体数组的下标
for (int i = 1; i <= 15; i++)
{
for (int j = 1; j <= 15; j++)
{
//25 + j * 25, 325 + i * 25, //棋盘左上是50 350
master[index].x = 25 + j * 25;
master[index].y = 325 + i * 25;
index++;
}
}
//清除上一下鼠标缓存
FlushMouseMsgBuffer();
MOUSEMSG m; // 定义鼠标消息
while (true)
{
//按下esc返回游戏界面
if (_kbhit())
{
char key;
key = _getch();
switch (key)
{
case 27:
{
//重置color
color = 0;
//音乐暂停
mciSendString("close bg", NULL, 0, NULL); //竟然神奇的把pause改成close就可以消除按下esc会页面在点击开始游戏直接出来棋子的bug
main();
}
}
}
//清除上一下鼠标缓存
FlushMouseMsgBuffer(); //让光标更加灵活
//获取一条鼠标消息
m = GetMouseMsg();
//是否暂停音乐
if (bgm % 2 == 0)
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(25, 730, "背景音乐:OFF");
mciSendString("pause bg", NULL, 0, NULL);
}
else
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(25, 730, "背景音乐:O N");
mciSendString("resume bg", NULL, 0, NULL);
}
//显示提示黑子先手或者显示提示当前将要下的棋子颜色
if (color == 0)
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(30, 300, "黑子先手!");
}
else if(color % 2 != 0)
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(30, 300, "轮到棋子:");
//提示落子颜色
setfillcolor(WHITE);
setlinecolor(WHITE);
fillcircle(130, 310, 10);
}
else
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(30, 300, "轮到棋子:");
//提示落子颜色
setfillcolor(BLACK);
setlinecolor(BLACK);
fillcircle(130, 310, 10);
}
switch (m.uMsg)
{
case WM_MOUSEMOVE:
for (int i = 0; i < 225; i++)
{
if ( (m.x >= master[i].x - 10 && m.x <= master[i].x + 10) && (m.y >= master[i].y - 10 && m.y <= master[i].y + 10) ) // m.x == master[i].x && m.y == master[i].y
{
//(m.x >= master[i].x - 5 && m.x <= master[i].x + 5) && (m.y >= master[i].y - 5 && m.y <= master[i].y + 5)
setlinecolor(RGB(248, 203, 18));
rectangle(xy.x - 15, xy.y - 15, xy.x + 15, xy.y + 15);
xy.x = master[i].x;
xy.y = master[i].y;
setlinecolor(RED);
setlinestyle(PS_DOT);
rectangle(xy.x - 15, xy.y - 15, xy.x + 15, xy.y + 15);
}
}
break;
case WM_MBUTTONDOWN:
if (m.mkShift)
{
bgm++; // 如果按下中键同时按下shift就决定音乐是否暂停(先按住shift在按住鼠标中键)
Sleep(100);
break;
}
if (m.mkCtrl)
{
//如果按下中键同时按下ctrl就重新开始游戏
color = 0; //重置颜色
IMAGE backgrand;
loadimage(&backgrand, "back.jpg", 500, 750);
putimage(0, 0, &backgrand); //重置画面
goto C;
}
exit(0); //设置强制退出游戏功能
case WM_LBUTTONUP:
//不可以重复下棋 通过getpixel这个函数来实现
if (getpixel(xy.x - 3, xy.y - 3) == RGB(0, 0, 0) || getpixel(xy.x - 3, xy.y - 3) == RGB(255, 255, 255))
{
break;
}
if (color % 2 == 0)
{
//把下的棋的顺序保存在array数组里面
array[color] = xy;
setfillcolor(BLACK);
setlinecolor(BLACK);
fillcircle(xy.x, xy.y, 10);
PlaySound("104.wav", NULL, SND_FILENAME | SND_ASYNC);
COLORREF hei = getpixel(xy.x - 3, xy.y - 3);
//胜负判断
int a = panduan(hei, xy.x, xy.y);
if (a == 1)
{
settextcolor(RGB(0, 0, 0));
settextstyle(30, 0, "楷体");
outtextxy(105, 200, "恭喜黑棋获胜!");
outtextxy(65, 170, "(请按任意键继续游戏)");
char str[30];
sprintf_s(str, "大战了%d回合!", color / 2 + 1);
outtextxy(105, 230, str);
PlaySound("ying.wav", NULL, SND_FILENAME | SND_ASYNC);
//显示棋子顺序
arrayqizhi();
//重置color
color = 0;
system("pause");
goto C;
}
//加入平局的判断
if (a == 0 && color == 224) //因为color最大值是224
{
settextcolor(RGB(0, 0, 0));
settextstyle(30, 0, "宋体");
outtextxy(250, 200, "平局!");
outtextxy(65, 170, "(请按任意键继续游戏)");
PlaySound("ying.wav", NULL, SND_FILENAME | SND_ASYNC);
//显示棋子顺序
arrayqizhi();
//重置color
color = 0;
system("pause");
goto C;
}
}
else
{
//把下的棋的顺序保存在array数组里面
array[color] = xy;
setfillcolor(WHITE);
setlinecolor(WHITE);
fillcircle(xy.x, xy.y, 10);
PlaySound("104.wav", NULL, SND_FILENAME | SND_ASYNC);
COLORREF bai = getpixel(xy.x - 3, xy.y - 3);
//胜负判断
int b = panduan(bai, xy.x, xy.y);
if (b == 1)
{
settextcolor(RGB(0, 0, 0));
settextstyle(30, 0, "楷体");
outtextxy(105, 200, "恭喜白棋获胜!");
outtextxy(65, 170, "(请按任意键继续游戏)");
char str[30];
sprintf_s(str, "大战了%d回合!", color / 2 + 1);
outtextxy(105, 230, str);
PlaySound("ying.wav", NULL, SND_FILENAME | SND_ASYNC);
//显示棋子顺序
arrayqizhi();
//重置color
color = 0;
system("pause");
goto C;
}
//加入平局的判断
if (b == 0 && color == 224)
{
settextcolor(RGB(0, 0, 0));
settextstyle(30, 0, "宋体");
outtextxy(105, 200, "平局!");
outtextxy(65, 170, "(请按任意键继续游戏)");
PlaySound("ying.wav", NULL, SND_FILENAME | SND_ASYNC);
//显示棋子顺序
arrayqizhi();
//重置color
color = 0;
system("pause");
goto C;
}
}
//把当前下的棋保存在huixy中
huixy.x = xy.x;
huixy.y = xy.y;
color++;
Sleep(100);
break;
case WM_RBUTTONDOWN: //设置悔棋功能
//保证是悔的上一颗的棋
if (huixy.x == xy.x && huixy.y == xy.y && getpixel(xy.x - 3, xy.y - 3) != RGB(248, 203, 18))
{
setfillcolor(RGB(248, 203, 18));
setlinecolor(RGB(248, 203, 18));
fillcircle(xy.x, xy.y, 10);
setlinecolor(BLACK);
for (int i = 1; i < 15; i++)
{
for (int j = 1; j < 15; j++)
{
rectangle(25 + j * 25, 325 + i * 25, 50 + j * 25, 350 + i * 25);
}
}
color--;
break;
}
}
//来一个重新检查 主要是让白棋不存在中心有黑线的情况
for (int i = 0; i < 255; i++)
{
if (getpixel(master[i].x - 3, master[i].y - 3) == RGB(0, 0, 0))
{
setfillcolor(RGB(0, 0, 0));
setlinecolor(RGB(0, 0, 0));
fillcircle(master[i].x, master[i].y, 10);
}
if (getpixel(master[i].x - 3, master[i].y - 3) == RGB(255, 255, 255))
{
setfillcolor(RGB(255, 255, 255));
setlinecolor(RGB(255, 255, 255));
fillcircle(master[i].x, master[i].y, 10);
}
}
}
}
void renjibegingame()
{
//加载背景音乐
mciSendString("open BGM.mp3 alias bg", NULL, 0, NULL);
mciSendString("play bg repeat", NULL, 0, NULL);
C:
//显示背景音乐开关
IMAGE BGM;
loadimage(&BGM, "BGM.jpg", 500, 750);
putimage(0, 0, &BGM);
// 棋盘加载
setlinecolor(BLACK);
setlinestyle(PS_SOLID);
setfillcolor(RGB(248, 203, 18));
fillrectangle(25, 325, 425, 725); //计算而来的
for (int i = 1; i < 15; i++)
{
for (int j = 1; j < 15; j++)
{
rectangle(25 + j * 25, 325 + i * 25, 50 + j * 25, 350 + i * 25); //棋盘左上是50 350
}
//printf("\n"); 可以不需要换行 因为这里全是通过坐标实现的
}
//黑子先手 游戏开始光标默认在正中间
//绘制光标
xy.x = 225;
xy.y = 525; // 这个坐标是推出来的 就是最中心的坐标
setlinecolor(RED);
setlinestyle(PS_DOT);
rectangle(xy.x - 15, xy.y - 15, xy.x + 15, xy.y + 15);
//初始化人机阿尔法猫
//加载每个点并且把分数搞成0
alph alphcat[225];
//填充电脑位置 //棋盘左上是50 350
int inde = 0; //定义结构体数组的下标
for (int i = 1; i <= 15; i++)
{
for (int j = 1; j <= 15; j++)
{
//25 + j * 25, 325 + i * 25, //棋盘左上是50 350
alphcat[inde].x = 25 + j * 25;
alphcat[inde].y = 325 + i * 25;
alphcat[inde].score = 0;
inde++;
}
}
//定义一个有225个元素的结构体数组来代表光标的所有分布的可能性
post master[225];
//填充电脑位置 //棋盘左上是50 350
int index = 0; //定义结构体数组的下标
for (int i = 1; i <= 15; i++)
{
for (int j = 1; j <= 15; j++)
{
//25 + j * 25, 325 + i * 25, //棋盘左上是50 350
master[index].x = 25 + j * 25;
master[index].y = 325 + i * 25;
index++;
}
}
//清除上一下鼠标缓存
FlushMouseMsgBuffer();
MOUSEMSG m; // 定义鼠标消息
while (true)
{
//按下esc返回游戏界面
if (_kbhit())
{
char key;
key = _getch();
switch (key)
{
case 27:
{
//重置color
color = 0;
//音乐暂停
mciSendString("close bg", NULL, 0, NULL); //竟然神奇的把pause改成close就可以消除按下esc会页面在点击开始游戏直接出来棋子的bug
main();
}
}
}
//清除上一下鼠标缓存
FlushMouseMsgBuffer(); //让光标更加灵活
//获取一条鼠标消息
m = GetMouseMsg();
//是否暂停音乐
if (bgm % 2 == 0)
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(25, 730, "背景音乐:OFF");
mciSendString("pause bg", NULL, 0, NULL);
}
else
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(25, 730, "背景音乐:O N");
mciSendString("resume bg", NULL, 0, NULL);
}
//显示提示黑子先手或者显示提示当前将要下的棋子颜色
if (color == 0)
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(30, 300, "黑子先手!");
}
else if (color % 2 != 0)
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(30, 300, "轮到棋子:");
//提示落子颜色
setfillcolor(WHITE);
setlinecolor(WHITE);
fillcircle(130, 310, 10);
}
else
{
settextcolor(RGB(0, 0, 0));
settextstyle(20, 0, "楷体");
outtextxy(30, 300, "轮到棋子:");
//提示落子颜色
setfillcolor(BLACK);
setlinecolor(BLACK);
fillcircle(130, 310, 10);
}
switch (m.uMsg)
{
case WM_MOUSEMOVE:
for (int i = 0; i < 225; i++)
{
if ((m.x >= master[i].x - 10 && m.x <= master[i].x + 10) && (m.y >= master[i].y - 10 && m.y <= master[i].y + 10))
{
setlinecolor(RGB(248, 203, 18));
rectangle(xy.x - 15, xy.y - 15, xy.x + 15, xy.y + 15);
xy.x = master[i].x;
xy.y = master[i].y;
setlinecolor(RED);
setlinestyle(PS_DOT);
rectangle(xy.x - 15, xy.y - 15, xy.x + 15, xy.y + 15);
}
}
break;
case WM_MBUTTONDOWN:
if (m.mkShift)
{
bgm++; // 如果按下中键同时按下shift就决定音乐是否暂停(先按住shift在按住鼠标中键)
Sleep(100);
break;
}
if (m.mkCtrl)
{
//如果按下中键同时按下ctrl就重新开始游戏
color = 0; //重置颜色
IMAGE backgrand;
loadimage(&backgrand, "back.jpg", 500, 750);
putimage(0, 0, &backgrand); //重置画面
goto C;
}
exit(0); //设置强制退出游戏功能
case WM_LBUTTONUP:
{
//不可以重复下棋 通过getpixel这个函数来实现
if (getpixel(xy.x - 3, xy.y - 3) == RGB(0, 0, 0) || getpixel(xy.x - 3, xy.y - 3) == RGB(255, 255, 255))
{
break;
}
//把下的棋的顺序保存在array数组里面
array[color] = xy;
setfillcolor(BLACK);
setlinecolor(BLACK);
fillcircle(xy.x, xy.y, 10);
PlaySound("104.wav", NULL, SND_FILENAME | SND_ASYNC);
COLORREF hei = getpixel(xy.x - 3, xy.y - 3);
//胜负判断
int a = panduan(hei, xy.x, xy.y);
if (a == 1)
{
settextcolor(RGB(0, 0, 0));
settextstyle(30, 0, "楷体");
outtextxy(105, 200, "阿尔法猫:你牛逼!");
outtextxy(65, 170, "(请按任意键继续游戏)");
char str[30];
sprintf_s(str, "大战了%d回合!", color / 2 + 1);
outtextxy(105, 230, str);
PlaySound("ying.wav", NULL, SND_FILENAME | SND_ASYNC);
//显示棋子顺序
rrarrayqizhi();
rjarrayqizhi();
//重置color
color = 0;
system("pause");
goto C;
}
//加入平局的判断
if (a == 0 && color == 224) //因为color最大值是224
{
settextcolor(RGB(0, 0, 0));
settextstyle(30, 0, "宋体");
outtextxy(80, 200, "我和你五五开!");
outtextxy(65, 170, "(请按任意键继续游戏)");
PlaySound("ying.wav", NULL, SND_FILENAME | SND_ASYNC);
//显示棋子顺序
rrarrayqizhi();
rjarrayqizhi();
//重置color
color = 0;
system("pause");
goto C;
}
//把当前下的棋保存在huixy中
huixy.x = xy.x;
huixy.y = xy.y;
color++;
Sleep(100);
}
case 1:
{
for (int i = 0; i < 225; i++)
{
if (RGB(0, 0, 0) != getpixel(alphcat[i].x - 3, alphcat[i].y - 3) && RGB(255, 255, 255) != getpixel(alphcat[i].x - 3, alphcat[i].y - 3)/*当前落棋点没有落棋 (这个点的颜色是背景色)*/)
{
//RGB(255, 255, 255) != getpixel(alphcat[i].x - 3, alphcat[i].y - 3)
alphcat[i].score = scorepanduan(alphcat[i].x, alphcat[i].y);
}
}
//再来选出一个得分最大的,如果得分一样就随机从最大的一个选一个
alph alphmax;
alphmax.score = alphcat[0].score;
for (int i = 1; i < 225; i++)
{
if (alphcat[i].score >= alphmax.score)
{
alphmax = alphcat[i];
}
}
// 把下的棋的顺序保存在array数组里面
rjarray[color] = alphmax;
//根据这个点画白棋
setfillcolor(WHITE);
setlinecolor(WHITE);
fillcircle(alphmax.x, alphmax.y, 10);
PlaySound("104.wav", NULL, SND_FILENAME | SND_ASYNC);
for (int i = 0; i < 225; i++)
{
alphcat[i].score = 0;
}
COLORREF bai = getpixel(alphmax.x - 3, alphmax.y - 3);
//胜负判断
int b = panduan(bai, alphmax.x, alphmax.y);
if (b == 1)
{
settextcolor(RGB(0, 0, 0));
settextstyle(30, 0, "楷体");
outtextxy(55, 200, "阿尔法猫:好气啊!我赢了!");
outtextxy(65, 170, "(请按任意键继续游戏)");
char str[30];
sprintf_s(str, "大战了%d回合!", color / 2 + 1);
outtextxy(105, 230, str);
PlaySound("ying.wav", NULL, SND_FILENAME | SND_ASYNC);
//显示棋子顺序
rrarrayqizhi();
rjarrayqizhi();
//重置color
color = 0;
system("pause");
goto C;
}
//加入平局的判断
if (b == 0 && color == 224) //因为color最大值是224
{
settextcolor(RGB(0, 0, 0));
settextstyle(30, 0, "宋体");
outtextxy(250, 200, "我和你五五开!");
outtextxy(65, 170, "(请按任意键继续游戏)");
PlaySound("ying.wav", NULL, SND_FILENAME | SND_ASYNC);
//显示棋子顺序
rrarrayqizhi();
rjarrayqizhi();
//重置color
color = 0;
system("pause");
goto C;
}
//把当前下的棋保存在rjhuixy中
rjhuixy.x = alphmax.x;
rjhuixy.y = alphmax.y;
color++;
Sleep(100);
break;
}
case WM_RBUTTONDOWN: //设置悔棋功能
//保证是悔的上一颗的棋
if (huixy.x == xy.x && huixy.y == xy.y && getpixel(xy.x - 3, xy.y - 3) != RGB(248, 203, 18))
{
//悔自己的黑棋
setfillcolor(RGB(248, 203, 18));
setlinecolor(RGB(248, 203, 18));
fillcircle(xy.x, xy.y, 10);
//机器也要悔一步棋
setfillcolor(RGB(248, 203, 18));
setlinecolor(RGB(248, 203, 18));
fillcircle(rjhuixy.x, rjhuixy.y, 10);
//重新画棋盘
setlinecolor(BLACK);
for (int i = 1; i < 15; i++)
{
for (int j = 1; j < 15; j++)
{
rectangle(25 + j * 25, 325 + i * 25, 50 + j * 25, 350 + i * 25);
}
}
color -= 2;
break;
}
}
//来一个重新检查 主要是让白棋不存在中心有黑线的情况
for (int i = 0; i < 255; i++)
{
if (getpixel(master[i].x - 3, master[i].y - 3) == RGB(0, 0, 0))
{
setfillcolor(RGB(0, 0, 0));
setlinecolor(RGB(0, 0, 0));
fillcircle(master[i].x, master[i].y, 10);
}
if (getpixel(master[i].x - 3, master[i].y - 3) == RGB(255, 255, 255))
{
setfillcolor(RGB(255, 255, 255));
setlinecolor(RGB(255, 255, 255));
fillcircle(master[i].x, master[i].y, 10);
}
}
}
}
void gameover()
{
//游戏结束释放资源
_getch();
closegraph();
}
int panduan(COLORREF cl, int x, int y)
{
int a, b;
//定义上下总个数
int i = 0;
a = x;
b = y;
/*x = xy.x;
y = xy.y;*/
//先检查上面的
while (cl == getpixel(a - 3, b - 3 - 25))
{
i++;
b -= 25;
}
//还原落子位置
a = x;
b = y;
//再检查下面的
while (cl == getpixel(a - 3, b - 3 + 25))
{
i++;
b += 25;
}
//还原落子位置
a = x;
b = y;
if (i >= 4)
{
return 1; ///////////////////////////////////////////////
}
//定义左右总个数
int j = 0;
a = x;
b = y;
//先检查左面的
while (cl == getpixel(a - 3 - 25, b - 3))
{
j++;
a -= 25;
}
//还原落子位置
a = x;
b = y;
//再检查下面的
while (cl == getpixel(a - 3 + 25, b - 3))
{
j++;
a += 25;
}
//还原落子位置
a = x;
b = y;
if (j >= 4)
{
return 1; ////////////////////////////////////////////
}
//定义'\'总个数
int k = 0;
a = x;
b = y;
//先检查上面的
while (cl == getpixel(a - 3 - 25, b - 3 - 25))
{
k++;
a -= 25;
b -= 25;
}
//还原落子位置
a = x;
b = y;
//再检查下面的
while (cl == getpixel(a - 3 + 25, b - 3 + 25))
{
k++;
a += 25;
b += 25;
}
//还原落子位置
a = x;
b = y;
if (k >= 4)
{
return 1; //////////////////////////
}
//定义'/'总个数
int l = 0;
a = x;
b = y;
//先检查上面的
while (cl == getpixel(a - 3 + 25, b - 3 - 25))
{
l++;
a += 25;
b -= 25;
}
//还原落子位置
a = x;
b = y;
//再检查下面的
while (cl == getpixel(a - 3 - 25, b - 3 + 25))
{
l++;
a -= 25;
b += 25;
}
//还原落子位置
a = x;
b = y;
if (l >= 4)
{
return 1; /////////////////////////////////////////
}
return 0;
}
void arrayqizhi()
{
//主要实现的功能是在黑色的棋上显示白色顺序 在白色棋子上显示黑色的顺序
for (int i = 0; i <= color; i++)
{
if (i % 2 == 0)
{
setbkcolor(RGB(0, 0, 0));
char arr[10];
sprintf_s(arr, "%-2d", i + 1);
settextcolor(RGB(255, 255, 255));
settextstyle(15, 0, "宋体");
outtextxy(array[i].x - 7, array[i].y - 7, arr);
}
else
{
setbkcolor(RGB(255, 255, 255));
char arr[10];
sprintf_s(arr, "%-2d", i + 1);
settextcolor(RGB(0, 0, 0));
settextstyle(15, 0, "宋体");
outtextxy(array[i].x - 7, array[i].y - 7, arr);
}
}
//恢复了背景颜色
setbkcolor(RGB(249, 237, 225));
}
void rjarrayqizhi()
{
// 在白色棋子上显示黑色的顺序
for (int i = 0; i <= color; i++)
{
if (i % 2 != 0)
{
setbkcolor(RGB(255, 255, 255));
char arr[10];
sprintf_s(arr, "%-2d", i + 1);
settextcolor(RGB(0, 0, 0));
settextstyle(15, 0, "宋体");
outtextxy(rjarray[i].x - 7, rjarray[i].y - 7, arr);
}
}
//恢复了背景颜色
setbkcolor(RGB(249, 237, 225));
}
void rrarrayqizhi()
{
// 在黑色棋子上显示白色的顺序
for (int i = 0; i <= color; i++)
{
if (i % 2 == 0)
{
setbkcolor(RGB(0, 0, 0));
char arr[10];
sprintf_s(arr, "%-2d", i + 1);
settextcolor(RGB(255, 255, 255));
settextstyle(15, 0, "宋体");
outtextxy(array[i].x - 7, array[i].y - 7, arr);
}
}
//恢复了背景颜色
setbkcolor(RGB(249, 237, 225));
}
int shpanduan(COLORREF cl, int x, int y, int q, int p)
{
//用一个K来体现某一个方向的下一个是背景而不是有另外颜色的(活) K = 1 表示下一个为背景色
int K = 0;
int a, b;
//定义上下总个数
int i = 0;
a = x;
b = y;
//先检查上面的
while (cl == getpixel(a - 3, b - 3 - 25))
{
i++;
b -= 25;
}
//检查是否下一个是背景色
if (getpixel(a - 3, b - 3 - 25) == RGB(248, 203, 18) && b - 25 > 350)
{
K++;
}
//还原落子位置
a = x;
b = y;
//再检查下面的
while (cl == getpixel(a - 3, b - 3 + 25))
{
i++;
b += 25;
}
//检查是否下一个是背景色
if (getpixel(a - 3, b - 3 + 25) == RGB(248, 203, 18) && b + 35 < 700)
{
K++;
}
//还原落子位置
a = x;
b = y;
if (i == p - 1 && K == q)
{
return 1; ///////////////////////////////////////////////
}
//重置K
K = 0;
//定义左右总个数
int j = 0;
a = x;
b = y;
//先检查左面的
while (cl == getpixel(a - 3 - 25, b - 3))
{
j++;
a -= 25;
}
//检查是否下一个是背景色
if (getpixel(a - 3 - 25, b - 3) == RGB(248, 203, 18) && a - 35 > 50)
{
K++;
}
//还原落子位置
a = x;
b = y;
//再检查下面的
while (cl == getpixel(a - 3 + 25, b - 3))
{
j++;
a += 25;
}
//检查是否下一个是背景色
if (getpixel(a - 3 + 25, b - 3) == RGB(248, 203, 18) && a + 35 < 700)
{
K++;
}
//还原落子位置
a = x;
b = y;
if (j == p - 1 && K == q)
{
return 1; ////////////////////////////////////////////
}
//重置K
K = 0;
//定义'\'总个数
int k = 0;
a = x;
b = y;
//先检查上面的
while (cl == getpixel(a - 3 - 25, b - 3 - 25))
{
k++;
a -= 25;
b -= 25;
}
//检查是否下一个是背景色
if (getpixel(a - 3 - 25, b - 3 - 25) == RGB(248, 203, 18) && a - 25 > 50 && b - 25 > 350)
{
K++;
}
//还原落子位置
a = x;
b = y;
//再检查下面的
while (cl == getpixel(a - 3 + 25, b - 3 + 25))
{
k++;
a += 25;
b += 25;
}
//检查是否下一个是背景色
if (getpixel(a - 3 + 25, b - 3 + 25) == RGB(248, 203, 18) && a + 25 < 400 && b + 25 < 700)
{
K++;
}
//还原落子位置
a = x;
b = y;
if (k == p - 1 && K == q)
{
return 1; //////////////////////////
}
//重置K
K = 0;
//定义'/'总个数
int l = 0;
a = x;
b = y;
//先检查上面的
while (cl == getpixel(a - 3 + 25, b - 3 - 25))
{
l++;
a += 25;
b -= 25;
}
//检查是否下一个是背景色
if (getpixel(a - 3 + 25, b - 3 - 25) == RGB(248, 203, 18) && a + 25 < 400 && b - 25 > 350)
{
K++;
}
//还原落子位置
a = x;
b = y;
//再检查下面的
while (cl == getpixel(a - 3 - 25, b - 3 + 25))
{
l++;
a -= 25;
b += 25;
}
//检查是否下一个是背景色
if (getpixel(a - 3 - 25, b - 3 + 25) == RGB(248, 203, 18) && a - 25 > 50 && b + 25 < 700)
{
K++;
}
//还原落子位置
a = x;
b = y;
if (l == p - 1 && K == q)
{
return 1; /////////////////////////////////////////
}
return 0;
}
int scorepanduan(int x, int y)
{
/* 主要思想
电脑白子 自己黑子
白子连成五子 +10000 阻碍黑子连成五子 +1000
白子连成活四 +200 阻碍黑子连成活四 +100
白子连成死四 +50 阻碍黑子连成死四 +20
白子连成活三 +30 阻碍黑子连成活三 +10
白子连成死三 +8 阻碍黑子连成死三 +5
白子连成活二 +2 阻碍黑子连成活二 +1
白子连成死二 +2 阻碍黑子连成死二 +1
白子连成活一 +1 阻碍黑子连成活一 +0
白子连成死一 +1 阻碍黑子连成死一 +0
————————————————
版权声明:本文为CSDN博主「罗磐」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chinajane163/article/details/52599787
*/
int a = x;
int b = y;
//定义一个得分
int score = 0;
//白子连成五子 +10000
if (panduan(RGB(255, 255, 255), a, b)) //这个函数只是i的值与k的值不一样 所以可以加两个变量在函数里面
{
score += 10000;
}
//阻碍黑子连成五子 +1000
if (panduan(RGB(0, 0, 0), a, b))
{
score += 1000;
}
//白子连成活四 +200
if (shpanduan(RGB(255, 255, 255), a, b, 2, 4))
{
score += 200;
}
//阻碍黑子连成活四 +100
if (shpanduan(RGB(0, 0, 0), a, b, 2, 4))
{
score += 100;
}
//白子连成死四 +50
if (shpanduan(RGB(255, 255, 255), a, b, 1, 4))
{
score += 50;
}
//阻碍黑子连成死四 +20
if (shpanduan(RGB(0, 0, 0), a, b, 1, 4))
{
score += 20;
}
//白子连成活三 +30
if (shpanduan(RGB(255, 255, 255), a, b, 2, 3))
{
score += 30;
}
//阻碍黑子连成活三 +10
if (shpanduan(RGB(0, 0, 0), a, b, 2, 3))
{
score += 10;
}
//白子连成死三 +8
if (shpanduan(RGB(255, 255, 255), a, b, 1, 3))
{
score += 8;
}
//阻碍黑子连成死三 +5
if (shpanduan(RGB(0, 0, 0), a, b, 1, 3))
{
score += 5;
}
//白子连成活二 +2
if (shpanduan(RGB(255, 255, 255), a, b, 2, 2))
{
score += 2;
}
//阻碍黑子连成活二 +1
if (shpanduan(RGB(0, 0, 0), a, b, 2, 2))
{
score += 1;
}
//白子连成死二 +2
if (shpanduan(RGB(255, 255, 255), a, b, 1, 2))
{
score += 2;
}
//阻碍黑子连成死二 +1
if (shpanduan(RGB(0, 0, 0), a, b, 1, 2))
{
score += 1;
}
//白子连成活一 +1
if (shpanduan(RGB(255, 255, 255), a, b, 2, 1))
{
score += 1;
}
/* //阻碍黑子连成活一 +0
if()
{
score += 0;
}*/
//白子连成死一 +1
if (shpanduan(RGB(255, 255, 255), a, b, 1, 1))
{
score += 1;
}
/* //阻碍黑子连成死一 +0
if()
{
score += 0;
}*/
return score;
}