C语言简易扫雷

用C语言完成简易扫雷游戏,我做的是棋盘大小8*8,10个雷的扫雷。

说明:

本人还是个新手,可能有些地方写的不是很好,请大家见谅。程序测试的也不够全面,可能存在bug,如果发现有bug或者代码不够规范还麻烦大佬们指正。

此程序比较简单,分享扫雷的大佬也很多,我这篇发出来也可以记录一下我的学习历程,也可以给感兴趣的人提供一些帮助。

另外,本人英语不是很好,所以大部分的函数名和变量名都是汉语拼音。

显示汉字时,有时候会发生俩汉字重叠的奇怪现象。

后续有需要的话我还会完善此文章。

注意:本程序中x为横坐标,代表列,y为纵坐标,代表行。(x,y)代表x列y行。


 

功能预期

1.运行程序后让玩家选择开始游戏还是退出游戏。

2.玩家选择开始游戏后,游戏开始。

3.棋盘8行8列10个雷。

4.每次玩家输入坐标(x,y)后,开始扫雷,判断输入坐标,如果已经选择过要有提示,如果选中了雷,显示游戏失败。

5.玩家第一次选择的坐标必不是雷。

6.每局游戏结束后不退出程序,而是询问玩家是否重新游戏。

7.若玩家输入无效信息,要给出提示并让玩家继续输入。

目录

一些准备

一些次要功能

界面:

获取是否开始游戏

获取输入的坐标

主要功能

清空棋盘

初始化

创建棋盘

取随机雷的位置

创建

选择坐标

显示雷

main函数

声明函数

总代码


一些准备

首先,在开始实现功能前,需要准备一些东西。

比如,棋盘每个格子的信息存放的地方。

这里我选择用结构体存储每个格子的数据。

struct GeZi {//格子
	char XianShi;//显示
	int LeiXing;//类型 1:雷 0:空
	int ZiShenShuZi;//自身数字=周围雷数
	char ZhuangTai;//状态 0:未选择 1:已选择
};

每个格子的数据包括:

1.显示:这个是在游戏界面显示出的信息。

2.类型:1的话是雷,0的话是空地。

3.自身数字:这个数据代表了周围8个方位的雷数。

4.状态:0代表未被选择,1代表已经被选择。

所有的头文件如下:
 

#include 
#include 
#include 
#include 

所有的全局变量如下:

int YiWanCheng = 0; //已完成排除雷的格子数量
struct GeZi Pan[10][10] = {};//棋盘
int CiShu = 0;//即将开始的场次
char s[7][50] = {'\0'};//提示区内容
int Lei[15] = {0};//存储雷的位置

一些次要功能

其次 我对游戏界面有一些个性化的设置。

界面:

╔═══════════════════════╗
║    1 2 3 4 5 6 7 8    ║
║  ╔═════════════════╗  ║
║ 1║                 ║ 1║
║ 2║                 ║ 2║
║ 3║                 ║ 3║
║ 4║                 ║ 4║
║ 5║                 ║ 5║
║ 6║                 ║ 6║
║ 7║                 ║ 7║
║ 8║                 ║ 8║
║  ╚═════════════════╝  ║
║    1 2 3 4 5 6 7 8    ║
╚═══════════════════════╝
╔═══════════════════════╗
║提示:                 ║
║棋盘大小:8×8 雷数:10  ║
║输入1:开始游戏;       ║
║输入0:退出游戏;       ║
║                       ║
║                       ║
║                       ║
╚═══════════════════════╝
请输入:

 我希望它的程序界面长这样。(有些框在这里对不齐)

我把这个界面分为三部分,上面的游戏区,中间的提示区,以及下面的输入区。

因为界面大体不变,每次只需要更改一些字,为了方便,我尝试把这些打包写入到一个Print函数中。在输出前可以选择清除之前输出的内容,只显示最新的输出。下面是我写的Print函数。

