C语言 - 你一定能看懂的扫雷万字详解(加入了递归展开和手动标雷的功能)

news2024/11/20 4:33:38

C语言之扫雷详解(包含递归展开和手动标雷功能,非常强大!)

文章目录

  • 一.写在前面
  • 二.效果展示
  • 三.整体逻辑
  • 四.详解
    • 1.进入主函数,打印菜单,玩家作出选择
    • 2.定义棋盘的数组并进行赋值
    • 3.棋盘的展示
    • 4.随机布雷
    • 5.开始扫雷
  • 五.递归展开和手动标记(注意到很多博主未提到这两个功能,所以我把这两个功能单独说一下,希望能帮助到你)
    • 1.递归展开
    • 2.手动标记

一.写在前面

🐶1.扫雷是windows的一款经典益智小游戏,我们在学习编程的时候尝试制作扫雷游戏,不能能激发我们学习编程的兴趣,更能提高我们的编程能力,所以自己尝试着去制作一个扫雷游戏是很有意义的。
🐭2.代码中我采用我使用两个数组,一个数组用来记录某个位置是否有雷(MyBoard数组),另一个数组用来记录这个位置周围有多少雷(NumBoard数组)。
🐹3.代码中我采用了宏定义,将ROW和COL定义为 9 ,将ROW和COL定义为ROW+2和COL+2,不仅易于理解,更便于修改。
🐰4.代码中我加入了清屏函数,在每次打印棋盘之前进行清屏,使得输出更加清爽。
🐺5.另外,我加入了递归展开功能,如果一个坐标周围都没有雷,那么会进入递归,会将这个坐标周围的坐标的周围的雷的数量都会显示出来(就是那个点一下出现一大片的功能)。
🐸6.我还加入手动标雷功能,在已经确定某个坐标处一定有雷后,可以对这个坐标进行标记,使得游戏更加方便。
🐯7.在代码中我加入了大量的注释,这可能使得代码看起来有点长,但是便于理解。

二.效果展示

🔆 游戏菜单
在这里插入图片描述

🔆棋盘展示
在这里插入图片描述

🔆 开始下棋
在这里插入图片描述

三.整体逻辑

1.打印菜单
2.玩家选择
3.定义两个棋盘并对棋盘的元素赋值
4.玩家下棋
5.游戏结束

游戏整体逻辑在game函数中实现,game函数代码如下:

void game()
{
	// 进入游戏,定义棋盘数组
	// 这里需定义两个棋盘数组
	// 一个棋盘是为了显示这个位置有没有雷,另外一个棋盘是为了显示这个位置周围的雷数
	// 每个棋盘的数组大小都要是行和列的数目加2,防止排查周围雷的数量时出现越界现象
	
	// 这个棋盘数组是为了标记这个位置是否有雷,无雷为0,有雷为1
	char MyBoard[ROWS][COLS] = { 0 };   

	// 这个棋盘数组是为了显示这个位置周围有多少雷
	char NumBoard[ROWS][COLS]= { 0 };  

	// 在定义棋盘之后,我们就要对两个数组棋盘的元素进行赋值
	InitBoard(MyBoard, NumBoard, ROW, COL);

	// 在赋值之后,展示棋盘
	DisplayBoard(NumBoard, ROW, COL);

	// 在初始化且展示之后,我们就要开始布雷了
	SetBoard(MyBoard, ROW, COL);

	// 开始扫雷
	Find(MyBoard, NumBoard, ROW, COL);
}

四.详解

1.进入主函数,打印菜单,玩家作出选择

进入主函数后首先打印游戏菜单,用do while语句模拟选择功能。
如果玩家选择 1 ,游戏开始。
如果玩家选择 0 ,游戏结束。
如果玩家输入了其他数字,系统提醒玩家重新输入。
代码如下:

int main()
{
	// 打印游戏菜单,指导玩家作出选择
	menu();
	
	// 利用do while语句模拟玩家的选择
	// 玩家选择 1 进入游戏,游戏结束后跳出循环
	// 玩家选择 0 直接退出循环,表示结束游戏
	// 玩家若选择其他,提醒玩家重新输入
	int input = 0;
	do
	{
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input != 0 && input != 1);
}
void menu()
{
	printf("***********************\n");
	printf("*****   1. play   *****\n");
	printf("*****   0. exit   *****\n");
	printf("***********************\n");
}

