C语言——扫雷游戏实现(超详解)

目录

一、扫雷游戏规则与实现思路

1、游戏概述

2、游戏规则描述:

3、游戏实现思路

二、模块化代码实现

1、创建主函数main()

2、创建菜单函数

 3、创建游戏函数game()

①棋盘的设置

②棋盘的初始化

③打印棋盘

④雷的布置

⑤雷的排查

三、全部源码

四、总结


一、扫雷游戏规则与实现思路

1、游戏概述

扫雷游戏想必大家应该都玩过吧,这个游戏的目标呢就是在一个 9x9 的棋盘上找出所有没有地雷的格子,而不踩到地雷。当然这个9×9只是一个初级玩法,棋盘大小和雷的数量是可以随便设置的,有那种电脑满屏的模式,但是我没去尝试过,一般玩的都是初级9×9的模式,而本篇文章也主要说的是9×9扫雷游戏的实现。

扫雷游戏网页版 - Minesweeper

2、游戏规则描述:

  1. 棋盘上的某些格子里有地雷,其他格子是空白的。
  2. 游戏开始时,棋盘上会有一些数字,这些数字表示周围 8 个格子中地雷的数量。
  3. 通过点击格子,如果格子是空白的,则会打开该格子;如果格子中有地雷,则游戏结束。
  4. 如果打开的格子周围的地雷数量与数字相符,则该格子周围的其他格子也会被打开。
  5. 游戏的目标是在不踩到地雷的情况下,找出所有没有地雷的格子。

扫雷游戏需要玩家运用逻辑推理和数学计算来推断哪些格子可能有地雷,哪些格子是安全的。通过不断尝试和推理,最终完成游戏。总的来说扫雷游戏是一款能够锻炼玩家多种能力的益智游戏,对提高玩家的逻辑推理、数学计算、观察、耐心和毅力、空间想象力等能力都有帮助。平时没事的时候可以玩一玩的,我个人感觉还是很interesting!

3、游戏实现思路

第一步,首先是需要我们去创建一个菜单界面函数,用于选择退出游戏或者是进入游戏。
第二步,创建用于放置雷的棋盘,并进行棋盘初始化。
第三步,放入雷,并打印出雷的初始化棋盘
第四步,输入排查雷的坐标

第五步,反馈输入坐标的结果,之后循环,直到成功排查或被炸死

在扫雷的过程中,创建棋盘布置雷和排查雷都需要储存信息,所以我们需要一定的数据结构来存储这些信息,在布置雷时,如果是雷就放1,不是雷就放0;

同时为了让游戏具有一定的可玩性,便于修改游戏难度,那么们便在头文件中define行、列和雷的数量

#define number 10//雷的个数
#define ROW 9//棋盘显示的长宽
#define COL 9

#define ROWS ROW+2//设置的存储的棋盘的长宽
#define COLS COL+2

二、模块化代码实现

在实现代码之前,我们使用多文件的形式对函数的声明与定义,这可以极大的简化我们的代码

test.c //⽂件中写游戏的测试逻辑 
game.c //⽂件中写游戏中函数的实现等
game.h //⽂件中写游戏需要的数据类型和函数声明等

1、创建主函数main()

在主函数中我们创建一个put值,用于输入判断我们菜单的选择,用do  while判断我们输入的选择是否结束,在这里我们需要创建菜单函数,每一次循环我们都调用菜单函数,接着使用switch语句中,来执行输入的结果,如果输入1则提示玩家开始游戏并调用游戏函数game(),输入0则退出游戏,输入其他数值则提示错误,并循环执行switch语句,直至玩家主动退出。

int main()
{
	int put = 0;//选项选择
    srand((unsigned int)time(NULL));//生成一个随机数,time函数无参返回,返回类型强制转换为unsigned
	do {
		menu();//调用菜单函数
		printf("请输入你的选择:");
		scanf(" %d", &put);
		switch (put)//switch语句,判断执行内容
		{
		case 1:
			printf("n请开始扫雷n");
			game();
			break;
		case 0:
			printf("n已退出游戏!n");
			break;
		default:
			printf("n选择错误,请重新输入!n");
			break;
		}
	} while (put);

	return 0;
}