int Print() { //输出基本界面
	int i = 0;
	int j = 0;

	system("CLS");//清屏
	printf("╔═══════════════════════╗\n");
	printf("║    1 2 3 4 5 6 7 8    ║\n");
	printf("║  ╔═════════════════╗  ║\n");

	for (i = 1; i <= 8; i++) {
		printf("║ %d║ ", i);
		for (j = 1; j <= 8; j++) {
			printf("%c ", Pan[i][j].XianShi);
		}
		printf("║ %d║\n", i);
	}

	printf("║  ╚═════════════════╝  ║\n");
	printf("║    1 2 3 4 5 6 7 8    ║\n");
	printf("╚═══════════════════════╝\n");
	printf("╔═══════════════════════╗\n");
	printf("║提示:                 ║\n");

	for (i = 1; i <= 6; i++) {
		printf("║%s║\n", s[i]); //s[i]每行23显示字符

	}




	printf("╚═══════════════════════╝\n");
	printf("请输入:");



}

说明:system("CLS")可以清空之前输出的内容

s[1]~s[6]是全局变量,记录着要输出的提示信息。

获取是否开始游戏

接下来,是获取有效的输入。一个是每局游戏开始前或者结束后,输入1开始游戏或者重新游戏,还是输入0退出程序。另一个是判断输入的坐标是否有效。

CiShu(次数)是一个全局变量,记录着这是第几局游戏。其主要目的是判断即将进行的是否是第一局游戏。如果是第一局游戏,则提示开始游戏,否则提示重新开始。

No1就是一个标识而已。

int ShiFouKaiShi() { //是否开始;
	int No1 = -1;
	char a = '\0';
	do {
		a = '\0';
		scanf("%d", &No1);
		a = getchar();
		while (a != '\n') {//清空缓冲区
			if (a == ' ') {


			} else {
				No1 = -1;//存在多余内容,判定输入无效

			}
			a = getchar();
		}
		if (No1 != 0 && No1 != 1) {//输入不是0和1,则判定输入无效
			No1 = -1;
		}
		if (No1 == -1) {//输入数据无效
			strcpy(s[1], "棋盘大小:8×8 雷数:10  ");
			strcpy(s[3], "输入0:退出游戏;       ");
			strcpy(s[4], "                       ");
			strcpy(s[5], "                       ");
			strcpy(s[6], "请输入有效数据         ");
			if (CiShu == 1) {
				strcpy(s[2], "输入1:开始游戏;       ");
			} else {
				strcpy(s[2], "输入1:重新开始;       ");
			}
			Print();
		}


	} while (No1 == -1);//此循环获取是否进入游戏
	return No1;
}

获取输入的坐标

int ShuRuZuoBiao(int *px, int *py) {//获取输入的坐标
	int x = 0;
	int y = 0;
	int n = 0; //输入整数个数
	char a = '\0'; //获取缓冲区字符
	int b = 1; //判断标志 1为有效
	do {
		b = 1;
		n = scanf("%d%d", &x, &y);
		a = getchar();
		while (a != '\n') {//清空缓冲区
			if (a == ' ') {


			} else {
				b = -1;//有多余内容,判定为输入无效

			}
			a = getchar();

		}
		if (n != 2 || x < 1 || x > 8 || y < 1 || y > 8) {//读入的不是2个整数,或读入的坐标不在棋盘范围内,判定为输入无效
			b = -1;
		}
		if (b == -1) {
			strcpy(s[2], "请输入选择的坐标x y    ");
			strcpy(s[3], "(中间用空格或换行分隔) ");
			strcpy(s[4], "                       ");
			strcpy(s[5], "                       ");
			strcpy(s[6], "请输入有效数据         ");

			Print();
		}
	} while (b == -1);
	if (b == 1) {
		*px = x;
		*py = y;
		strcpy(s[6], "                       ");
	}
	return b;
}

主要功能

接下来,我们就可以开始主要功能的编写了。

首先,在全局变量中创建出棋盘Pan。并且记录一下当前以确定没雷格子的数量YiWanCheng。同时,为了方便,我在全局变量中用一个数组(Lei)记录了雷的位置,第i个雷位置存在Lei[i]里。

struct GeZi Pan[10][10] = {};
int YiWanCheng = 0; //已完成排除雷的格子数量
int Lei[15] = {0};//记录10个雷的位置

清空棋盘

每局游戏开始前,都需要让棋盘中所有格子恢复默认值,同时使已完成排雷的格子的数量清0,让Lei[1]~lei[10]清零。为了方便,我把上述操作写为一个函数,QingKongQiPan

