今天验收五子棋大作业,实现人人对战、人机对战两种模式,实现五子棋复盘功能,运用easyx图形库实现图形化页面和鼠标点击落子。
下面是实现图形化页面的代码
#include<graphics.h>//easyx图形库 白棋1黑棋-1
#include<stdio.h>
#include<stdlib.h>
initgraph(470, 470);
loadimage(NULL, "背景0.jpg");//插入图片
setlinecolor(BLACK);//棋盘线的颜色
for (int i = 55; i <= 415; i += 30)//绘制棋盘
{
line(i, 55, i, 415);//划线函数
line(55, i, 415, i);
}
settextstyle(25, 0, "隶书");//设置字体大小样式
settextcolor(BLACK);//设置字体颜色
setbkmode(TRANSPARENT);//删除字的背景
outtextxy(10, 10, "欢迎来到五子棋,开启一场头脑风暴吧!");
char num[20];
sprintf(num, "%d", e - 1);//在页面上输出一个变量数字
outtextxy(440, 435, num);
outtextxy(365, 435, "局数:");
这样就可以输出图形化界面和棋盘了!!!
接下来我们要实现玩家进行鼠标点击落子:要搞清他的思想,界面是由470*470像素点构成的
运用easyx图形库里的鼠标函数,根据鼠标点击的位置进行落子,直接上代码吧
void player()//玩家
{
while (1)
{
MOUSEMSG m;//保存鼠标信息
m = GetMouseMsg();
if (m.uMsg == WM_LBUTTONDOWN)//判断鼠标信息中是否有按下左键
{
if (m.x >= 40 && m.x <= 430 && m.y >= 40 && m.y <= 430)//保证传出来数都在棋盘内
{
int a = (m.x - 40) / 30;//对a b取整范围为0到12
int b = (m.y - 40) / 30;
if (board[a][b] == 0)//防止重复
{
setfillcolor(WHITE);
solidcircle(a * 30 + 55, b * 30 + 55, 13);
//使棋子落在十字线的交叉点上且每个棋子相差30个像素点
board[a][b] = 1;//将白棋赋为1
fupan[s[e]].x = a;//将数据存在一个结构体中,便于接下来复盘
fupan[s[e]].y = b;
fupan[s[e]].color = 1;
fwrite(&fupan[s[e]], sizeof(struct a), 1, fp);
s[e]++;
o++;
add(a, b);//函数
update();//函数
if (win(a, b, board) == 1)//函数
{
fclose(fp);
e++;
MessageBox(GetHWnd(), "恭喜白棋赢了!游戏结束", "提示", MB_YESNO) == 6)
exit(0);
}
else
{
break;
}
}
else
{
MessageBox(GetHWnd(), "该位置已有棋子请重新选择", "提示", MB_OK);
continue;
}
}
else
{
MessageBox(GetHWnd(), "超出棋盘范围,请重新输入", "提示", MB_OK);
continue;
}
}
}
}
若要实现人机对战需要对每一个空位赢的可能性进行判断,我们将对一个位置的横向纵向斜向四个方向进行判断
int getXscore(int x, int y, int s)//计算横向空格处价值
{
int left, right;//记录棋子的左右是空位还是出界和对方棋子
int countleft = 0;
int countright = 0;
int t = x;//保存一开始x的数值
while (1)//向左
{
x = x - 1;
if (x == -1 || board[x][y] == -s)
{
left = 2;//表示左面出界或者对方棋子
break;
}
else if (board[x][y] == s)
{
countleft++;
continue;
}
if (board[x][y] == 0)
{
left = 1;//表示左面是空位
break;
}
}
x = t;
while (1)//向右
{
x++;
if (x == 13 || board[x][y] == -s)
{
right = 2;//表示右面出界或者对方棋子
break;
}
if (board[x][y] == s)
{
countright++;
continue;
}
if (board[x][y] == 0)
{
right = 1;//表示右面是空位
break;
}
}
return getcount(countleft + countright, left, right, s);//计算空位分数
}
int getYscore(int x, int y, int s) //计算竖向空格处得分
{
int left, right;
int countleft = 0;
int countright = 0;
int t = y;
while (1)//向上
{
y = y - 1;
if (y == -1 || board[x][y] == -s)
{
left = 2;//表示出界或者对方棋子
break;
}
if (board[x][y] == s)
{
countleft++;
continue;
}
if (board[x][y] == 0)
{
left = 1;//表示空位
break;
}
}
y = t;
while (1)//向下
{
y = y + 1;
if (y == 13 || board[x][y] == -s)
{
right = 2;//表示出界或者对方棋子
break;
}
if (board[x][y] == s)
{
countright++;
continue;
}
if (board[x][y] == 0)
{
right = 1;//表示空位
break;
}
}
return getcount(countleft + countright, left, right, s);//计算空位分数
}
int getXYscore1(int x, int y, int s)//计算主对角线空格处得分
{
int left, right;
int countleft = 0;
int countright = 0;
int X = x, Y = y;
while (1)//向左上
{
y = y - 1;
x = x - 1;
if (x == -1 || y == -1 || board[x][y] == -s)
{
left = 2;//表示出界或者对方棋子
break;
}
if (board[x][y] == s)
{
countleft++;
continue;
}
if (board[x][y] == 0)
{
left = 1;//表示空位
break;
}
}
x = X;
y = Y;
while (1)//向右下
{
y = y + 1;
x = x + 1;
if (y == 13 || x == 13 || board[x][y] == -s)
{
right = 2;//表示出界或者对方棋子
break;
}
if (board[x][y] == s)
{
countright++;
continue;
}
if (board[x][y] == 0)
{
right = 1;//表示空位
break;
}
}
return getcount(countleft + countright, left, right, s);//计算空位分数
}
int getXYscore2(int x, int y, int s)//计算副对角线空格处得分
{
int left, right;
int countleft = 0;
int countright = 0;
int X = x, Y = y;
while (1)//向左下
{
y = y + 1;
x = x - 1;
if (x == -1 || y == 13 || board[x][y] == -s)
{
left = 2;//表示出界或者对方棋子
break;
}
if (board[x][y] == s)
{
countleft++;
continue;
}
if (board[x][y] == 0)
{
left = 1;//表示空位
break;
}
}
x = X;
y = Y;
while (1)//向右上
{
y = y - 1;
x = x + 1;
if (y == -1 || x == 13 || board[x][y] == -s)
{
right = 2;//表示出界或者对方棋子
break;
}
if (board[x][y] == s)
{
countright++;
continue;
}
if (board[x][y] == 0)
{
right = 1;//表示空位
break;
}
}
return getcount(countleft + countright, left, right, s);//计算空位分数
}
int getcount(int count, int left, int right, int s)//计算空位分数
{
if (count == 4)
{
if (s == -1)//当自己的棋子连成4个的时候优先选择进攻
{
return 100000;
}
else
{
return 10000;
}
}//再下一棋就连成五子
if (count == 3)
{
if (left == 1 && right == 1)//1表示一边是空位
{
return 2500;
}
else if (left + right == 3)
{
return 500;
}
else
{
return 0;
}
}
if (count == 2)
{
if (left == 1 && right == 1)
{
return 500;
}
else if (left + right == 3)
{
return 100;
}
else
{
return 0;
}
}
if (count == 1)
{
if (left == 1 && right == 1)
{
return 100;
}
else if (left + right == 3)
{
return 20;
}
}
if (count == 0)
{
if (left == 1 && right == 1)
{
return 20;
}
}
return 0;
}
接下来我们每下一个棋子将他相邻米字型的位置寻找空位,并将空位的信息存在数组中
void add(int x, int y)//每下完一个棋子坐标xy,寻找一个棋子相邻位置是否有空位,并存在结构体中
{
int i = 0, j = 0;
for (i = x - 1 && i >= 0; i <= x + 1 && i <= 12; i++)
{
for (j = y - 1 && j >= 0; j <= y + 1 && j <= 12; j++)
{
if (i == x && j == y)
continue;
if (board[i][j] == 0 && True[i][j] == 0)
{
KongWei[n].local = i * 100 + j;//2位数必须乘以100
n++;//用来记录装入结构体中位置的个数
True[i][j] = 1;//防止重复装进结构体
}
}
}
}
我们对上面存入结构体的所有空位进行分数的计算
void update()//更新分数
{
int i, local, x, y;
for (i = 0; i < n; i++)//遍历结构体中的位置
{
local = KongWei[i].local;
x = local / 100;
y = local % 100;
if (board[x][y] != 0)
{
KongWei[i].score = 0;
continue;
}
else//如果还是空位
{
KongWei[i].score = Max((getXscore(x, y, 1) + getYscore(x, y, 1)
+ getXYscore1(x, y, 1) + getXYscore2(x, y, 1)),
(getXscore(x, y, -1) + getYscore(x, y, -1)
+ getXYscore1(x, y, -1) + getXYscore2(x, y, -1)));
}
}
}
之后遍历结构体找出最高分数的位置,该函数的返回值是分数最高的位置坐标
int Maxscorelocal()//返回价值最高的空格的位置
{
int i, local;
int maxlocal = 0;
int maxscore = 0;
for (i = 0; i < n; i++)
{
local = KongWei[i].local;
if (board[local / 100][local % 100] == 0 && True[local / 100][local % 100] == 1)
{
if (KongWei[i].score >= maxscore)//如果相同,输出最后的那个
{
maxscore = KongWei[i].score;
maxlocal = KongWei[i].local;
}
}
}
return maxlocal;
}
然后我们机器就可以下棋啦!
void computer()
{
while (1)
{
int i = Maxscorelocal() / 100;
int j = Maxscorelocal() % 100;
setfillcolor(BLACK);//机器是黑棋
solidcircle(i * 30 + 55, j * 30 + 55, 13);
board[i][j] = -1;
fupan[s[e]].x = i;
fupan[s[e]].y = j;
fupan[s[e]].color = -1;
fwrite(&fupan[s[e]], sizeof(struct a), 1, fp);
s[e]++;
o++;
add(i, j);
update();
if (win(i, j, board) == -1)
{
fclose(fp);
e++;
MessageBox(GetHWnd(), "您输了,不要灰心", "提示", MB_YESNO)
exit(0);
}
else
{
break;
}
}
判断输赢
int win(int x, int y, int board[][13])//判断输赢
{
int i, j;
for (i = x - 4, j = y; i <= x; i++)//判断横向防止连成4个
{
if (i >= 0 && board[i][j] == board[i + 1][j]
&& board[i + 1][j] == board[i + 2][j]
&& board[i + 2][j] == board[i + 3][j]
&& board[i + 3][j] == board[i + 4][j]
&& board[i + 4][j] != board[i + 5][j]
&& board[i + 4][j] != board[i - 1][j])
{
if (board[i][j] == 1)
return 1;
else
return -1;
}
}
for (i = x, j = y - 4; j <= y; j++)//判断竖向
{
if (j >= 0 && board[i][j] == board[i][j + 1]
&& board[i][j + 1] == board[i][j + 2]
&& board[i][j + 2] == board[i][j + 3]
&& board[i][j + 3] == board[i][j + 4]
&& board[i][j + 4] != board[i][j + 5]
&& board[i][j + 4] != board[i][j - 1])
{
if (board[i][j] == 1)
return 1;
else
return -1;
}
}
for (i = x - 4, j = y - 4; i <= x; i++, j++)//判断主对角线
{
if (j >= 0 && i >= 0
&& board[i][j] == board[i + 1][j + 1]
&& board[i + 1][j + 1] == board[i + 2][j + 2]
&& board[i + 2][j + 2] == board[i + 3][j + 3]
&& board[i + 3][j + 3] == board[i + 4][j + 4]
&& board[i + 4][j + 4] != board[i + 5][j + 5]
&& board[i - 1][j - 1] != board[i + 4][j + 4])
{
if (board[i][j] == 1)
return 1;
else
return -1;
}
}
for (i = x - 4, j = y + 4; i <= x; i++, j--)//副对角线
{
if (i >= 0 && j <= 12
&& board[i][j] == board[i + 1][j - 1]
&& board[i + 1][j - 1] == board[i + 2][j - 2]
&& board[i + 2][j - 2] == board[i + 3][j - 3]
&& board[i + 3][j - 3] == board[i + 4][j - 4]
&& board[i + 4][j - 4] != board[i + 5][j - 5]
&& board[i + 4][j - 4] != board[i - 1][j + 1])
{
if (board[i][j] == 1)
return 1;
else
return -1;
}
}
return 0;
}
复盘
void huifang()
{
background2();
MessageBox(GetHWnd(), "接下来对话框里的数字表示局数,查看请按是,跳过请按否", "提示", MB_YESNO);
for (int i = 1; i < e; i++)
{
sprintf(E, "%d.txt", i);//用变量打开一个文件
if (MessageBox(GetHWnd(), E, "提示", MB_YESNO) == 6)
{
fp = fopen(E, "r");
if (fp == NULL)
{
MessageBox(GetHWnd(), "文件打开失败", "提示", MB_YESNO);
exit(0);
}
for (o = 0; o < s[i]; o++)
{
fread(&fupan[o], sizeof(struct a), 1, fp);
if (fupan[o].color == -1)
{
setfillcolor(BLACK);
}
else
{
setfillcolor(WHITE);
}
solidcircle(fupan[o].x * 30 + 55, fupan[o].y * 30 + 55, 13);
if (MessageBox(GetHWnd(), "是否查看下一步棋", "提示", MB_YESNO) != 6)
{
break;
}
}
fclose(fp);
MessageBox(GetHWnd(), "该局的历史回放已完成", "提示", MB_OK);
for (int w = 0; w < 13 * 13; w++)
{
fupan[w] = { 0 };
}
}
else
{
continue;
}
background2();
}
MessageBox(GetHWnd(), "所有的历史回放查看完毕,游戏结束", "温馨提示", MB_OK);
exit(0);
}
接下来就主函数了
int main()
{
int board[13][13] = { 0 };//无棋子初始化为0
int True[13][13] = { 0 };//判断该空位是否在结构体中
int n = 0;//表示结构体空位的个数
int f = 0;//当双方都是4个棋子且有空位时优先选择进攻
int o = 0;//用来记录总的步数
int e = 1;//记录开局数用作文件命名
char E[100]={0};//存入一个字符串
int s[100] = { 0 };
FILE* fp;
struct position//计算空位的价值
{
int local;
int score;
};
position KongWei[13 * 13] = { {0,0} };
struct a
{
int x;
int y;
int color;
};
a fupan[13 * 13] = { {0,0,0} };
while(1)
{
computer();
player();
}
}
以上就是我写的子函数,如果大家对主函数进行修改会得到更好的模式,请大家自行发挥创造力进行组装吧!!!