2.定义棋盘的数组并进行赋值

进入游戏后,为了方便写代码,这里我们需要用到两个数组,并且数组的大小都为11 * 11(以9 * 9的棋盘为例)。
用到两个数组的原因
我们既要用数组标记某个位置是否有雷,又要用数组记录这个位置周围有多少雷,用一个数组实现的话不太方便,我们最好使用两个数组
数组的大小都为11 * 11的原因:
后期我们为了统计某个位置周围雷的数量,需要遍历这个位置周围的八个位置的雷的情况,如果是9*9的数组的话,在边界时,遍历某个坐标周围的雷的情况,会出现数组越界现象。为了防止数组越界,我们使用的数组大小都要为11 * 11。
代码如下:

	// 进入游戏,定义棋盘数组
	// 这里需定义两个棋盘数组
	// 一个棋盘是为了显示这个位置有没有雷,另外一个棋盘是为了显示这个位置周围的雷数
	// 每个棋盘的数组大小都要是行和列的数目加2,防止排查周围雷的数量时出现越界现象
	
	// 这个棋盘数组是为了标记这个位置是否有雷,无雷为0,有雷为1
	char MyBoard[ROWS][COLS] = { 0 };   

	// 这个棋盘数组是为了显示这个位置周围有多少雷
	char NumBoard[ROWS][COLS]= { 0 };  

	// 在定义棋盘之后,我们就要对两个数组棋盘的元素进行赋值
	InitBoard(MyBoard, NumBoard, ROW, COL);
void InitBoard(char MyBoard[ROWS][COLS], char NumBoard[ROWS][COLS], int row, int col)
{
	// 玩家进入游戏后看不到周围雷的数量,只是看到了坐标
	// 我们规定玩家看到的坐标为星号

	int i = 0;
	int j = 0;

	// 对NumBoard棋盘数组的元素进行赋值
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			MyBoard[i][j] = '0';
		}
	}

	// 对NumBoard棋盘数组的元素进行赋值
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			NumBoard[i][j] = '*';
		}
	}
}

3.棋盘的展示

在定义和打印棋盘之后,我们就要将棋盘展示给玩家看。
为了使得棋盘看起来不那么枯燥,我们也有必要添加一些其他的元素到棋盘中。
棋盘展示的代码如下:

void DisplayBoard(char NumBoard[ROWS][COLS], int row, int col)
{
	// 便于实现后期的标记的标记功能,我们把每行每列都打印上序号
	// 为了使游戏看起来更加清爽,我们在代码中加入清屏函数
	system("cls");
	int i = 0;
	int j = 0;
	// ---|---|---|---
	printf("   |");
	for (i = 1; i <= row; i++)
	{
		printf(" %d |", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		for (j = 0; j <= 9; j++)
		{
			printf("---|");
		}
		printf("\n");
		printf(" %d |", i);
		for (j = 1; j <= col; j++)
		{
			printf(" %c |", NumBoard[i][j]);
		}
		printf("\n");
	}
	for (j = 0; j <= 9; j++)
	{
		printf("---|");
	}
	printf("\n");
}

实现之后的效果如如下;
在这里插入图片描述

4.随机布雷

展示棋盘之后,利用时间戳生成随机数来实现随机布雷的效果。
首先引用头文件:

#include <stdlib.h>
#include <time.h>

在布雷时我们用字符 0 表示无雷,用字符 1 表示有雷。
由于布雷时可能布到已有雷的位置上,造成布雷失败的效果。
所以我们在这里最好采用一个while循环,在布雷成功时跳出循环。在布雷失败时循环继续。
代码如下:

void SetBoard(char MyBoard[ROWS][COLS], int row, int col)
{
	// 我们规定,是几乘几的棋盘,就布几个雷
	// 这里利用时间戳生成随机数模拟随机布雷
	srand((unsigned int)time(NULL));
	int i = 0;
	for (i = 0; i < row; i++)
	{
		// 由于布雷可能失败,所以这里使用一个while循环
		// 在布雷成功时跳出循环,在布雷失败时循环结束
		while (1)
		{
			// 将随机数的范围变为 1 到 9
			int x = rand() % 9 + 1;
			int y = rand() % 9 + 1;
			// 在每次布雷前,都需检查这个位置是否有雷
			if (MyBoard[x][y] == '0')
			{
				MyBoard[x][y] = '1';
				break;
			}
		}
	}
}

5.开始扫雷

我们输入横坐标和纵坐标来表示要扫的坐标。
由于玩家输入的坐标可能不合法或者可能那个坐标已经被占用,且玩家需要多次重复输入坐标所以我们需要用一个 while循环来模拟玩家的重复选择,当所有雷扫完之后或者玩家踩到雷之后游戏结束。
1.如果玩家输入的横坐标和纵坐标都是一到九的数字,那么输入合法,此时如果这个位置有雷,那么跳出循环,游戏结束。如果这个位置没有雷,进入near函数显示这个坐标周围的雷的数量。
在扫雷开始前,我们定义一个全局变量 n ,在每次排雷时 n 都要加一表示排了一个位置,当 n 一直增加到72(以9*9的棋盘为例,9 * 9 - 9 = 72)时,循环结束,游戏胜利。

		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (NumBoard[x][y] != '*')
			{
				printf("这个位置已排过,请重新输入\n");
			}
			else
			{
				if (MyBoard[x][y] == '0')
				{
					// 说明这个位置没有雷,此时应该找出这个位置周围雷的数量
					// 定义一个函数来找这个位置周围雷的数量
					near(MyBoard, NumBoard, x, y);
					// 每次排雷之后,都展示一下棋盘给玩家看
					DisplayBoard(NumBoard, row, col);

					// 如果此时 n 已经大于或者等于72(81-9)则说明所有位置已经排完,游戏结束
					if (n >= 72)
					{
						printf("恭喜你,你赢了\n");
						break;
					}

				}
				else
				{
					// 游戏结束并打印棋盘(让玩家知道他是怎么死的)
					DisplayBoard(MyBoard, row, col);
					printf("游戏结束,你输了\n");
					break;
				}
			}
		}

near函数中,我们遍历这个坐标周围的八个坐标,以此来统计这个坐标周围的雷的数量。并且在每次使用near函数时,判断这个位置是否为 *,也就是是否还未排过,如果未排过,将 n 加一,如果排过,结束这个函数。

	// 判断在NumBoard函数中该位置是否为'*',若是则++
	if (NumBoard[x][y] == '*')
	{
		n++;
	}
	else
	{
		return;
	}
	// 查看这个位置周围的八个位置有几个雷
	int num = 0;
	int i = 0;
	int j = 0;
	for (i = -1; i <= 1; i++)
	{
		for (j = -1; j <= 1; j++)
		{
			if (MyBoard[x + i][y + j] == '1')
			{
				num++;
			}
		}
	}
	// 查找结束后,将NumBoard数组的相应位置的元素改变为雷的个数
	// 并且由于棋盘中打印的是字符,需要将数字转化为字符
	NumBoard[x][y] = num + '0';

递归展开的实现:
如果这个坐标周围雷的数量为零,那么再让玩家输入坐标一个一个去排那岂不是很麻烦?
为了方便玩家,如果这个坐标周围的雷数为零,我们便展开这个坐标周围的坐标。
在展开之后,如果又发现某个坐标周围雷数为零,那么继续展开。
也就是说,在near函数内部如果发现又符合某个条件,继续调用near函数,那么这就需要用到函数递归了。
代码如下:

	// 如果周围雷的数量为0的话,自动显示周围每个位置的周围的雷的数量
	// 采用了递归的方法
	if (num == 0)
	{
		for (i = -1; i <= 1; i++)
		{
			for (j = -1; j <= 1; j++)
			{
				near(MyBoard, NumBoard, x+i, y+j);
			}
		}
	}

near函数的整体代码如下:

void near(char MyBoard[ROWS][COLS], char NumBoard[ROWS][COLS], int x, int y)
{
	// 判断在NumBoard函数中该位置是否为'*',若是则++
	if (NumBoard[x][y] == '*')
	{
		n++;
	}
	else
	{
		return;
	}
	// 查看这个位置周围的八个位置有几个雷
	int num = 0;
	int i = 0;
	int j = 0;
	for (i = -1; i <= 1; i++)
	{
		for (j = -1; j <= 1; j++)
		{
			if (MyBoard[x + i][y + j] == '1')
			{
				num++;
			}
		}
	}
	// 查找结束后,将NumBoard数组的相应位置的元素改变为雷的个数
	// 并且由于棋盘中打印的是字符,需要将数字转化为字符
	NumBoard[x][y] = num + '0';
	// 如果周围雷的数量为0的话,自动显示周围每个位置的周围的雷的数量
	// 采用了递归的方法
	if (num == 0)
	{
		for (i = -1; i <= 1; i++)
		{
			for (j = -1; j <= 1; j++)
			{
				near(MyBoard, NumBoard, x+i, y+j);
			}
		}
	}
}

手动标记功能的实现:
为了方便玩家进行游戏,我在代码中加入了标记功能,将确定有雷的地方标记为 #
如何将玩家排雷和玩家标记进行区别?
若玩家输入的坐标是负数,则进行标记。
在标记时,也要区分这个位置是否以及被标记过。若未标记过,对这个位置进行标记。若已经标记过,取消标记。

手动标记功能的代码如下:

		else if (x >= -row && x <= -1 && y >= -col && y <= -1)
		{
			if (NumBoard[-x][-y] == '*')
			{
				NumBoard[-x][-y] = '#';
				DisplayBoard(NumBoard, row, col);
			}
			else if (NumBoard[-x][-y] == '#')
			{
				NumBoard[-x][-y] = '*';
				DisplayBoard(NumBoard, row, col);
			}
		}

排雷函数的整体代码如下:

void Find(char MyBoard[ROWS][COLS], char NumBoard[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	// 使用while循环,如果点到雷或者游戏结束时跳出循环。如果未点到雷循环继续,玩家继续排雷
	while (1)
	{
		// 在输入完成后,判断玩家的输入是否合法
		// 若输入合法,跳出循环;若不合法,循环继续,并提醒玩家重新输入
		// 在这里加入标记功能,如果玩家输入负数则标记某个坐标。

		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (NumBoard[x][y] != '*')
			{
				printf("这个位置已排过,请重新输入\n");
			}
			else
			{
				if (MyBoard[x][y] == '0')
				{
					// 说明这个位置没有雷,此时应该找出这个位置周围雷的数量
					// 定义一个函数来找这个位置周围雷的数量
					near(MyBoard, NumBoard, x, y);
					// 每次排雷之后,都展示一下棋盘给玩家看
					DisplayBoard(NumBoard, row, col);

					// 如果此时 n 已经大于或者等于72(81-9)则说明所有位置已经排完,游戏结束
					if (n >= 72)
					{
						printf("恭喜你,你赢了\n");
						break;
					}

				}
				else
				{
					// 游戏结束并打印棋盘(让玩家知道他是怎么死的)
					DisplayBoard(MyBoard, row, col);
					printf("游戏结束,你输了\n");
					break;
				}
			}
		}

		else if (x >= -row && x <= -1 && y >= -col && y <= -1)
		{
			if (NumBoard[-x][-y] == '*')
			{
				NumBoard[-x][-y] = '#';
				DisplayBoard(NumBoard, row, col);
			}
			else if (NumBoard[-x][-y] == '#')
			{
				NumBoard[-x][-y] = '*';
				DisplayBoard(NumBoard, row, col);
			}
		}

		else
		{
			printf("输入非法,请重新输入\n");
		}

	}
}

至此,扫雷游戏就制作完成了!
不管怎样,自己尝试还是最重要的,快去试着制作一个扫雷游戏吧!

游戏的整体代码如下:

#pragma warning (disable:6031)
#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

// 定义一个全局变量 n ,用来统计已排的位置的数目
// 在每次进入near函数后,判断在NumBoard函数中该位置是否为'*',若是则++
int n = 0;

void menu()
{
	printf("***********************\n");
	printf("*****   1. play   *****\n");
	printf("*****   0. exit   *****\n");
	printf("***********************\n");
}