int QingKongQiPan() { //清空棋盘
	int i = 0;
	int j = 0;
	for (i = 1; i <= 8; i++) {//恢复棋盘中格子的信息
		for (j = 1; j <= 8; j++) {
			Pan[i][j].XianShi = ' ';
			Pan[i][j].ZhuangTai = 0;
			Pan[i][j].LeiXing = 0;
			Pan[i][j].ZiShenShuZi = 0;
		}
	}
	for (i = 1; i <= 10; i++) {//清空雷的位置
		Lei[i] = 0;

	}
	YiWanCheng = 0;//已完成排雷数归零
	return 0;
}

初始化

在第一局游戏正式开始前,将游戏初始化一下,包括清空棋盘和初始化全局变量的s数组。

int ChuShiHua() {//初始化
	QingKongQiPan();
	strcpy(s[1], "棋盘大小:8×8 雷数:10  ");
	strcpy(s[2], "输入1:开始游戏;       ");
	strcpy(s[3], "输入0:退出游戏;       ");
	strcpy(s[4], "                       ");
	strcpy(s[5], "                       ");
	strcpy(s[6], "                       ");

}

创建棋盘

接着,就该写给棋盘写入初始信息的功能了。

取随机雷的位置

因为雷的位置要随机,所以,需要先取随机数。这里的随机数有点要求,因为棋盘大小是8*8,就是64个格子,一共有10个雷,所以,要在1~64之间随机取10个不同的数,将8*8的棋盘的格子依次编号,每个与随机数大小相等的编号的格子类型设置为雷。因为扫雷要求,第一次选的必不是雷,所以我的思路是等玩家输入了第一对有效坐标后,再创建棋盘。因此,我要完成的功能就是从1~64之间随机选10个不等的数,且每个随机数对应的格子都不是第一个有效坐标对应的格子。

我们需要利用中的srand()和rand()函数。注意,如果只用rand(),会发现每局游戏的随机数是一样的。所以,为了雷位置随机,要在rand()前写上srand(time(0));这样才能获得到比较随机的随机数。但这样取得的随机数范围不在1~64之间,因此我们需要让取到的数对64取余数,现在得到的数范围在0~63之间了,只需要将这个数再加1,得到的数范围就在1~64之间了。用n记录已经取到的雷数,将第i个取到的数保存到Lei[i]中,使雷数n=n+1;

下面,还需要判断如果两个数相等,就再取新的数,避免一个格子不止一个雷的情况。完成这个小功能,我用的方法是设置一个int型数组c,c[i]==0表示i编号对应格子没有保存为雷,c[i]==1代表i编号对应的格子已被选择为雷。在每次获得随机数b后,判断c[b]是否为1,为1的话就舍弃当前随机数再取一个。

之前还提到了要避开第一个有效坐标(x,y),(x,y)对应的编号为(8*(y-1)+x),所以只需要在开头让c[8*(y-1)+x]=1即可,使对应编号被假想为雷,但是不保存到Lei数组,也不增加雷的个数n。

n>=10时,即雷数量够了,便停止取随机数。

把上述功能写进取随机数(QuSuiJiShu)函数。

int QuSuiJiShu(int x, int y) { //1-64之间取10个不同随机数,且不为输入的坐标(即(y-1)*8+x)对应值,并存到Lei里
	int n = 0;//记录已经取到的雷数
	int b = 0; //暂存随机数的变量
	int c[70] = {0}; //暂存已得随机数的数组
	c[(y - 1) * 8 + x] = 1;//假定坐标位是雷

	srand(time(0));//不能删
	while (n < 10) {
		b = rand();
		b = b % 64;//取0~63的随机数
		b = b + 1;//调整随机数范围
		if (c[b] != 1) {//判断是否可以在新生成的随机数对应格子放置雷
			c[b] = 1;//标记此位置是雷
			n = n + 1;//雷数+1
			Lei[n] = b;//将编号存入Lei
		}
	}
	return 0;

}

创建

取完随机的雷的位置了,就可以创建棋盘了。

保险起见,把Pan中所有格子的类型都变为空地,所有自身数字都变为0

接下来用刚刚写的取随机数函数获取10个雷的编号。将对应编号分别转换为对应的格子,并将其类型改为雷。