2、创建菜单函数

因为不需要返回值所以使用void,菜单函数会在mian()函数中被调用

void menu()//不需要返回值,void
{
	printf("***********************n");
	printf("***********************n");
	printf("******  1.play  *******n");
	printf("******  0.exit  *******n");
	printf("***********************n");
	printf("***********************n");
}

 3、创建游戏函数game()

①棋盘的设置

扫雷游戏我们首先要创建一个棋盘用于放置雷,而棋盘我们用二维数组char[x][y]来设置,x,y表示棋盘的行列,那么在设置棋盘之前,我们先来说一下游戏的排雷,当我们任意选择棋盘中的一个坐标,如果这个坐标放置的不是雷,那么它就会显示以当前坐标为中心的周围 8 个格子中地雷的数量,如图所示

但是如果我们选择的坐标是这个棋盘的最边上,那么它所搜查的范围就会超出所设置的二维数组9×9的棋盘,如下图所示的灰色框,中心位置显示周围有两个雷,但是它搜查的范围是以它为中心的一个九宫格,所以最下面的那一行就已经不在一开始布置的9×9棋盘里了,出了棋盘的范围,导致了越界问题

所以我们在设置棋盘的时候可以选择将棋盘的范围设置的大一些,在9×9棋盘的基础上,将二维数组扩大一圈设置成11×11的棋盘,如下图所示,中间蓝色范围是用来布置雷的棋盘,而周边多出来的一圈绿色便是用来防止越界问题的,那么在这个棋盘上我们输入坐标排查的的范围都是在棋盘的范围之内,就不存在越界问题了,所以在设置棋盘的时候我们将存放数据的数组可以设置成char[11][11]

假设我们现在已经布置好了雷(雷用1表示,不是雷用0表示),当我们搜查一个坐标的时候,如果这个坐标周围有一个雷,那么我们需要将这个雷的数量信息记录并存储下来,同时打印给玩家,但是我们存放雷的数组里面已经有数据了,如果再存放在里面就会可能产生混淆从而导致棋盘混乱打印困难,所以我们可以设置两个棋盘,一个是雷的棋盘mine,一个是用于放置雷的信息的棋盘show,我们后面会把雷布置到到mine数组里面,再mine数组排查雷之后,将雷的信息存放到show数组里面,然后打印show数组的信息给用户参考排查,这样就不会存在数据混淆了。

char mine[ROWS][COLS];//设置成可变量方便于修改游戏难度
char show[ROWS][COLS];//此处ROWS与COLS值为11

②棋盘的初始化

棋盘设置好之后呢,我们就该对棋盘进行初始化,让用于雷的棋盘数组mine中先全是无雷信息,全部初始化为字符‘0’;显示给用户看的棋盘数组show初始化字符全部为‘*’,这样可以让用户不知道*下面的信息,从而保持游戏的可玩性。同时,为了报纸两个数组类型的一致,我们使用同一套函数对这两个数组进行初始化处理,如下图所示

//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)//接收数组,行,列,所要初始的内容
{
	int i = 0; //控制行
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)//控制列
		{
			arr[i][j] = set;//初始化数组
		}
	}
}

//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');//用于存放雷的棋盘,初始化为0
InitBoard(show, ROWS, COLS,'*');//用于显示给用户看的,初始化为*

③打印棋盘

在初始化棋盘中之后,我们输入选项 ‘1’ 之后进入游戏时为了不让界面过于单调,我们需要打印一个隐藏信息的棋盘给用户看,从而方便用户进行游戏,如下图所示

