C语言初阶习题【20】扫雷游戏

1.用C语言实现扫雷游戏

本博客和三子棋游戏比较大的区别是,三子棋游戏是写完了再总结的,本博客是边代码实现边编辑博客,所以本博客会比较详细的po出每一步骤,在每实现一个小功能的时候我们都先验证下效果,再继续下一步。

2.思路

总体的思路和三子棋游戏是一样的,我们把游戏实现部分放在game.c和game.h中,把游戏的测试代码放到test.c中。main函数在test.c中。
小tips:我们把需要包含的头文件都放在game.h中,game.c和test.c中只需要包含我们的game.h一个头文件即可。

2.1 test.c函数实现

2.1.1 main()函数和test()函数实现

在main函数中只简单调用我们的test()函数,在test()函数中打印游戏菜单,实现让玩家选择开始游戏还是结束游戏。

  • game.h中的代码实现
#pragma once //这个是我创建.h文件的时候自动出现的,不是自己手敲的
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
  • test.c中的代码实现
#include "game.h"
void manu()
{
	printf("===========================\n");
	printf("========1:开始游戏=========\n");
	printf("========0:结束游戏=========\n");
	printf("===========================\n");
}
void test()
{
	int input = 0;
	do
	{
		manu();
		printf("请输入您的选择:\n");
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				//game(); 因为还没有实现game()所以这里我屏蔽掉了。
				break;
			case 0:
				printf("游戏结束,欢迎下次再来!\n");
				break;
			default:
				printf("您的输入有误,请重新输入:\n");
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}
  • 验证

在这里插入图片描述

2.1.2 test.c中的game()函数实现思路

设计扫雷游戏之前,先进行思考

  1. 创建地图,9*9的二维数组,元素类型是什么?
  2. 每个格子的状态有以下状态
    a)未翻开(草地)
    b)已翻开(数字)
    c)是地雷
    d)不是地雷
    四种状态是两大类,我们用两个二维数组表示。
    第一个数组表示翻开状态showMap:
    char类型表示,如果是 * 表示未翻开 ; 如果是阿拉伯数字,就表示翻开
    第二个数组表示是否地雷状态mineMap:
    char 类型表示 如果是 【1】:表示是地雷 【0】:表示不是地雷 、 也可以int 类型表示 如果是数字1:地雷; 数字0:不是地雷
  3. 这里还有个需要考虑的是虽然9×9数组是我们的目标,但是在边角位置,我们要对周围8个位置进行数雷的个数,非常容易数组越界,这里的解决思路有两个,其一是每次都需要判定我们的翻开位置是否是边角位置,这样比较繁琐。其二是直接创建两个11×11的数组,这样我们使用我们9*9的地图的时候就没有这个风险。这里使用的是第二个思路。

扫雷游戏的思路

  1. 先创建地图(两个地图一个是我们放雷的地图mineMap,一个是我们的展示地图showMap),并进行初始化
    a)针对showMap 默认初始化全是 *,表示未知,等待玩家翻开
    b)针对mineMap 默认初始化都是字符’0’,之后我们初始化10个地雷(根据随机位置来摆放) 没地雷用字符’0’ 表示,地雷位置用字符’1’表示
  2. 打印地图showMap
  3. 给mineMap地图布置雷。
  4. 排查雷
    a)提示玩家输入要翻开的位置坐标,并进行校验
    b) 判定当前位置是否是雷,如果是雷则游戏失败,游戏结束
    c) 如果当前位置是最后一个“不是雷的格子”那么游戏胜利,游戏结束
    d)如果不是雷,更新翻开的当前位置,把【* 】替换成一个数字(就把showMap中对应位置的 * 修改成一个具体的数字)这个数字要根据当前位置周围8个格子的地雷数目来决定。
  5. 下一步从2继续开始,直到游戏结束。

2.2 test.c中的game()函数和game.c中的函数实现

2.2.1 地图创建

  • 在test.c中的game()函数中创建两个char类型的二维数组,需要设置两个全局变量,我们放在game.h中,这里我们先设置两个为9的行和列,由于我们为了避免数组越界所以又定义了一个,MAX_ROW和MAX_COL变量,这样设置,之后打印的时候不需要写很多个9了,直接用这个全局变量。