自身数字,就是周围雷数。通过刚刚的一些操作,使空地和非游戏区格子的类型为0,雷的类型为1,所以,只需要将每个游戏区格子8个方向的格子的类型加起来,就是自己的自身数字。

把这些功能写进创建(ChuangJian)函数。

int ChuangJian(int x, int y) { //创建一个(x,y)必不是雷的棋盘
	int i = 0;
	int j = 0;
	QuSuiJiShu( x, y);//取10个随机雷

	for (i = 0; i <= 9; i++) {//此处要对Pan数组内所有成员操作
		for (j = 0; j <= 9; j++) {
			Pan[i][j].LeiXing = 0;
			Pan[i][j].ZiShenShuZi = 0;

		}
	}
	for (i = 1; i <= 10; i++) {//使10个雷对应格子标记为雷

		if (Lei[i] % 8 == 0) {
			Pan[Lei[i] / 8 ][8 ].LeiXing = 1;
		} else {
			Pan[Lei[i] / 8 + 1][Lei[i] % 8 ].LeiXing = 1;
		}

	}
	for (i = 1; i <= 8; i++) {//使每个游戏区格子的自身数字等于其8个周围格子的类型之和
		for (j = 1; j <= 8; j++) {
			Pan[i][j].ZiShenShuZi = Pan[i - 1][j - 1].LeiXing + Pan[i - 1][j].LeiXing + Pan[i - 1][j + 1].LeiXing ;
			Pan[i][j].ZiShenShuZi = Pan[i][j].ZiShenShuZi + Pan[i][j -  1].LeiXing + Pan[i][j + 1].LeiXing;
			Pan[i][j].ZiShenShuZi = Pan[i][j].ZiShenShuZi + Pan[i + 1][j - 1].LeiXing + Pan[i + 1][j].LeiXing ;
			Pan[i][j].ZiShenShuZi = Pan[i][j].ZiShenShuZi + Pan[i + 1][j + 1].LeiXing;
		}
	}
	return 0;
}

至此,棋盘就创建完成了。

选择坐标

接下来,便是紧张又刺激的扫雷过程了。

接下来,写一个选择(XuanZe)函数,XuanZe(x,y)代表玩家选择了(x,y)

当(x,y)被选择过时,即Pan[y][x].zhuangtai==1时,返回1

当(x,y)是雷时,即Pan[y][x].LeiXing==1时,返回-1

当(x,y)既没被选择过,又不是雷,那么就把(x,y)改为选择状态,已完成排雷格子数+1,并且将Pan[y][x].XianShi改为自身数字,这里要注意,Pan[y][x].XianShi是char型,而Pan[y][x].LeiXing是int型,所以需要将Pan[y][x].LeiXing转换为char型,即Pan[y][x].LeiXing-'0',再赋值给Pan[y][x].XianShi。当自身数字为0时,代表周围8个格子都没有雷,则自动选择周围没有被选择过的游戏区格子。

int XuanZe(int x, int y) {//选择(x,y) 返回0:正常 -1:踩雷,游戏结束 1:已被选择
	if (Pan[y][x].ZhuangTai == 1) {//已经被选择过
		return 1;
	} else {
		if (Pan[y][x].LeiXing == 1) {//选择的坐标是雷
			return -1;
		} else {
			YiWanCheng = YiWanCheng + 1;//已完成排雷格子数+1
			Pan[y][x].XianShi = Pan[y][x].ZiShenShuZi + '0';//显示出类型转换后的自身数字
			Pan[y][x].ZhuangTai = 1;//标记被选择
			if (Pan[y][x].ZiShenShuZi == 0) {//分别选择周围8个未被选择的游戏区格子
				if (Pan[y - 1][x - 1].ZhuangTai == 0 && y - 1 >= 1 && x - 1 >= 1) {
					XuanZe(x - 1, y - 1);
				}
				if (Pan[y - 1][x].ZhuangTai == 0 && y - 1 >= 1) {
					XuanZe(x, y - 1);
				}
				if (Pan[y - 1][x + 1].ZhuangTai == 0 && y - 1 >= 1 && x + 1 <= 8) {
					XuanZe(x + 1, y - 1);
				}
				if (Pan[y ][x - 1].ZhuangTai == 0 && x - 1 >= 1) {
					XuanZe(x - 1, y );
				}
				if (Pan[y][x + 1 ].ZhuangTai == 0 && x + 1 <= 8) {
					XuanZe(x + 1, y );
				}
				if (Pan[y + 1][x - 1].ZhuangTai == 0 && y + 1 <= 8 && x - 1 >= 1) {
					XuanZe(x - 1, y + 1);
				}
				if (Pan[y + 1][x ].ZhuangTai == 0 && y + 1 <= 8) {
					XuanZe(x, y + 1);
				}
				if (Pan[y + 1][x + 1].ZhuangTai == 0 && y + 1 <= 8 && x + 1 <= 8) {
					XuanZe(x + 1, y + 1);
				}
			}

			return 0;
		}
	}


}

