五子棋实现人机对战,复盘,鼠标点击落子

今天验收五子棋大作业,实现人人对战、人机对战两种模式,实现五子棋复盘功能,运用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();
}
}

以上就是我写的子函数,如果大家对主函数进行修改会得到更好的模式,请大家自行发挥创造力进行组装吧!!!

  • 4
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值