那么我们该如何打印呢,首先要传给函数的参数是mine数组、行和列,在进入函数之后我们为了让在棋盘的周围显示行与列,首先从零开始循环打印小于等于列号的数,打印完之后开始打印棋盘,在打印每一行开始之前呢,还是先打印行号再接着打印mine数组的每一行,那么最终代码的实现就如下所示

//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)//打印显示的棋盘
{
	int i = 0; //控制行
	for (i = 0; i <= col; i++)//打印列号
	{
		printf("%d ", i);
	}
	printf("n");
	for (i = 1; i <= row; i++)                                     
	{
		int j = 0;
		printf("%d ",i);//打印行号
		for (j = 1; j <= col; j++)//控制列
		{
			printf("%c ", arr[i][j]);//循环打印数组里的所有内容
		}printf("n");//每一行打印完之后换行
	}
	printf("n");
}

//打印棋盘
DisplayBoard(show,ROW,COL);//打印9×9显示给用户看的棋盘

④雷的布置

现在我们棋盘初始化完成了,但是mine里面全是‘0’,没有雷的信息,所以现在我们需要往数组mine里面放入雷的信息,那么我们该如何放置呢?现在让我们来理一下思路,我们要在一个9×9的棋盘范围大小,一共81个坐标里面放置10个雷,为了保证游戏的可玩性,所以我们放置的这十个雷应该是随机的,是随机布置在这81个坐标中的任意10个。

(1) rand() 函数

在这里我们就需要用到随机数生成函数rand(),使用这个函数需要包含一个头文件 stdlib.h但我们需要注意的是,由于随机数生成器的实现方式,生成的随机数可能不是完全随机的,而是一种伪随机数,在一些固定的模式下以它的种子为基准值生通过某种算法根据成的可以算的伪随机数。而rand函数的种子一般是默认为一个固定值,那么现在我们可以知道,如果想让rand函数生成一个真正的随机数就需要时刻改变它的种子就可以了。

(2) srand() 函数

现在我们就要用到srand()函数了,它一般用于初始化随机数生成器,通常是为rand函数设置种子,以便生成不同的随机数序列。所以我们在每次调用rand函数之前应先调用srand函数,以传入不同的种子。而srand函数通过参数seed来设置它的随机生成数,也就是说我们需要种子的种子不是一个固定值,只有这样,rand函数生成的数才是真正的随机数。

(3) time()函数

因为时间是每时每刻都在变化的,所以我们一般使用当前时间作为srand函数的种子,这里我们就需要使用time函数了,time函数的原型是time_t time(time_t *timer)这样的,使用时需要包含头文件time.h,其实time函数所返回的时间就是自1970年1月1日 00:00:00 UTC(协调世界时)以来的秒数,它的返回值是一个长整数time_t类型的值,表示秒数。如果time函数的参数timer不为空,那么time函数就会将这个返回当前时间的值,并将当前时间存储在参数所指向的变量中。但是如果参数为空,time函数将会返回当前时间的值,而不存储当前时间。

(4) 结合

所以结合以上三个函数,我们知道了一个可以生成真正随机数的方法。即调用这三个函数,以time(NULL)函数返回当前时间的值,然后将其转化为无符号整数,并传递给srand函数,用来初始化随机数生成器。这样,每次调用rand函数的时候,都会基于当前时间生成不同的随机数了!代码如下

srand((unsigned int)time(NULL));//生成一个随机数,time函数无参返回,返回类型强制转换为unsigned

随机数生成之后,它的范围是无法固定的,但是我们布置雷只需要在9×9棋盘上布置,那么我们就可以将这个生成的数%棋盘的长宽然后+1,比如当前棋盘长宽为9,那么用生成的随机数%9得到的数字就是0-8,在+1就是1-9,而一到九就是我们所需要布置棋盘雷的坐标,代码如下

int x = rand()%row+1;//棋盘x的坐标,%row值为0-8,+1值变成0-9
int y = rand()%col+1;//棋盘y的坐标,同上0-9