显示雷

如果成功扫雷或者不幸踩雷,将所有雷的位置显示出来。

定义一个显示雷(XianShiLei)函数,把所有雷的格子的.XianShi改为'*',标记出雷的位置。

int XianShiLei() {
	int i = 0;
	for (i = 1; i <= 10; i++) {
		if (Lei[i] % 8 == 0) {
			Pan[Lei[i] / 8 ][8 ].XianShi = '*';
		} else {
			Pan[Lei[i] / 8 + 1][Lei[i] % 8 ].XianShi = '*';
		}

	}
}

main函数

至此,大部分功能已经完成,现在开始main函数编写。

初始化后,将显示信息打印出来。即将开始第1局游戏,标记CiShu=1。之后判断玩家是否想开始游戏,当选择开始游戏后,让玩家输入第一组坐标。之后通过这个坐标来创建棋盘,接着选择第一组输入的坐标,接下来输出需要显示的信息。接下来,在已完成排雷数小于54(64个格子,10个雷,一共54个空地)时,重复让玩家输入坐标,选择坐标的操作,如果选择过则提示,如果是雷则跳出循环。每次判断后,都需要输出需要显示的内容,用来即使更新信息。当已排除雷数到达54时,证明扫雷已经完成,提示扫雷成功并询问是否重新游戏。

int main() {
	int No1 = -1;
	int x = 0;//横坐标(列)
	int y = 0;//纵坐标(行)
	int c = 0;//输入坐标返回标识


	ChuShiHua();//第一局游戏开始前,初始化一下一些信息

	Print();//输出需要显示的信息
	CiShu = 1;//即将开始第1局游戏
	No1 = ShiFouKaiShi();//获取是否开始信息

	while (No1 == 1) {//玩家确定开始游戏
		x = 0;
		y = 0;

		strcpy(s[2], "请输入选择的坐标x y    ");
		strcpy(s[3], "(中间用空格或换行分隔) ");
		strcpy(s[6], "                       ");
		Print();//提示信息更新并输出



		ShuRuZuoBiao (&x, &y);//输入有效(x,y)

		ChuangJian(x, y);//创建棋盘
		c = XuanZe(x, y);//选择第一个坐标
		Print();//输出信息


		while (YiWanCheng < 54) {//成功扫雷前,不断扫雷
			ShuRuZuoBiao (&x, &y);//输入有效坐标

			c = XuanZe(x, y);//选择输入的坐标
			if (c == 1) {//坐标被选择过
				strcpy(s[6], "您输入的坐标已被选择   ");
			} else if (c == -1) {//选择到了雷
				strcpy(s[6], "游戏失败               ");
				break;//跳出循环,本轮游戏结束
			} else {

			}
			Print();


		}
        //本轮游戏结束
		if (YiWanCheng == 54) {//是否成功找到了54个空地
			strcpy(s[6], "成功扫雷               ");

		}
		strcpy(s[1], "棋盘大小:8×8 雷数:10  ");
		strcpy(s[2], "输入1:重新开始;       ");
		strcpy(s[3], "输入0:退出游戏;       ");
		XianShiLei();//将所有雷位置显示出来
		Print();//输出需要显示的信息
		No1 = ShiFouKaiShi();//询问玩家是否再来一局
		QingKongQiPan();//清空棋盘数据
		Print();//输出信息
		CiShu = CiShu + 1;//即将开始的次数+1
	}


	return 0;
}

