扫雷的基本实现

  • 一,基本运行的过程
  • 二,代码实现
  • 一,打印菜单,写开始游戏的程序;
  • 二,创建两个地图,一个埋雷,一个用于显示;
  • 用于打印盘的的代码
  • 三,初始化地图
  • 设置雷
  • 四,排雷
  • 用于排雷、检查是否排雷完毕的代码
  • 三,难点
  • 一,布置雷
  • 二,数雷
  • 三,雷的放置
  • 四,打印、扫雷时
  • 五,未实现的功能


一,基本运行的过程

第一步:打印菜单,写开始游戏的程序;
第二步:创建两个地图,一个埋雷,一个用于显示;
第三步:将两个地图初始化;
第四步:排雷;
第五步:判断是否踩雷;
第六步:判断是否排除所有雷;

二,代码实现

一,打印菜单,写开始游戏的程序;

void muen()
{
	printf("***********************\n"); 
	printf("*********1.Play********\n");
	printf("*********0.Exit********\n");
	printf("***********************\n");
}
int main()
{
	int a = 1;
	do
	{
		muen();
		printf("请选择:>");
		scanf("%d", &a);
		switch (a)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏退出\n");
			break;
		default:
			printf("输入错误,请重新输入:\n");
		}
	} while (a);
	return 0;
}

二,创建两个地图,一个埋雷,一个用于显示;

先定义地图的大小,我们要写的地图为9*9,说以要创建11行11列的地图(为什么要创建11行11列的,待会会说)

#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
#define MINE 10
void game()
{
	int a = 1;
	char show[ROWS][COLS] = { 0 };//创建一个ROW行,COL列的二维数组用于显示扫雷区域
	char mine[ROWS][COLS] = { 0 };//创建一个ROW行,COL列的二维数组用于创建扫雷区域
	intnshow(show, ROWS, COLS);//初始化展示棋盘,使其全部为*
	intnmine(mine, ROWS, COLS);//初始化棋盘使其全部为0
	setmine(mine, ROW, COL);
	do
	{
		Displayshow(show, ROW, COL);//打印展示地图
		printf("请输入要排查的坐标:>");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		a=findmine(mine ,show, ROWS, COLS,x,y);
		if (a == 0)
			break;
		a=chakwin(show, ROWS, COLS);
		if (a == 0)
		{
			printf("恭喜你,排查完所有雷!\n");
			break;
		}

	} while (a);
}

用于打印盘的的代码

void Displayshow(char show[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
	printf("--------------扫雷游戏--------------\n");
	for (i = 0; i < rows; i++)
	{
		
		if (i == 0)//打印第一行列的坐标
		{
			printf("%d ", i);
			for (j = 0; j < cols; j++)
			{
					printf("%d ", j + 1);
			}
			printf("\n");
		}
		printf("%d ", i+1);//打印行数
		for (j = 0; j < cols; j++)
		{
		   printf("%c ", show[i][j]);
		}
		printf("\n");
	}
}

三,初始化地图

void intnshow(char show[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= rows; i++)
	{
		for (j = 0; j <= cols; j++)
		{
			show[i][j] = '*';
		}
	}
}
void intnmine(char show[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			show[i][j] = '0';
		}
	}
}

设置雷

void setmine(char mine[ROWS][COLS], int row, int col)
{
	int connut = 0;
    srand((unsigned)time(NULL));
	while ( connut < MINE)
	{
		int x = rand() % row+1;//让随机数在1~row
		int y = rand() % col+1;//让随机数在1~col
		if ((mine[x][y] == '0'))//当坐标不为‘0’时设置雷
		{
			mine[x][y] = '1';
			connut++;
		}
	}
}

这里使用时间作为随机数的种子

四,排雷

do
	{
		Displayshow(show, ROW, COL);
		printf("请输入要排查的坐标:>");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		a=findmine(mine ,show, ROWS, COLS,x,y);
		if (a == 0)
			break;
		a=chakwin(show, ROWS, COLS);
		if (a == 0)
		{
			printf("恭喜你,排查完所有雷!\n");
			break;
		}

用于排雷、检查是否排雷完毕的代码

int findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int x,int y)
{
	
	while (1)
	{
		if (x >= 1 && x <= row&&y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')//踩雷
			{
				printf("很遗憾,你被炸死了!\n");
				//Displayshow(mine, ROWS, COLS);
				return 0;
			}
			else
			{
				int count =get_mine_cunt(mine, x, y);
				show[x-1][y-1] = count + '0';
				if (count == 0)//当该坐标雷数为0时,根据规则周围都没雷,可以全部展开
				{
				findmines(mine, show, row, col, x, y-1);
				findmines(mine, show, row, col, x, y + 1);
				findmines(mine, show, row, col, x - 1, y + 1);
				findmines(mine, show, row, col, x - 1, y - 1);
				findmines(mine, show, row, col, x + 1, y+1);
				findmines(mine, show, row, col, x + 1, y-1);
				findmines(mine, show, row, col, x - 1, y);
				findmines(mine, show, row, col, x + 1, y);
				}
				return 1;
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
			return 1;
		}
	}
}

此处还有数雷的代码

int get_mine_cunt(char mine[ROWS][COLS], int x, int y)
{
	return mine[x][y - 1] +
		mine[x][y + 1] +
		mine[x - 1][y - 1] +
		mine[x - 1][y + 1] +
		mine[x + 1][y - 1] +
		mine[x + 1][y + 1] +
		mine[x - 1][y] +
		mine[x + 1][y] - 8 * '0';
}

设定11行11列,只需要其中9行9列,这可以让我们数类似与第一行第一列的代码时更方便

void findmines(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
	if (x >= 1 && x <= row&&y >= 1 && y <= col)
	{
		int count = get_mine_cunt(mine, x, y);
		show[x - 1][y - 1] = count + '0';
	}
}

检查是否排查完毕的代码

int chakwin(char show[ROWS][COL], int row, int col)
{
	int count = 0;
	int i = 1;
	int j = 1;
	for (i = 1; i <= ROWS; i++)
	{
		for (j = 1; j <= COLS; j++)
		{
			if (show[i][j] == '*')
				count++;
		}
	}
	if (count == (MINE+40))
		return 0;
	else
		return 1;
}

三,难点

一,布置雷

利用srand((unsigned)time(NULL));设置时间戳,利用rand函数随机设置雷;学习srand函数时,不知道到要对时间进行无符号类型转化,查阅资料后解决。

二,数雷

这里设置11行11列的地图,目的是能更方便的数1行1列位置的雷,在数第一行第一列的雷时,实际上是在数雷地图上的第2行第2列的坐标,这样就可以使数雷的时候直接数2行2列周围的8个格子就行,用简单代码,完成数雷的操作。

三,雷的放置

放置雷时,由于全部初始化为‘0’,所以放置时只需令其为’1’,数雷时只需将周围8个位置的值相加(建立的类型是char,故相加值是其ASC码值),再减去8*‘0‘就可以得到该坐标雷的数量,打印时要记得加上’0’,才是显示该坐标周围雷的数量。

四,打印、扫雷时

坐标一定要对齐!!!