现在我们雷的坐标范围已经确定好了,开始布置雷吧!我们要布置的雷的数量是10,那么我们首先int count = number;而number已经在头文件game.h中声明过了,当然如果想加大一些难度可以直接更改头文件中number的值。然后使用while循环,以count为条件,每次成功布置好一个雷之后,count--,当雷全部布置完成后count==0,while循环结束。在while循环里面我们使用if语句来判断当前位置是否为雷,不是则布置雷,布置好count自减,如此循环,雷就布置好啦!下面是布置好的例子与代码。

void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = number;//设置雷的数量为10
	while (count)
	{   //使用rand函数需要调用srand函数,设置在主函数里面
		int x = rand()%row+1;//棋盘x的坐标,%row值为0-8,+1值变成1-9
		int y = rand()%col+1;//棋盘y的坐标,同上1-9
		
		if(arr[x][y]=='0')//首先判断当前的随机位置是否有雷,无雷进入
		{
			arr[x][y] = '1';//没有雷就在当前位置下放一个‘1’表示雷
			count--;//放置成功后,雷的数量减一
		}

	}
}

//布置好雷之后可以打印雷,查看是否布置成功,执行的时候此代码需要隐藏
DisplayBoard(mine, ROW, COL);

⑤雷的排查

雷布置好之后我们就需要玩家输入坐标排查雷并将排查后的棋盘显示给玩家,那么当输入一个坐标之后该如何排查呢,首先就是创建一个排雷函数,用于接收有雷的棋盘和用于显示的棋盘,开始我们先定义x,y作为排查坐标,此处的count是可排查的次数,当我们如果将无雷区域全部排查出来之后我们该如何结束呢,所以我们使用while循环,条件是count < row*col - number即count<行*列-雷的数量,每次成功排雷后,count++,当count < row*col - number不成立时while循环结束,执行if语句,如果count == row * col - number,即排雷成功。

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;//排查的坐标
	int count = 0;//可排查的次数
	while(count < row*col - number)
	{
		
		
	    {//成功排查出雷

           count++;
        }
	}
	if (count == row * col - number)//如果排查的次数等于没有雷的数量,则排查成功
	{
		printf("<( ̄︶ ̄)>恭喜你排雷成功!!!");
	}
}

//开始排查雷
FindMine(mine,show,ROW,COL);

那么在while循环里我们该如何排雷呢,我们要知道,当我们输入一个坐标后会有三种情况,即当前位置是雷,当前位置不是雷,以及输入的坐标不在棋盘范围之内,我们先来说当前位置是雷。首先呢,为了让游戏更有可玩性我们可以在玩家输入坐标前进行提示,用printf打印出来,在while里我们使用if语句进行判断玩家输入的坐标是否符合棋盘的,如果坐标正确就开始排查,如果不是就提示错误,代码如下

if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
{

}
else
{
	printf("输入坐标错误,请重新输入n");
}

当玩家输入坐标正确进入排查后,如果输入的坐标当前位置为雷,即在if语句中调用mine数组,如果mine[x][y] == '1',即为雷。然后我们就进入if语句输出提示并且打印雷没有隐藏的棋盘,break跳出当前while语句。

if (mine[x][y] == '1')//如果输入的坐标位置是‘1’,则被炸死
{
	printf("很遗憾,你被炸死啦!!!!n");
	printf("n");
	DisplayBoard(mine, ROW, COL);//被炸死了将布置雷的棋盘打印出来
	break;//跳出
}

如果当前位置不是雷,那么我们需要排查这个坐标周围的一个九宫格共八个坐标,我们可以知道我们输入的坐标是这个九宫格的中心,那么这个九宫格也就很好排查啦,我们可以设置一个函数,返回值就是雷的数量,在这里我们将char类型转换为int,方便计算。

/*排查输入坐标周围的雷,static表示此函数只能在game.c里面被调用
  别的文件无法调用,具有一定的私密性*/