声明函数

最后,别忘了声明一下自己定义的函数

int ChuShiHua();
int ShuRuZuoBiao(int *px, int *py);
int QuSuiJiShu( int x, int y);
int ChuangJian(int x, int y);
int XuanZe(int x, int y) ;
int ShiFouKaiShi();
int QingKongQiPan();
int XianShiLei();
int Print();

总代码

#include 
#include 
#include 
#include 

struct GeZi {//格子
	char XianShi;//显示
	int LeiXing;//类型 1:雷 0:空
	int ZiShenShuZi;//自身数字=周围雷数
	char ZhuangTai;//状态 0:未选择 1:已选择
};



int YiWanCheng = 0; //已完成排除雷的格子数量
struct GeZi Pan[10][10] = {};//棋盘
int CiShu = 0;//即将开始的场次
char s[7][50] = {'\0'};//提示区内容
int Lei[15] = {0};//存储雷的位置

int ChuShiHua();
int ShuRuZuoBiao(int *px, int *py);
int QuSuiJiShu( int x, int y);
int ChuangJian(int x, int y);
int XuanZe(int x, int y) ;
int ShiFouKaiShi();
int QingKongQiPan();
int XianShiLei();
int Print();

int main() {
	int No1 = -1;
	int x = 0;//横坐标(列)
	int y = 0;//纵坐标(行)
	int c = 0;//输入坐标返回标识


	ChuShiHua();//第一局游戏开始前,初始化一下一些信息

	Print();//输出需要显示的信息
	CiShu = 1;//即将开始第1局游戏
	No1 = ShiFouKaiShi();//获取是否开始信息

	while (No1 == 1) {//玩家确定开始游戏
		x = 0;
		y = 0;

		strcpy(s[2], "请输入选择的坐标x y    ");
		strcpy(s[3], "(中间用空格或换行分隔) ");
		strcpy(s[6], "                       ");
		Print();//提示信息更新并输出



		ShuRuZuoBiao (&x, &y);//输入有效(x,y)

		ChuangJian(x, y);//创建棋盘
		c = XuanZe(x, y);//选择第一个坐标
		Print();//输出信息


		while (YiWanCheng < 54) {//成功扫雷前,不断扫雷
			ShuRuZuoBiao (&x, &y);//输入有效坐标

			c = XuanZe(x, y);//选择输入的坐标
			if (c == 1) {//坐标被选择过
				strcpy(s[6], "您输入的坐标已被选择   ");
			} else if (c == -1) {//选择到了雷
				strcpy(s[6], "游戏失败               ");
				break;//跳出循环,本轮游戏结束
			} else {

			}
			Print();


		}
		//本轮游戏结束
		if (YiWanCheng == 54) {//是否成功找到了54个空地
			strcpy(s[6], "成功扫雷               ");

		}
		strcpy(s[1], "棋盘大小:8×8 雷数:10  ");
		strcpy(s[2], "输入1:重新开始;       ");
		strcpy(s[3], "输入0:退出游戏;       ");
		XianShiLei();//将所有雷位置显示出来
		Print();//输出需要显示的信息
		No1 = ShiFouKaiShi();//询问玩家是否再来一局
		QingKongQiPan();//清空棋盘数据
		Print();//输出信息
		CiShu = CiShu + 1;//即将开始的次数+1
	}


	return 0;
}

int Print() { //输出基本界面
	int i = 0;
	int j = 0;

	system("CLS");//清屏
	printf("╔═══════════════════════╗\n");
	printf("║    1 2 3 4 5 6 7 8    ║\n");
	printf("║  ╔═════════════════╗  ║\n");

	for (i = 1; i <= 8; i++) {
		printf("║ %d║ ", i);
		for (j = 1; j <= 8; j++) {
			printf("%c ", Pan[i][j].XianShi);
		}
		printf("║ %d║\n", i);
	}

	printf("║  ╚═════════════════╝  ║\n");
	printf("║    1 2 3 4 5 6 7 8    ║\n");
	printf("╚═══════════════════════╝\n");
	printf("╔═══════════════════════╗\n");
	printf("║提示:                 ║\n");

	for (i = 1; i <= 6; i++) {
		printf("║%s║\n", s[i]); //s[i]每行23显示字符

	}




	printf("╚═══════════════════════╝\n");
	printf("请输入:");



}