void InitBoard(char MyBoard[ROWS][COLS], char NumBoard[ROWS][COLS], int row, int col)
{
	// 玩家进入游戏后看不到周围雷的数量,只是看到了坐标
	// 我们规定玩家看到的坐标为星号

	int i = 0;
	int j = 0;

	// 对NumBoard棋盘数组的元素进行赋值
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			MyBoard[i][j] = '0';
		}
	}

	// 对NumBoard棋盘数组的元素进行赋值
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			NumBoard[i][j] = '*';
		}
	}
}

void DisplayBoard(char NumBoard[ROWS][COLS], int row, int col)
{
	// 便于实现后期的标记的标记功能,我们把每行每列都打印上序号
	// 为了使游戏看起来更加清爽,我们在代码中加入清屏函数
	system("cls");
	int i = 0;
	int j = 0;
	// ---|---|---|---
	printf("   |");
	for (i = 1; i <= row; i++)
	{
		printf(" %d |", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		for (j = 0; j <= 9; j++)
		{
			printf("---|");
		}
		printf("\n");
		printf(" %d |", i);
		for (j = 1; j <= col; j++)
		{
			printf(" %c |", NumBoard[i][j]);
		}
		printf("\n");
	}
	for (j = 0; j <= 9; j++)
	{
		printf("---|");
	}
	printf("\n");
}

void SetBoard(char MyBoard[ROWS][COLS], int row, int col)
{
	// 我们规定,是几乘几的棋盘,就布几个雷
	// 这里利用时间戳生成随机数模拟随机布雷
	srand((unsigned int)time(NULL));
	int i = 0;
	for (i = 0; i < row; i++)
	{
		// 由于布雷可能失败,所以这里使用一个while循环
		// 在布雷成功时跳出循环,在布雷失败时循环结束
		while (1)
		{
			// 将随机数的范围变为 1 到 9
			int x = rand() % 9 + 1;
			int y = rand() % 9 + 1;
			// 在每次布雷前,都需检查这个位置是否有雷
			if (MyBoard[x][y] == '0')
			{
				MyBoard[x][y] = '1';
				break;
			}
		}
	}
}

void near(char MyBoard[ROWS][COLS], char NumBoard[ROWS][COLS], int x, int y)
{
	// 判断在NumBoard函数中该位置是否为'*',若是则++
	if (NumBoard[x][y] == '*')
	{
		n++;
	}
	else
	{
		return;
	}
	// 查看这个位置周围的八个位置有几个雷
	int num = 0;
	int i = 0;
	int j = 0;
	for (i = -1; i <= 1; i++)
	{
		for (j = -1; j <= 1; j++)
		{
			if (MyBoard[x + i][y + j] == '1')
			{
				num++;
			}
		}
	}
	// 查找结束后,将NumBoard数组的相应位置的元素改变为雷的个数
	// 并且由于棋盘中打印的是字符,需要将数字转化为字符
	NumBoard[x][y] = num + '0';
	// 如果周围雷的数量为0的话,自动显示周围每个位置的周围的雷的数量
	// 采用了递归的方法
	if (num == 0)
	{
		for (i = -1; i <= 1; i++)
		{
			for (j = -1; j <= 1; j++)
			{
				near(MyBoard, NumBoard, x+i, y+j);
			}
		}
	}
}

void Find(char MyBoard[ROWS][COLS], char NumBoard[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	// 使用while循环,如果点到雷或者游戏结束时跳出循环。如果未点到雷循环继续,玩家继续排雷
	while (1)
	{
		// 在输入完成后,判断玩家的输入是否合法
		// 若输入合法,跳出循环;若不合法,循环继续,并提醒玩家重新输入
		// 在这里加入标记功能,如果玩家输入负数则标记某个坐标。

		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (NumBoard[x][y] != '*')
			{
				printf("这个位置已排过,请重新输入\n");
			}
			else
			{
				if (MyBoard[x][y] == '0')
				{
					// 说明这个位置没有雷,此时应该找出这个位置周围雷的数量
					// 定义一个函数来找这个位置周围雷的数量
					near(MyBoard, NumBoard, x, y);
					// 每次排雷之后,都展示一下棋盘给玩家看
					DisplayBoard(NumBoard, row, col);

					// 如果此时 n 已经大于或者等于72(81-9)则说明所有位置已经排完,游戏结束
					if (n >= 72)
					{
						printf("恭喜你,你赢了\n");
						break;
					}

				}
				else
				{
					// 游戏结束并打印棋盘(让玩家知道他是怎么死的)
					DisplayBoard(MyBoard, row, col);
					printf("游戏结束,你输了\n");
					break;
				}
			}
		}

		else if (x >= -row && x <= -1 && y >= -col && y <= -1)
		{
			if (NumBoard[-x][-y] == '*')
			{
				NumBoard[-x][-y] = '#';
				DisplayBoard(NumBoard, row, col);
			}
			else if (NumBoard[-x][-y] == '#')
			{
				NumBoard[-x][-y] = '*';
				DisplayBoard(NumBoard, row, col);
			}
		}

		else
		{
			printf("输入非法,请重新输入\n");
		}

	}
}

void game()
{
	// 进入游戏,定义棋盘数组
	// 这里需定义两个棋盘数组
	// 一个棋盘是为了显示这个位置有没有雷,另外一个棋盘是为了显示这个位置周围的雷数
	// 每个棋盘的数组大小都要是行和列的数目加2,防止排查周围雷的数量时出现越界现象
	
	// 这个棋盘数组是为了标记这个位置是否有雷,无雷为0,有雷为1
	char MyBoard[ROWS][COLS] = { 0 };   

	// 这个棋盘数组是为了显示这个位置周围有多少雷
	char NumBoard[ROWS][COLS]= { 0 };  

	// 在定义棋盘之后,我们就要对两个数组棋盘的元素进行赋值
	InitBoard(MyBoard, NumBoard, ROW, COL);

	// 在赋值之后,展示棋盘
	DisplayBoard(NumBoard, ROW, COL);

	// 在初始化且展示之后,我们就要开始布雷了
	SetBoard(MyBoard, ROW, COL);

	// 开始扫雷
	Find(MyBoard, NumBoard, ROW, COL);
}

int main()
{
	// 打印游戏菜单,指导玩家作出选择
	menu();
	
	// 利用do while语句模拟玩家的选择
	// 玩家选择 1 进入游戏,游戏结束后跳出循环
	// 玩家选择 0 直接退出循环,表示结束游戏
	// 玩家若选择其他,提醒玩家重新输入
	int input = 0;
	do
	{
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input != 0 && input != 1);
}

五.递归展开和手动标记(注意到很多博主未提到这两个功能,所以我把这两个功能单独说一下,希望能帮助到你)

1.递归展开

如果这个坐标周围雷的数量为零,那么再让玩家输入坐标一个一个去排那岂不是很麻烦?
为了方便玩家,如果这个坐标周围的雷数为零,我们便展开这个坐标周围的坐标。
在展开之后,如果又发现某个坐标周围雷数为零,那么继续展开。
也就是说,在near函数内部如果发现又符合某个条件,继续调用near函数,那么这就需要用到函数递归了。
整个near函数代码如下:

void near(char MyBoard[ROWS][COLS], char NumBoard[ROWS][COLS], int x, int y)
{
	// 判断在NumBoard函数中该位置是否为'*',若是则++
	if (NumBoard[x][y] == '*')
	{
		n++;
	}
	else
	{
		return;
	}
	// 查看这个位置周围的八个位置有几个雷
	int num = 0;
	int i = 0;
	int j = 0;
	for (i = -1; i <= 1; i++)
	{
		for (j = -1; j <= 1; j++)
		{
			if (MyBoard[x + i][y + j] == '1')
			{
				num++;
			}
		}
	}
	// 查找结束后,将NumBoard数组的相应位置的元素改变为雷的个数
	// 并且由于棋盘中打印的是字符,需要将数字转化为字符
	NumBoard[x][y] = num + '0';
	// 如果周围雷的数量为0的话,自动显示周围每个位置的周围的雷的数量
	// 采用了递归的方法
	if (num == 0)
	{
		for (i = -1; i <= 1; i++)
		{
			for (j = -1; j <= 1; j++)
			{
				near(MyBoard, NumBoard, x+i, y+j);
			}
		}
	}
}

2.手动标记

为了方便玩家进行游戏,我在代码中加入了标记功能,将确定有雷的地方标记为 #
如何将玩家排雷和玩家标记进行区别?
若玩家输入的坐标是负数,则进行标记。
在标记时,也要区分这个位置是否以及被标记过。若未标记过,对这个位置进行标记。若已经标记过,取消标记。

手动标记功能的代码如下

		else if (x >= -row && x <= -1 && y >= -col && y <= -1)
		{
			if (NumBoard[-x][-y] == '*')
			{
				NumBoard[-x][-y] = '#';
				DisplayBoard(NumBoard, row, col);
			}
			else if (NumBoard[-x][-y] == '#')
			{
				NumBoard[-x][-y] = '*';
				DisplayBoard(NumBoard, row, col);
			}
		}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/447.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端开发入门--html--Flask

快速开发网站 pip install flaskfrom flask import Flaskapp Flask(__name__)# 创建了网址 /show/info 和 函数index 的对应关系 # 以后用户在浏览器上访问 /show/info&#xff0c;网站自动执行 index app.route("/show/info") def index():return "中国联通&…

TPH-YOLOv5 | 基于Transformer的YOLOv5小目标检测器 | 四头加注意力

论文地址&#xff1a;https://arxiv.org/pdf/2108.11539.pdf 项目地址&#xff1a;https://github.com/cv516Buaa/tph-yolov5 在无人机捕获的场景中进行对象检测是最近的一项热门任务。由于无人机总是在不同的高度航行&#xff0c;物体尺度变化剧烈&#xff0c;给网络优化带来…

NMEA协议解析

文章目录一、NMEA0183协议1、NMEA基本框架2、常用语句1&#xff09;GNGGA2&#xff09;GNGLL3&#xff09;GNGSA4&#xff09;GPGSV5&#xff09;GNRMC6&#xff09;GNVTG7&#xff09;GNZDA8&#xff09;PAIRCLK等二、异或校验和代码1、网址在线计算BCC2、BCC校验和代码一、NM…

Java语言中的异常处理

异常处理 在java语言中&#xff0c;很机智的将异常作为对象来处理&#xff0c;而且定义一个基类java.lang.Throwable作为所有异常类的父类。在这许多类中一般分为两大类&#xff1a; 错误类(Error)和异常类&#xff08;Expception&#xff09;。 如图&#xff1a; 注&#xf…

iNOF在现实网络中的运用,以带反射器的iONF为例

定义 iNOF&#xff08;Intelligent Lossless NVMe Over Fabric&#xff0c;智能无损存储网络&#xff09;是指通过对接入主机的快速管控&#xff0c;将智能无损网络应用到存储系统&#xff0c;实现计算和存储网络融合的技术。 目的 网络转发设备用于传输流量&#xff0c;不同类…

竞争不是内卷,用头脑学习,而非时间

文章目录 用头脑学习&#xff0c;而非时间 前言 一、自由竞争不是内卷 二、内卷都在哪些行业 三、高效学习来大数据梦想联盟 用头脑学习&#xff0c;而非时间 前言 大多数人不懂&#xff0c;不会&#xff0c;不做&#xff0c;才是你的机会&#xff0c;你得行动&#xff…

【Queue】- 从源码分析ArrayDeque及其常用方法

文章目录概述ArrayDeque基础知识ArrayDeque内部结构ArrayDeque的构造方法ArrayDeque的扩容操作ArrayDeque常用方法将ArrayDeque作为双端队列使用时public void addFirst(E e)public void addLast(E e)public boolean offerFirst(E e)public boolean offerLast(E e)public E pol…

动态SLAM论文归纳

持续更新&#xff0c;持续更新 2022 Multi-modal Semantic SLAM for Complex Dynamic Environments 作者&#xff1a;Han Wang, Jing Ying Ko and Lihua Xie, Fellowcode&#xff1a;https://github.com/wh200720041/MMS_SLAM视频&#xff1a;https://www.youtube.com/watch…

web自动化测试——入门篇01

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

并发编程中的原子性,可见性,有序性问题

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章是关于并发编程中出现的原子性&#xff0c;可见性&#xff0c;有序性问题。 本篇文章记录的基础知识&#xff0c;适合在学Java的小白&#xff0c;也适合复习中&am…

PyTorch(三)TensorBoard 与 Transforms

文章目录Log一、TensorBoard1. TensorBoard 的安装2. SummaryWriter 的使用① add_scalar() 的使用a. 参数说明b. 函数使用c. 使用 Tensorboard② add_image() 的使用a. 参数说明b. 使用 numpy.array() 对 PIL 图片进行转换c. 使用函数d. 改变 global_step二、Transforms1. Tra…

数据结构 | 时间复杂度与空间复杂度

… &#x1f333;&#x1f332;&#x1f331;本文已收录至&#xff1a;数据结构 | C语言 更多知识尽在此专栏中&#xff01; &#x1f389;&#x1f389;&#x1f389;欢迎点赞、收藏、关注 &#x1f389;&#x1f389;&#x1f389;文章目录&#x1f333;前言&#x1f333;正…

【C++初阶】类和对象(二)

大家好我是沐曦希&#x1f495; 类和对象1.类的6个默认成员函数2.构造函数2.1 概念2.2 特性3.析构函数3.1 概念3.2 特性4.拷贝构造函数4.1 概念4.2 特征1.类的6个默认成员函数 空类&#xff1a;类中一个成员都没有 可是空类真的什么都没有吗&#xff1f; 并不是&#xff0c;任…

STM32关于UART的接收方式

STM32的 UART 一般分为定长接收和不定长接收 定长接收&#xff1a; HAL_UART_Receive():只能接收固定长度的数据&#xff0c;如果超过固定长度的数据只能接收对应长度&#xff0c;如果小于固定长度则不会接收 HAL_UART_Receive_IT():中断方式接收&#xff0c;每接收一个字节…

CSS 2 CSS 选择器 - 5 2.8 伪选择器 2.8.1 伪类选择器【根据特定状态选取元素】

CSS 文章目录CSS2 CSS 选择器 - 52.8 伪选择器2.8.1 伪类选择器【根据特定状态选取元素】2 CSS 选择器 - 5 2.8 伪选择器 2.8.1 伪类选择器【根据特定状态选取元素】 【什么是伪类】 伪类用于定义元素的特殊状态。 例如&#xff0c;它可以用于&#xff1a; 设置鼠标悬停在…

如何删除ZIP压缩包的密码?

ZIP是比较常用的压缩文件格式&#xff0c;有时候因为工作需要很多人还会给压缩包设置打开密码。那如果后续不需要密码保护了要如何删除密码呢&#xff1f;密码忘记了还能删除吗&#xff1f; 首先来说说第一种情况&#xff0c;也就是知道密码但后续不需要密码保护&#xff0c;只…

1. 初识Python

1. Pythond 简介 Python 语言由荷兰的 Guido Van Rossum (吉多范罗苏姆, 江湖人称龟叔) 在1989年圣诞节期间为了打发圣诞节的无趣而开发的一个脚本解释语言.Python 源代码遵循 GPL(GNU General Public License)开源协议, 也就是说你可以免费使用和传播它, 而不用担心版权的问…

libusb系列-005-部分API简介

libusb系列-005-部分API简介 文章目录libusb系列-005-部分API简介摘要libusb_initlibusb_open_device_with_vid_pidlibusb_kernel_driver_activelibusb_detach_kernel_driverlibusb_claim_interfacelibusb_release_interfacelibusb_attach_kernel_driverlibusb_closelibusb_exi…

【论文翻译】分布式并发控制中时间戳排序算法与本地计数器同步的改进方法

An Advanced Approach of Local Counter Synchronization to Timestamp Ordering Algorithm in Distributed Concurrency Control DOI目录1 介绍2 时间戳排序算法3 本地计数器同步的一种高级方法3.1 改进更新本地计数器的广播消息方式3.2 减少广播消息中的数据传输费用4 结论参…

时间复杂度与空间复杂度

文章目录1.什么是数据结构2.什么是算法3.如何学好数据结构呢3.1写代码3.2 多去动手画图4.算法效率4.1如何评判一个算法的好与坏呢4.2算法的复杂度5.时间复杂度5.1 概念5.2大O渐进法6常见的时间复杂度6.1常数阶6.2线性阶6.3 对数阶6.4平方阶6.5函数调用6.5.1普通调用6.5.2递归调…