static int GetMine(char mine[ROWS][COLS], int x, int y)
{
	//每个坐标相加并减去字符0的大小(字符0的ASII码值为48),转换成数字
	return mine[x - 1][y] + mine[x + 1][y] + mine[x - 1][y - 1] + 
           mine[x][y - 1] + mine[x + 1][y - 1] +
		   mine[x - 1][y + 1] + mine[x][y + 1] + 
           mine[x + 1][y + 1] - 8 * '0';
}

我们在if-else语句中定义一个num来存储排查出的雷的数量,之后再将num由int转换为char类型以便放入show数组中,打印排查过后用于显示给用户的棋盘,同时次数count++。

else//输入位置不是雷,则显示当前位置的周围有几个雷
{
    int num = GetMine(mine, x, y);//九宫格雷的数量函数
   // 将雷的数量放入show数组中, + ‘0’是将num由int类型转换为字符char类型
    show[x][y] = num + '0';
    DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
    count++;
}

以上基本上所有的扫雷代码就完成了,综合代码如下,但是我们在运行时会出现一种情况,就是每次只显示当前位置的雷,不像是我们看到的网页版本那种,如果这个坐标周围没有雷会展开一大片空白,所以代码还是存在着一定的缺陷

while(count < row*col - number)
	{
		printf("请输入要排查的坐标(中间用空格隔开):");
	    scanf("%d %d", &x, &y);//输入排查坐标
		
		if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
		{
			if (mine[x][y] == '1')//如果输入的坐标位置是‘1’,则被炸死
			{
				printf("很遗憾,你被炸死啦!!!!n");
				printf("n");
				DisplayBoard(mine, ROW, COL);//被炸死了将布置雷的棋盘打印出来
				break;//跳出
			}

			else//输入位置不是雷,则显示当前位置的周围有几个雷
			{
                int num = GetMine(mine, x, y);//九宫格雷的数量函数
                //将雷的数量放入show数组中, + ‘0’是将num由int类型转换为字符char类型
                show[x][y] = num + '0';
				DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
				count++;
			}
		}
		else
		{
			printf("输入坐标错误,请重新输入n");
		}
	}

⑥无雷区域的扩展

此处无雷区域的展开我们使用递归函数实现,如果当前坐标的九宫格有雷,那么和上面的代码就是一样的,但是如果无雷,那么我们就不返回0了,而是将show数组中的 ‘*’ 赋值为空格 ‘ ’ ,并且使用for循环将以这个坐标为中心的九宫格全部使用递归函数将show数组中的 ‘*’ 赋值为空格 ‘ ’,而在if-else语句那里有雷的代码就可以直接调用这个扩展函数了,效果和代码如下

else//输入位置不是雷,则显示当前位置的周围有几个雷
{
	ExpandBlank(mine, show, x, y);
	DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
    count++;
}
//无雷区域的扩展,使用递归实现
void ExpandBlank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	int num = GetMine(mine, x, y);//九宫格雷的数量函数
	if (num)
	{
		// 将雷的数量放入show数组中, + ‘0’是将num由int类型转换为字符char类型
		show[x][y] = num + '0';
	}
	else if (show[x][y] == '*')
	{
		show[x][y] = ' ';//将没有雷的地方赋值为空格
		int i = 0, j = 0;//使用循环作为递归的条件,找出无雷区域
		for (i = x - 1; i <= x + 1; i++)
		{
			for (j = y - 1; j <= y + 1; j++)
			{
				ExpandBlank(mine, show, i, j);
			}
		}
	}
}

无雷区域扩展完后,我们的获胜条件判断也需要更改,在这里我们可以写一个获胜判断条件函数,当棋盘中剩余的为排查 * 数量为十个 (雷的数量) 时,即为胜利,则返回真,否则返回假。