int ShiFouKaiShi() { //是否开始;
	int No1 = -1;
	char a = '\0';
	do {
		a = '\0';
		scanf("%d", &No1);
		a = getchar();
		while (a != '\n') {//清空缓冲区
			if (a == ' ') {


			} else {
				No1 = -1;//存在多余内容,判定输入无效

			}
			a = getchar();
		}
		if (No1 != 0 && No1 != 1) {//输入不是0和1,则判定输入无效
			No1 = -1;
		}
		if (No1 == -1) {//输入数据无效
			strcpy(s[1], "棋盘大小:8×8 雷数:10  ");
			strcpy(s[3], "输入0:退出游戏;       ");
			strcpy(s[4], "                       ");
			strcpy(s[5], "                       ");
			strcpy(s[6], "请输入有效数据         ");
			if (CiShu == 1) {
				strcpy(s[2], "输入1:开始游戏;       ");
			} else {
				strcpy(s[2], "输入1:重新开始;       ");
			}
			Print();
		}


	} while (No1 == -1);//此循环获取是否进入游戏
	return No1;
}

int ShuRuZuoBiao(int *px, int *py) {//获取输入的坐标
	int x = 0;
	int y = 0;
	int n = 0; //输入整数个数
	char a = '\0'; //获取缓冲区字符
	int b = 1; //判断标志 1为有效
	do {
		b = 1;
		n = scanf("%d%d", &x, &y);
		a = getchar();
		while (a != '\n') {//清空缓冲区
			if (a == ' ') {


			} else {
				b = -1;//有多余内容,判定为输入无效

			}
			a = getchar();

		}
		if (n != 2 || x < 1 || x > 8 || y < 1 || y > 8) {//读入的不是2个整数,或读入的坐标不在棋盘范围内,判定为输入无效
			b = -1;
		}
		if (b == -1) {
			strcpy(s[2], "请输入选择的坐标x y    ");
			strcpy(s[3], "(中间用空格或换行分隔) ");
			strcpy(s[4], "                       ");
			strcpy(s[5], "                       ");
			strcpy(s[6], "请输入有效数据         ");

			Print();
		}
	} while (b == -1);
	if (b == 1) {
		*px = x;
		*py = y;
		strcpy(s[6], "                       ");
	}
	return b;
}

int QingKongQiPan() { //清空棋盘
	int i = 0;
	int j = 0;
	for (i = 1; i <= 8; i++) {//恢复棋盘中格子的信息
		for (j = 1; j <= 8; j++) {
			Pan[i][j].XianShi = ' ';
			Pan[i][j].ZhuangTai = 0;
			Pan[i][j].LeiXing = 0;
			Pan[i][j].ZiShenShuZi = 0;
		}
	}
	for (i = 1; i <= 10; i++) {//清空雷的位置
		Lei[i] = 0;

	}
	YiWanCheng = 0;//已完成排雷数归零
	return 0;
}

int ChuShiHua() {//初始化
	QingKongQiPan();
	strcpy(s[1], "棋盘大小:8×8 雷数:10  ");
	strcpy(s[2], "输入1:开始游戏;       ");
	strcpy(s[3], "输入0:退出游戏;       ");
	strcpy(s[4], "                       ");
	strcpy(s[5], "                       ");
	strcpy(s[6], "                       ");

}

int QuSuiJiShu(int x, int y) { //1-64之间取10个不同随机数,且不为输入的坐标(即(y-1)*8+x)对应值,并存到Lei里
	int n = 0;//记录已经取到的雷数
	int b = 0; //暂存随机数的变量
	int c[70] = {0}; //暂存已得随机数的数组
	c[(y - 1) * 8 + x] = 1;//假定坐标位是雷

	srand(time(0));//不能删
	while (n < 10) {
		b = rand();
		b = b % 64;//取0~63的随机数
		b = b + 1;//调整随机数范围
		if (c[b] != 1) {//判断是否可以在新生成的随机数对应格子放置雷
			c[b] = 1;//标记此位置是雷
			n = n + 1;//雷数+1
			Lei[n] = b;//将编号存入Lei
		}
	}
	return 0;

}