//game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

#define ROW 9
#define COL 9
#define MAX_ROW ROW+2
#define MAX_COL COL+2

#include <stdio.h>
//test.c
void game()
{
	//1.地图创建
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
}

2.2.2 地图初始化

  1. game函数中只需要调用init函数,init函数的实际的实现在game.c中。
void game()
{
	//1.地图创建
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
	//2.地图初始化
	init(showMap, MAX_ROW,MAX_COL,'*');
	init(mineMap, MAX_ROW, MAX_COL, '0');
}

  1. init函数具体实现

先在game.h中声明

//game.h
void init(char showMap[MAX_ROW][MAX_COL], int row, int col, char i);

然后在game.c中具体实现
可以用for循环,也可以使用库函数memset,这里因为我们需要初始化两个数组,但是两个数组的内容不同,所以给init函数添加了一个参数,用来传入我们要初始化的值。

//game.c
//1.地图初始化
void init(char board[MAX_ROW][MAX_COL], int row, int col, char set)
{
#if 0
	int i = 0;
	int j = 0;
	for (i = 0; i < col; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
#endif 
	
	memset(board, set, row * col * sizeof(char));
}

2.2.3 地图打印

  1. game函数中只需要调用Print函数,Print函数的实际的实现在game.c中。
//test.c
void game()
{
	//1.地图创建
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
	//2.地图初始化
	init(showMap, MAX_ROW,MAX_COL,'*');
	init(mineMap, MAX_ROW, MAX_COL, '0');
	//3. 地图打印
	Print(showMap, ROW, COL); //打印地图我们只需要9行9列
	Print(mineMap, ROW, COL);
}
  1. Print函数具体实现

先在game.h中声明

//game.h
//1.地图初始化
void init(char showMap[MAX_ROW][MAX_COL], int row, int col, char set);

//2.地图打印
void Print(char board[MAX_ROW][MAX_COL], int row, int col);

在game.c中具体实现

第一版本

//game.c
//2.地图打印
void Print(char board[MAX_ROW][MAX_COL], int row, int col)
{
	//我们只需要打印9*9的,但是我们必须用11*11的接收,
	// 因为数组的存储方式决定了,我们不可能只单单把中间元素取出来,只能按顺序取
	int i = 0;
	int j = 0;
	for (i = 1; i < row-1; i++)
	{
		for (j = 1; j < col-1; j++)
		{
			printf("%c", board[i][j]);
		}
		printf("\n");
	}
}

第一版本效果(有点丑)
在这里插入图片描述

第二版本,每个值之间添加空格
在这里插入图片描述

第三版本,给每一行上面和每一列的前面增加数字,让玩家能直观的看到是第几行第几列。在最开始和结束打印一行提示扫雷。

//game.c
//2.地图打印
void Print(char board[MAX_ROW][MAX_COL], int row, int col)
{
	//我们只需要打印9*9的,所以传值的时候只需要传9行9列
	// 但是我们必须用11*11的接收, 因为数组的存储方式决定了,
	// 我们不可能只单单把中间元素取出来,只能按顺序取
	printf("--------扫雷-------\n");
	int i = 0;
	int j = 0;
	//控制列号
	for (j = 0; j <= col; j++)
	{
		printf("%d ", j);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		//控制行号
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("--------扫雷-------\n");
}

第三版本效果
在这里插入图片描述

2.3.4 布置雷

  1. 在game()函数中调用布置雷函数
//test.c
void game()
{
	//1.地图创建
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
	//2.地图初始化
	init(showMap, MAX_ROW,MAX_COL,'*');
	init(mineMap, MAX_ROW, MAX_COL, '0');
	//3. 地图打印
	Print(showMap, ROW, COL); //打印地图我们只需要9行9列
	Print(mineMap, ROW, COL);//实际游戏的时候,不能打印存放雷的地图
	//4.布置雷
	setMine(mineMap, ROW, COL);//布置9*9,所以传的是9行9列
	Print(mineMap, ROW, COL);//布置完打印下看看效果
}

  1. 在game.h中声明
//test.c
//1.地图初始化
void init(char showMap[MAX_ROW][MAX_COL], int row, int col, char set);

//2.地图打印
void Print(char board[MAX_ROW][MAX_COL], int row, int col);

//3.布置雷
void setMine(char board[MAX_ROW][MAX_COL], int row, int col);//接收还是11行11列,我们只是只需要对9*9的位置进行布置雷操作。

  1. 在game.c中实现
    设定10个雷,在game.h中宏定义一下
//game.h
#define EASY_MODE 10

思路:随机生成坐标,只要该坐标不是雷,就布置雷。

随机数生成函数rand()需要和srand()函数搭配使用,在我们的test()函数中调用我们的srand()函数生成随机数种子,要记得在game.h中添加我们的头文件。

//game.h
#include<stdlib.h>
#include<time.h>
//test.c中的test()添加
srand((unsigned int)time(NULL));

在这里插入图片描述

排查雷函数实现

//3.布置雷
void setMine(char board[MAX_ROW][MAX_COL], int row, int col)
{
	//思路:设置10个count,让count一直减减,当count减到0的时候就表示我们布置雷完成。
	int mine_Count = EASY_MODE;

	while (mine_Count)
	{
		//1.生成随机数坐标
		int x = rand() % row+1;//要生成0~9 mod9就是0~9 全部+1 就是1~10
		int y = rand() % col+1;

		//2.判断该坐标是否是雷,是雷就重新生成随机坐标,否则就布置
		if (board[x][y] == '1')
		{
			continue;
		}
		else
		{
			board[x][y] = '1';
			mine_Count--;//布置成功之后要记得给count--
		}
	}
	
}

布置雷函数效果
在这里插入图片描述

2.3.5 排查雷

实现思路:

  1. 提示玩家输入要翻开的位置坐标,并去mineMap中进行校验
  2. 判定当前位置是否是雷,如果是雷则游戏失败,游戏结束
  3. 如果当前位置是最后一个“不是雷的格子”那么游戏胜利,(81个格子,10个雷,即需要找到71个不是雷的格子),游戏结束
  4. 如果不是雷,showMap中更新翻开的当前位置,把【‘*’ 】替换成一个数字(就把showMap中对应位置的【’ * '】修改成一个具体的数字)这个数字要根据当前位置周围8个格子的地雷数目来决定。
  1. 在game()函数中调用findMine()
//test.c
void game()
{
	//1.地图创建
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
	//2.地图初始化
	init(showMap, MAX_ROW,MAX_COL,'*');
	init(mineMap, MAX_ROW, MAX_COL, '0');
	//3. 地图打印
	Print(showMap, ROW, COL); //打印地图我们只需要9行9列
	Print(mineMap, ROW, COL);//实际游戏的时候,不能打印存放雷的地图
	//4.布置雷
	setMine(mineMap, ROW, COL);//布置9*9,所以传的是9行9列
	Print(mineMap, ROW, COL);
	//5.排查雷
	findMine(mineMap, showMap, ROW, COL);
}
  1. 在game.h中声明
//game.h

//1.地图初始化
void init(char showMap[MAX_ROW][MAX_COL], int row, int col, char set);

//2.地图打印
void Print(char board[MAX_ROW][MAX_COL], int row, int col);

//3.布置雷
void setMine(char board[MAX_ROW][MAX_COL], int row, int col);

//4.排查雷
void findMine(char board[MAX_ROW][MAX_COL], char board2[MAX_ROW][MAX_COL], int row, int col);
  1. 在game.c中实现

版本1


//game.c

//可以加static 只有本.c文件的函数可以调用它
static int getMineCount(char mineMap[MAX_ROW][MAX_COL], int x, int y)
{
	//知道了x,y能够算出它的周围格子坐标,我们把所有坐标的值加起来,减去8*字符‘0’就把字符数字转换为数字,得到的值就是周围有几个1

	return  (mineMap[x - 1][y - 1] + mineMap[x - 1][y] + mineMap[x - 1][y + 1] + mineMap[x][y + 1]
		+ mineMap[x + 1][y + 1] + mineMap[x + 1][y] + mineMap[x + 1][y - 1] + mineMap[x][y - 1]) - 8 * '0';

}
//4.排查雷

void findMine(char mineMap[MAX_ROW][MAX_COL], char showMap[MAX_ROW][MAX_COL], int row, int col)
{
	//1.提示玩家,输入要排查的坐标
	printf("请输入你要排查的坐标:\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//1.判断这个坐标是不是雷。是雷提示,游戏失败
			if (mineMap[x][y] == '1')
			{
				printf("很抱歉你扫到雷了,游戏结束\n");
				Print(mineMap, row, col);
				break;
			}
			else
			{ //不是雷,需要数下周围8个格子有几个雷,封装一个函数 ,得到的数值写回到showMap中去。
				int n = getMineCount(mineMap, x, y);//这里是int
				showMap[x][y] = n+'0';//showMap存放的是字符类型,我们需要把得到的int数字。转换成对应的字符。这里是加上一个字符'0'
				Print(showMap, row, col);
			}
		}
		else
		{
			printf("坐标非法,请重新输入:\n");//所以这里要用到循环,万一玩家输入非法坐标
		}
	}
}

版本1效果
在这里插入图片描述
在这里插入图片描述

我们到这一步就可以简单的玩起来了,我们可以 game()中不打印我们的mineMap(),然后玩下我们的游戏。
在这里插入图片描述

版本2:
版本1缺少赢的判断。是死循环,我们需要增加对于玩家赢的情况的判断。

思路:每找到一个不是雷的格子count就++。 当找到第71个不是雷的格子的时候,游戏结束。 (81个格子减去10个雷,就剩下71个不是雷的格子)

//4.排查雷
void findMine(char mineMap[MAX_ROW][MAX_COL], char showMap[MAX_ROW][MAX_COL], int row, int col)
{
	//1.提示玩家,输入要排查的坐标
	printf("请输入你要排查的坐标:\n");
	int x = 0;
	int y = 0;
	//每找到一个不是雷的格子count就++。
	// 当找到第71个不是雷的格子的时候,游戏结束。
	// (81个格子减去10个雷,就剩下71个不是雷的格子)
	int winCount = 0;
	while (winCount < row*col-EASY_MODE)
	{
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//1.判断这个坐标是不是雷。是雷提示,游戏失败
			if (mineMap[x][y] == '1')
			{
				printf("很抱歉你扫到雷了,游戏结束\n");
				Print(mineMap, row, col);
				break;
			}
			else
			{ //不是雷,需要数下周围8个格子有几个雷,封装一个函数 ,得到的数值写回到showMap中去。
				int n = getMineCount(mineMap, x, y);//这里是int
				showMap[x][y] = n+'0';//showMap存放的是字符类型,我们需要把得到的int数字。转换成对应的字符。这里是加上一个字符'0'
				Print(showMap, row, col);
				winCount++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入:\n");//所以这里要用到循环,万一玩家输入非法坐标
		}
	}
	if (winCount == row * col - EASY_MODE) //这里必须加判断条件,因为排雷失败也会跳出出while循环
	{
		printf("恭喜你!排雷成功!\n");
	}
}

验证下,把我们的雷改成80个,我们直接找到那个不是雷的坐标,验证下我们的逻辑。
在game.h中

#define EASY_MODE 80

在test.c的game()函数中打印我们的mineMap。

void game()
{
	//1.地图创建
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
	//2.地图初始化
	init(showMap, MAX_ROW,MAX_COL,'*');
	init(mineMap, MAX_ROW, MAX_COL, '0');
	//3. 地图打印
	Print(showMap, ROW, COL); //打印地图我们只需要9行9列
	//Print(mineMap, ROW, COL);//实际游戏的时候,不能打印存放雷的地图
	//4.布置雷
	setMine(mineMap, ROW, COL);//布置9*9,所以传的是9行9列
	Print(mineMap, ROW, COL);
	//5.排查雷
	findMine(mineMap, showMap, ROW, COL);//我们找雷的时候也只需要9*9的
}

版本2效果
在这里插入图片描述

版本3
小优化,(1)我们应该把我们的提示,请输入想要排查的坐标放到循环里面(2)在我们排雷成功的时候打印下我们的mineMap,看下我们的成功结果(3)把我们的EASY_MODE 改回10(4)在test的game函数中不打印我们的mineMap。就可以正常玩游戏了。(5)在玩家输入坐标的时候要判断下是否已经输入过这个坐标,否则我们重复我们已经排查过的坐标,count还一直++,会导致我们还没有拍完雷就判定我们赢了。

//game.h
#define EASY_MODE 10
//game.c
//4.排查雷
void findMine(char mineMap[MAX_ROW][MAX_COL], char showMap[MAX_ROW][MAX_COL], int row, int col)
{

	int x = 0;
	int y = 0;
	//每找到一个不是雷的格子count就++。
	// 当找到第71个不是雷的格子的时候,游戏结束。
	// (81个格子减去10个雷,就剩下71个不是雷的格子)
	int winCount = 0;
	while (winCount < row*col-EASY_MODE)
	{	
		//1.提示玩家,输入要排查的坐标
		printf("请输入你要排查的坐标:\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//判断输入的坐标是否已经排查过了。排查过的坐标在showMap中不是*
			if (showMap[x][y] != '*')
			{
				printf("该坐标已经排查过了,请重新输入:\n");
				continue;
			}
			//1.判断这个坐标是不是雷。是雷提示,游戏失败
			if (mineMap[x][y] == '1')
			{
				printf("很抱歉你扫到雷了,游戏结束\n");
				Print(mineMap, row, col);
				break;
			}
			else
			{ //不是雷,需要数下周围8个格子有几个雷,封装一个函数 ,得到的数值写回到showMap中去。
				int n = getMineCount(mineMap, x, y);//这里是int
				showMap[x][y] = n+'0';//showMap存放的是字符类型,我们需要把得到的int数字。转换成对应的字符。这里是加上一个字符'0'
				Print(showMap, row, col);
				winCount++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入:\n");//所以这里要用到循环,万一玩家输入非法坐标
		}
	}
	if (winCount == row * col - EASY_MODE) //这里必须判断,因为排雷失败也会出while循环
	{
		printf("恭喜你!排雷成功!\n");
		Print(mineMap, row, col);
	}
}
//test.c
void game()
{
	//1.地图创建
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
	//2.地图初始化
	init(showMap, MAX_ROW,MAX_COL,'*');
	init(mineMap, MAX_ROW, MAX_COL, '0');
	//3. 地图打印
	Print(showMap, ROW, COL); //打印地图我们只需要9行9列
	//Print(mineMap, ROW, COL);//实际游戏的时候,不能打印存放雷的地图
	//4.布置雷
	setMine(mineMap, ROW, COL);//布置9*9,所以传的是9行9列
	//Print(mineMap, ROW, COL);
	//5.排查雷
	findMine(mineMap, showMap, ROW, COL);//我们找雷的时候也只需要9*9的
}

我们也是验证下,把我们的EASY_MODE改成79 ,打印我们的mineMap,

#define EASY_MODE 79

在这里插入图片描述

3.全部代码

3.1 test.c

#include "game.h"
void manu()
{
	printf("===========================\n");
	printf("========1:开始游戏=========\n");
	printf("========0:结束游戏=========\n");
	printf("===========================\n");
}


void game()
{
	//1.地图创建
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
	//2.地图初始化
	init(showMap, MAX_ROW,MAX_COL,'*');
	init(mineMap, MAX_ROW, MAX_COL, '0');
	//3. 地图打印
	Print(showMap, ROW, COL); //打印地图我们只需要9行9列
	//Print(mineMap, ROW, COL);//实际游戏的时候,不能打印存放雷的地图
	//4.布置雷
	setMine(mineMap, ROW, COL);//布置9*9,所以传的是9行9列
	//Print(mineMap, ROW, COL);
	//5.排查雷
	findMine(mineMap, showMap, ROW, COL);//我们找雷的时候也只需要9*9的
}

	

void test()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		manu();
		printf("请输入您的选择:\n");
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				game();
				break;
			case 0:
				printf("游戏结束,欢迎下次再来!\n");
				break;
			default:
				printf("您的输入有误,请重新输入:\n");
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

3.2 game.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1


#define ROW 9
#define COL 9

#define MAX_ROW ROW+2
#define MAX_COL COL+2

#define EASY_MODE 10

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

//1.地图初始化
void init(char showMap[MAX_ROW][MAX_COL], int row, int col, char set);

//2.地图打印
void Print(char board[MAX_ROW][MAX_COL], int row, int col);

//3.布置雷
void setMine(char board[MAX_ROW][MAX_COL], int row, int col);

//4.排查雷
void findMine(char board[MAX_ROW][MAX_COL], char board2[MAX_ROW][MAX_COL], int row, int col);

3.3 game.c



#include "game.h"


//1.地图初始化
void init(char board[MAX_ROW][MAX_COL], int row, int col, char set)
{
#if 0
	int i = 0;
	int j = 0;
	for (i = 0; i < col; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}

#endif 
	
	memset(board, set, row * col * sizeof(char));
}
//2.地图打印
void Print(char board[MAX_ROW][MAX_COL], int row, int col)
{
	//我们只需要打印9*9的,所以传值的时候只需要传9行9列
	// 但是我们必须用11*11的接收, 因为数组的存储方式决定了,
	// 我们不可能只单单把中间元素取出来,只能按顺序取
	printf("--------扫雷-------\n");
	int i = 0;
	int j = 0;
	//控制列号
	for (j = 0; j <= col; j++)
	{
		printf("%d ", j);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		//控制行号
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("--------扫雷-------\n");
}
//3.布置雷
void setMine(char board[MAX_ROW][MAX_COL], int row, int col)
{
	//思路:设置10个count,让count一直减减,当count减到0的时候就表示我们布置雷完成。
	int mine_Count = EASY_MODE;

	while (mine_Count)
	{
		//1.生成随机数坐标
		int x = rand() % row+1;//要生成0~9 mod9就是0~9 全部+1 就是1~10
		int y = rand() % col+1;

		//2.判断该坐标是否是雷,是雷就重新生成随机坐标,否则就布置
		if (board[x][y] == '1')
		{
			continue;
		}
		else
		{
			board[x][y] = '1';
			mine_Count--;
		}
	}
	
}


//可以加static 只有本.c文件的函数可以调用它
static int getMineCount(char mineMap[MAX_ROW][MAX_COL], int x, int y)
{
	//知道了x,y能够算出它的周围格子坐标,我们把所有坐标的值加起来,减去8*字符‘0’就把字符数字转换为数字,得到的值就是周围有几个1

	return  (mineMap[x - 1][y - 1] + mineMap[x - 1][y] + mineMap[x - 1][y + 1] + mineMap[x][y + 1]
		+ mineMap[x + 1][y + 1] + mineMap[x + 1][y] + mineMap[x + 1][y - 1] + mineMap[x][y - 1]) - 8 * '0';

}

//4.排查雷
void findMine(char mineMap[MAX_ROW][MAX_COL], char showMap[MAX_ROW][MAX_COL], int row, int col)
{

	int x = 0;
	int y = 0;
	//每找到一个不是雷的格子count就++。
	// 当找到第71个不是雷的格子的时候,游戏结束。
	// (81个格子减去10个雷,就剩下71个不是雷的格子)
	int winCount = 0;
	while (winCount < row*col-EASY_MODE)
	{	
		//1.提示玩家,输入要排查的坐标
		printf("请输入你要排查的坐标:\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//判断输入的坐标是否已经排查过了。排查过的坐标在showMap中不是*
			if (showMap[x][y] != '*')
			{
				printf("该坐标已经排查过了,请重新输入:\n");
				continue;
			}
			//1.判断这个坐标是不是雷。是雷提示,游戏失败
			if (mineMap[x][y] == '1')
			{
				printf("很抱歉你扫到雷了,游戏结束\n");
				Print(mineMap, row, col);
				break;
			}
			else
			{ //不是雷,需要数下周围8个格子有几个雷,封装一个函数 ,得到的数值写回到showMap中去。
				int n = getMineCount(mineMap, x, y);//这里是int
				showMap[x][y] = n+'0';//showMap存放的是字符类型,我们需要把得到的int数字。转换成对应的字符。这里是加上一个字符'0'
				Print(showMap, row, col);
				winCount++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入:\n");//所以这里要用到循环,万一玩家输入非法坐标
		}
	}
	if (winCount == row * col - EASY_MODE) //这里必须判断,因为排雷失败也会出while循环
	{
		printf("恭喜你!排雷成功!\n");
		Print(mineMap, row, col);
	}
}

4 小结

  1. 关于为什么定义了全局常量,但是在函数实现的时候没有直接使用定义的全局常量,还传了两个row和col参数。
    其一是尽量不要让函数过分依赖全局符号;
    其二是以参数的形式传进去,是比较灵活的,比如我们的打印函数,我们只需要使用9×9的,我们就传9×9,如果我们要用12×12的我们就可以直接传,尽量用什么以参数的形式传递给函数进行使用。

  2. 数字2如何变成字符2
    在这里插入图片描述
    字符2的ASCII码是50
    字符‘0’ 的ASCII码是48
    所以 给数字2+字符’0’就能得到字符‘2’。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python AI教程之七:多项式回归

多项式回归的实现 多项式回归是一种线性回归,其中独立变量 x 和因变量 y 之间的关系被建模为n 次多项式。多项式回归拟合 x 的值与 y 的相应条件均值之间的非线性关系,表示为 E(y | x)。在本文中,我们将深入探讨多项式回归。 目录 什么是多项式回归? 为什么采用多项式回归…

【Leetcode】3280. 将日期转换为二进制表示

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个字符串 date&#xff0c;它的格式为 yyyy-mm-dd&#xff0c;表示一个公历日期。 date 可以重写为二进制表示&#xff0c;只需要将年、月、日分别转换为对应的二进制表示&a…

网段划分和 IP 地址

1. IP 协议 IP 协议是网络层协议&#xff0c;主要负责在不同网络设备之间&#xff0c;进行数据包的地址分配和路由选择。 地址分配&#xff1a;为每个连接到公网的设备分配一个唯一的 IP 地址&#xff0c;确保数据能被准确地发送到目标设备。 数据分片和组装&#xff1a;当发…

【Python系列】Python 中对对象列表进行排序

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

微服务のGeteWay

目录 概念&#xff1a; 三大核心&#xff1a; 工作流程&#xff1a; 9527网关如何做路由映射&#xff1a; GetWay高级特性&#xff1a; 按服务名动态路由服务&#xff1a; 断言Route Predicate Factories &#xff1a; 获取当前时区时间&#xff1a; After Route &…

数字图像处理 三 空间滤波

空间滤波是一种图像处理技术&#xff0c;它通过对图像像素及其邻域进行运算&#xff0c;利用均值&#xff0c;高斯&#xff0c;梯度&#xff0c;拉普拉斯等线性滤波和中值&#xff0c;最大最小&#xff0c;双边滤波等非线性滤波改变像素值&#xff0c;实现图像的平滑&#xff0…

【CVE-2024-12987 】DrayTek 网关设备中 `apmcfgupload` 端点的命令注入漏洞

概述 DrayTek 网关设备(包括 Vigor2960 和 Vigor300B 型号)存在通过 Web 管理接口进行命令注入的漏洞。攻击者可以通过发送恶意的 HTTP 请求到 /cgi-bin/mainfunction.cgi/apmcfgupload 端点,利用该漏洞注入任意命令,从而影响超过 66,000 台连接到互联网的设备。 受影响的…

mac下载Homebrew安装nvm

通过Homebrew安装 - 国内下载地址 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"安装nvm brew install nvm 配置nvm环境变量 export NVM_DIR“$HOME/.nvm” [ -s “/usr/local/opt/nvm/nvm.sh” ] && . “/usr/…

[react] 纯组件优化子

有组件如下,上面变化秒数, 下面是大量计算的子组件,上面每一秒钟变化一次,这时候子组件会不断重新渲染, 浪费资源 父组件如下 import React, { memo, useEffect, useMemo, useState } from react; import type { ReactNode, FC } from react; import HugeCount from ./Te; int…

Unity Mesh生成Cube

1. 配置一个Cube的每个面的数据 一共是6个面&#xff0c;每个面包含的数据包括4个顶点的相对顶点坐标&#xff08;Cube的中心为原点&#xff09;&#xff0c;法线方向&#xff0c;UV坐标&#xff0c;顶点渲染顺序&#xff0c;以及这个面用到的材质&#xff0c;因为这里是Top&am…

Spring--三级缓存机制

一、什么是三级缓存 就是在Bean生成流程中保存Bean对象三种形态的三个Map集合&#xff0c;如下&#xff1a; // 一级缓存Map 存放完整的Bean&#xff08;流程跑完的&#xff09; private final Map<String, Object> singletonObjects new ConcurrentHashMap(256);// 二…

使用R语言绘制标准的中国地图和世界地图

在日常的学习和生活中&#xff0c;有时我们常常需要制作带有国界线的地图。这个时候绘制标准的国家地图就显得很重要。目前国家标准地图服务系统向全社会公布的标准中国地图数据&#xff0c;是最权威的地图数据。 今天介绍的R包“ggmapcn”&#xff0c;就是基于最新公布的地图…

2025考研江南大学复试科目控制综合(初试807自动控制原理)

​ 2025年全国硕士研究生招生考试江南大学考点 一年年的考研如期而至&#xff0c;我也变成了研二了&#xff0c;作为2次考研经历的学长&#xff0c;总是情不自禁地回想起自己的考研经历&#xff0c;我也会经常从那段经历中汲取力量。我能理解大多数考生考完后的的迷茫无助&…

WebApi使用 (.Net Framework版)

1 创建 使用.Net做web后端&#xff0c;推荐使用.Net Core&#xff0c;微软在此基础上做了很多适配&#xff0c;包括内置Swagger&#xff0c;可以直接启动等等。而.Net Framework版&#xff0c;需要手动配置很多内容。 如果需要调用的项目是基于.Net Framework&#xff0c;那么…

使用 ASP.NET Core wwwroot 上传和存储文件

在 ASP.NET Core 应用程序中上传和存储文件是用户个人资料、产品目录等功能的常见要求。本指南将解释使用wwwroot存储图像&#xff08;可用于文件&#xff09;的过程以及如何在应用程序中处理图像上传。 步骤 1&#xff1a;设置项目环境 确保您的 ASP.NET 项目中具有必要的依…

2024年中国新能源汽车用车发展怎么样 PaperGPT(一)

概述 在国家政策的强力扶持下&#xff0c;2024年中国新能源汽车市场迎来了新的发展机遇。本文将基于《中国新能源汽车用车报告&#xff08;2024年&#xff09;》的数据&#xff0c;对新能源汽车的市场发展和用车趋势概述。 新能源汽车市场发展 政策推动&#xff1a;国家和地…

[论文粗读]A Simple Framework for Contrastive Learning of Visual Representations

引言 今天带来一篇经典论文A Simple Framework for Contrastive Learning of Visual Representations的笔记。 本篇工作提出了SimCLR&#xff0c;一种用于视觉表征对比学习的简单框架。提出(1)数据增强组合在定义有效预测任务中起到至关重要的作用&#xff1b;(2)在表示和对比…

(leetcode算法题)188. 买卖股票的最佳时机 IV

题目中要求最多可以完成k次交易&#xff0c;很多时候不要把问题搞复杂了&#xff0c; 按照题目要求&#xff0c;研究对象是最后一天结束后最多进行了 k 次交易获得的最大利润 那么就可以把问题拆分成 第 1 天结束后完成 0 次交易获得的最大利润&#xff0c;第 1 天结束后完成…

使用 Docker 搭建 Hadoop 集群

1.1. 启用 WSL 与虚拟机平台 1.1.1. 启用功能 启用 WSL并使用 Moba 连接-CSDN博客 1.2 安装 Docker Desktop 最新版本链接&#xff1a;Docker Desktop: The #1 Containerization Tool for Developers | Docker 指定版本链接&#xff1a;Docker Desktop release notes | Do…

win32汇编环境,对话框程序模版,含文本框与菜单简单功能

;运行效果 ;win32汇编环境,对话框程序模版&#xff0c;含文本框与菜单简单功能 ;直接抄进RadAsm可编译运行。 ;下面为asm文件 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&g…