//获胜条件函数
int EndMine(char show[ROWS][COLS], int row, int col)
{
	int count = 0;
	for (int i = 1; i <= row; i++)
	{
		for (int j = 1; j <= col; j++)
		{
			if (show[i][j] == '*')//在棋盘上查找没有被排查的点
				count++;//统计没有被排查的点的数量
		}
	}
	if (count == number)//如果没有被排查的点的数量等于雷的数量
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

当我们使用获胜函数后,那么排查雷的函数也需要进行一定的修改,如下

else//输入位置不是雷,则显示当前位置的周围有几个雷
{
	ExpandBlank(mine, show, x, y);
	DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
	
	if (EndMine(show, ROW, COL))//如果没有被排查的点的数量等于雷的数量
	{
		printf("<( ̄︶ ̄)>恭喜你排雷成功!!!n");//则排雷成功
		DisplayBoard(mine, ROW, COL);//打印布置的棋盘
		break;
	}
}

三、全部源码

test.c

#include "game.h"//调用自己创建的头文件用""

void menu()//不需要返回值,void
{
	printf("n***********************n");
	printf("***********************n");
	printf("******  1.play  *******n");
	printf("******  0.exit  *******n");
	printf("***********************n");
	printf("***********************n");
}
void game()//不需要返回值,void
{
	char mine[ROWS][COLS];//设置成可变量方便于修改游戏难度
	char show[ROWS][COLS];

	//初始化棋盘
	InitBoard(mine, ROWS, COLS,'0');//用于存放雷的棋盘,初始化为0
	InitBoard(show, ROWS, COLS,'*');//用于显示给用户看的,初始化为*

	//打印棋盘
	DisplayBoard(show,ROW,COL);//打印9×9显示给用户看的棋盘

	//布置雷
	SetMine(mine, ROW, COL);
	//布置好雷之后可以打印雷,查看是否布置成功
	//DisplayBoard(mine, ROW, COL);

	//开始排查雷
	FindMine(mine,show,ROW,COL);
}

int main()
{
	int put = 0;
	srand((unsigned int)time(NULL));//生成一个随机数,time函数无参返回,返回类型强制转换为unsigned
	do {
		menu();
		printf("请输入你的选择:");
		scanf(" %d", &put);
		switch (put)
		{
		case 1:
			printf("n请开始扫雷n");
			game();
			break;
		case 0:
			printf("n已退出游戏!n");
			break;
		default:
			printf("n选择错误,请重新输入!n");
			break;
		}
	} while (put);

	return 0;
}

game.c

#include "game.h"//调用自己创建的头文件用"

//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)//接收数组,行,列,所要初始的内容
{
	int i = 0; //控制行
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)//控制列
		{
			arr[i][j] = set;//初始化数组
		}
	}
}
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)//打印显示的棋盘
{
	int i = 0; //控制行
	for (i = 0; i <= col; i++)//打印列号
	{
		printf("%d ", i);
	}
	printf("n");
	for (i = 1; i <= row; i++)                                     
	{
		int j = 0;
		printf("%d ",i);//打印行号
		for (j = 1; j <= col; j++)//控制列
		{
			printf("%c ", arr[i][j]);//循环打印数组里的所有内容
		}printf("n");//每一行打印完之后换行
	}
	printf("n");
}

//在棋盘中布置雷
void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = number;//设置雷的数量为10
	while (count)
	{   //使用rand函数需要调用srand函数,设置在主函数里面
		int x = rand()%row+1;//棋盘x的坐标,%row值为0-8,+1值变成0-9
		int y = rand()%col+1;//棋盘y的坐标,同上0-9
		
		if(arr[x][y]=='0')//首先判断当前的随机位置是否有雷,无雷进入
		{
			arr[x][y] = '1';//没有雷就在当前位置下放一个‘1’表示雷
			count--;//放置成功后,雷的数量减一
		}

	}
}