int ChuangJian(int x, int y) { //创建一个(x,y)必不是雷的棋盘
	int i = 0;
	int j = 0;
	QuSuiJiShu( x, y);//取10个随机雷

	for (i = 0; i <= 9; i++) {//此处要对Pan数组内所有成员操作
		for (j = 0; j <= 9; j++) {
			Pan[i][j].LeiXing = 0;
			Pan[i][j].ZiShenShuZi = 0;

		}
	}
	for (i = 1; i <= 10; i++) {//使10个雷对应格子标记为雷

		if (Lei[i] % 8 == 0) {
			Pan[Lei[i] / 8 ][8 ].LeiXing = 1;
		} else {
			Pan[Lei[i] / 8 + 1][Lei[i] % 8 ].LeiXing = 1;
		}

	}
	for (i = 1; i <= 8; i++) {//使每个游戏区格子的自身数字等于其8个周围格子的类型之和
		for (j = 1; j <= 8; j++) {
			Pan[i][j].ZiShenShuZi = Pan[i - 1][j - 1].LeiXing + Pan[i - 1][j].LeiXing + Pan[i - 1][j + 1].LeiXing ;
			Pan[i][j].ZiShenShuZi = Pan[i][j].ZiShenShuZi + Pan[i][j -  1].LeiXing + Pan[i][j + 1].LeiXing;
			Pan[i][j].ZiShenShuZi = Pan[i][j].ZiShenShuZi + Pan[i + 1][j - 1].LeiXing + Pan[i + 1][j].LeiXing ;
			Pan[i][j].ZiShenShuZi = Pan[i][j].ZiShenShuZi + Pan[i + 1][j + 1].LeiXing;
		}
	}
	return 0;
}

int XuanZe(int x, int y) {//选择(x,y) 返回0:正常 -1:踩雷,游戏结束 1:已被选择
	if (Pan[y][x].ZhuangTai == 1) {//已经被选择过
		return 1;
	} else {
		if (Pan[y][x].LeiXing == 1) {//选择的坐标是雷
			return -1;
		} else {
			YiWanCheng = YiWanCheng + 1;//已完成排雷格子数+1
			Pan[y][x].XianShi = Pan[y][x].ZiShenShuZi + '0';//显示出类型转换后的自身数字
			Pan[y][x].ZhuangTai = 1;//标记被选择
			if (Pan[y][x].ZiShenShuZi == 0) {//分别选择周围8个未被选择的游戏区格子
				if (Pan[y - 1][x - 1].ZhuangTai == 0 && y - 1 >= 1 && x - 1 >= 1) {
					XuanZe(x - 1, y - 1);
				}
				if (Pan[y - 1][x].ZhuangTai == 0 && y - 1 >= 1) {
					XuanZe(x, y - 1);
				}
				if (Pan[y - 1][x + 1].ZhuangTai == 0 && y - 1 >= 1 && x + 1 <= 8) {
					XuanZe(x + 1, y - 1);
				}
				if (Pan[y ][x - 1].ZhuangTai == 0 && x - 1 >= 1) {
					XuanZe(x - 1, y );
				}
				if (Pan[y][x + 1 ].ZhuangTai == 0 && x + 1 <= 8) {
					XuanZe(x + 1, y );
				}
				if (Pan[y + 1][x - 1].ZhuangTai == 0 && y + 1 <= 8 && x - 1 >= 1) {
					XuanZe(x - 1, y + 1);
				}
				if (Pan[y + 1][x ].ZhuangTai == 0 && y + 1 <= 8) {
					XuanZe(x, y + 1);
				}
				if (Pan[y + 1][x + 1].ZhuangTai == 0 && y + 1 <= 8 && x + 1 <= 8) {
					XuanZe(x + 1, y + 1);
				}
			}

			return 0;
		}
	}


}

int XianShiLei() {
	int i = 0;
	for (i = 1; i <= 10; i++) {
		if (Lei[i] % 8 == 0) {
			Pan[Lei[i] / 8 ][8 ].XianShi = '*';
		} else {
			Pan[Lei[i] / 8 + 1][Lei[i] % 8 ].XianShi = '*';
		}

	}
}

你可能感兴趣的