//排查输入坐标周围的雷,static表示此函数只能在game.c里面被调用,别的文件无法调用,具有一定的私密性
static int GetMine(char mine[ROWS][COLS], int x, int y)
{
	//每个坐标相加并减去字符0的大小(字符0的ASII码值为48),转换成数字
	return mine[x - 1][y] + mine[x + 1][y] + mine[x - 1][y - 1] + 
           mine[x][y - 1] + mine[x + 1][y - 1] +
		   mine[x - 1][y + 1] + mine[x][y + 1] + 
           mine[x + 1][y + 1] - 8 * '0';
}

//获胜条件函数
int EndMine(char show[ROWS][COLS], int row, int col)
{
	int count = 0;
	for (int i = 1; i <= row; i++)
	{
		for (int j = 1; j <= col; j++)
		{
			if (show[i][j] == '*')//在棋盘上查找没有被排查的点
				count++;//统计没有被排查的点的数量
		}
	}
	if (count == number)//如果没有被排查的点的数量等于雷的数量
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

//无雷区域的扩展,使用递归实现
void ExpandBlank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	int num = GetMine(mine, x, y);//九宫格雷的数量函数
	if (num)
	{
		// 将雷的数量放入show数组中, + ‘0’是将num由int类型转换为字符char类型
		show[x][y] = num + '0';
	}
	else if (show[x][y] == '*')
	{
		show[x][y] = ' ';//将没有雷的地方赋值为空格
		int i = 0, j = 0;//使用循环作为递归的条件,找出无雷区域
		for (i = x - 1; i <= x + 1; i++)
		{
			for (j = y - 1; j <= y + 1; j++)
			{
				ExpandBlank(mine, show, i, j);
			}
		}
	}
}


//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;//排查的坐标
	int count = 0;//可排查的次数
	while(count < row*col - number)
	{
		printf("请输入要排查的坐标(中间用空格隔开):");
	    scanf("%d %d", &x, &y);//输入排查坐标
		
		if (x >= 1 && x <= row && y >= 1 && y <= col)//排查坐标需要在1-9之间
		{
			if (mine[x][y] == '1')//如果输入的坐标位置是‘1’,则被炸死
			{
				printf("很遗憾,你被炸死啦!!!!n");
				printf("n");
				DisplayBoard(mine, ROW, COL);//被炸死了,将布置雷的棋盘打印出来
				break;//跳出
			}

			else//输入位置不是雷,则显示当前位置的周围有几个雷
			{
				ExpandBlank(mine, show, x, y);
				DisplayBoard(show, ROW, COL);//显示排查过后的用户棋盘
				if (EndMine(show, ROW, COL))//返回为真
				{
					printf("<( ̄︶ ̄)>恭喜你排雷成功!!!n");//排雷成功
					DisplayBoard(mine, ROW, COL);//打印布置的棋盘
					break;
				}
			}
		}
		else
		{
			printf("输入坐标错误,请重新输入n");
		}
	}
}

game.h

#pragma once

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


#define number 10//雷的个数
#define ROW 9//棋盘显示的长宽
#define COL 9

#define ROWS ROW+2//设置的存储的棋盘的长宽
#define COLS COL+2

void InitBoard(char arr[ROWS][COLS],int rows,int cols,char set);//接收数组,行,列,所要初始的内容

void DisplayBoard(char arr[ROWS][COLS], int row, int col);//数组大小不变,但是传过来显示的棋盘变成9×9

void SetMine(char arr[ROWS][COLS], int row, int col);//布置雷

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//排查雷

四、总结

扫雷游戏是一款十分有趣的游戏,在C语言中涉及到了数组,循环和条件语句,随机数的生成,函数,递归等知识点,可以说是把前期所学到的知识进行了一个汇总,敲一遍这个代码还是十分有用的,可以检很好的验一下自己的学习效果,家人们也可以看一看这篇文章然后自己去实现一下。

好啦,以上就是今天的全部分享了,如有不足欢迎家人们评论区批评指正,如果这篇文章对你有用的话,可以给我来个一键三连嘛(写了一天了,求赞求支持/(ㄒoㄒ)/~~)

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇

)">
下一篇>>