经典版扫雷游戏的实现(含展开)

扫雷作为经典的电脑游戏,曾令很多人着迷,今天我就用C语言实现这个游戏

扫雷的基本规则

扫雷的详细规则是随便点开一个方格,根据展开方格的数字去推断其相邻九宫格内未展开方格下面是否是地雷,最终任务就是点开所有没有地雷的方格,以找出所有的地雷。

用C语言来实现扫雷

由于此程序 所需的代码量稍微有些多,所以我们将其分为三个部分来写
1.test.c 用于写主函数
2.game.c 用于写有关游戏的函数
3.game.h 用于定义函数

首先是扫雷效果图的展示 ,上图 呲牙 在这里插入图片描述

接下来大致介绍下实现扫雷的思路
1.设计主菜单
2.设计扫雷游戏(包括打印棋盘,设置雷,排查雷)

接下来开始逐一详细介绍

首先就是游戏主体的实现

让玩家可以自行选择开始或者结束游戏

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

}
void game()
{
    
    
   printf("扫雷");
}

int main()
{
    
    
	srand((unsigned)time(NULL));
	int input;
	do
	{
    
    
		menu();
		printf("请选择\n");
		scanf("%d",&input);
		switch (input)
		{
    
    
			case 1:
				game();
				break;
			case 0:
				printf("游戏结束\n");
				break;
			default:
				printf("选择错误,请重新选择\n");
				break;
		}

	} while (input);
	return 0;
}

扫雷game 的实现

首先我们需要的就是打印棋盘,在这里我们是游戏的设计者,所以我们需要打印两个棋盘,一个棋盘是给用户所展示的,另一个棋盘是给我们自己来看的(我们通过这个棋盘来实现游戏的实现),效果图如下
在这里插入图片描述
第一个满是*号的棋盘就是给用户所展示的,
第二个布满0,1的棋盘就是给我们自己所展示的,0代表着安全,1代表着雷,( 这里为什么用0 ,1代表安全与雷,在随后进行解释)

  1. 初始化棋盘,在初始化时有我们需要注意的细节
    我们首先来设计一个9x9的棋盘,这里就需要借助二维数组
char mine[ROWS][COLS];//存放布置好的雷的信息 
char show[ROWS][COLS];//存放的是排查出的雷的信息

注:

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void Initboard(char board[ROWS][COLS], int rows, int cols, char set)
{
    
    
	int i = 0, j = 0;
	for(i = 0;i < rows;i++)
	{
    
    
		for (j = 0;j < cols;j++)
		{
    
    
			board[i][j] = set;
		}
	}
}

//初始化棋盘
	Initboard(mine, ROWS, COLS, '0');
	Initboard(show,ROWS, COLS, '*');

我们通过此函数,来给棋盘进行初始化,实现上诉效果图所展示的
相信到这里细心的小伙伴已经发现了端倪,我们想创建的是9x9的棋盘,初始化也是初始9x9的棋盘即可,而上述代码初始的却是11x11的棋盘,难道是写错了吗,其实不然

我们都明白,扫雷是要随便随便点开一个方格,然后此方格呈现一个数字告诫我们这个方格周围有几个雷,例如下图
在这里插入图片描述
呈现2,说明这个格子周围8个格子中存在着2个雷,所以在设计算法时要统计点击处周围8个方位雷的个数,假如要统计边缘边缘处的雷时,就会造成数组越界,影响程序的实现,所以想要打印9x9的棋盘时,我们要专门打印成11x11的棋盘,多出来的我们不要展示即可!
在这里插入图片描述

  1. 进行打印棋盘
void displayboard(char board[ROWS][COLS], int row, int col)
{
    
    
	int i = 0, j = 0;
	printf("----------------扫雷游戏————————\n");
	for (i = 0;i <= col;i++)
	{
    
    
		printf("%d.",i);
	}
	printf("\n");
	for (i = 1;i <= row;i++)  //此处i与j都是从1开始
	{
    
    
		printf("%d.", i);
		for (j = 1;j <= col;j++)
		{
    
    
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("----------------扫雷游戏————————\n");

}
``
```c
displayboard(mine, ROW, COL);
displayboard(show, ROW, COL);

这样一个棋盘界面就诞生了,效果图如上

  1. 布置雷

首先要明白的是雷的位置是随机的(所以这里借助随机数rand),其次还要自己设置雷的个数(用宏定义实现) ,同时注意雷所在的位置是在9x9棋盘上的

#define EASY_COUNT 10  // 雷的个数
void SetMine(char mine[ROWS][COLS], int row, int col, int count)
{
    
    
	while (count)
	{
    
    
		int x =  rand() % row + 1;  // 用到rand,注意主函数要使用srand((unsigned)time(NULL));
		int y =  rand() % col + 1;
		if (mine[x][y] =='0')//x,y坐标处没有雷
		{
    
    
			mine[x][y] = '1';
			count--;
		}
	}
}
  1. 雷的位置已经就位,接下来所做的就是排查雷
Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    
    
	int win = 0;
	while (win<row*col-EASY_COUNT)
	{
    
    
		printf("请输入要排查的坐标: ");
		int x = 0, y = 0;
		scanf("%d %d",&x,&y);
		//坐标的合法性
		//该坐标是不是雷,是雷,统计雷的个数
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
    
    
			if (mine[x][y] == '1')
			{
    
    
				printf("很遗憾,你被炸死了\n");
				displayboard(mine, row, col);
				break;
			}   
			else
			{
    
    
				int count = GetMinecont(mine, x, y);
				show[x][y] = count + '0';
				displayboard(show,row,col);
				win++;
			}
		}
		else
		{
    
    
			printf("该坐标不合法,请重新输入");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
    
    
		printf("恭喜你排雷成功\n");
		displayboard(mine, row, col);
	}

}

win 代表我们所探的地方,如果该处安全则win 增加,同时还需要进行统计所探出雷的个数我们用以下函数实现

int GetMinecont(char mine[ROWS][COLS],int x, int y)
{
    
    
	int i = 0, j = 0, sum = 0;
	for (i = x - 1;i <= x + 1;i++)
	{
    
    
		for (j = y - 1;j <= y + 1;j++)
		{
    
    
			sum += mine[i][j];
		}

	}
	return sum - 9 * '0';
}

这里就对应开头提出的问题,为什么用0与1来代表安全与雷,主要是为了我们统计雷个数算法的简便性!,同时此函数非常的巧妙
如果我们用其他的字符代替,就会增大运算量,也不会像此函数一样简便,这里依然存在着一个细节,如图在这里插入图片描述

我们初始化的0 与1是字符1 与字符0 ,而不是简单的数字1与0;

show[x][y] = count + '0';

同时值得注意的还有此处,如果我们仅仅将count赋给该坐标,(以count==2为例)代表的是以2为ascll值得字符,所以要将他赋值成字符2(赋值字符2的原因是我们初始化就为字符),就要+上一个字符0

到此最简单版本的扫雷已经完成了
**源码 github链接
链接

接下来就是实现展开

实现展开的思路
1.这个坐标没有雷
2.这个坐标周围没有雷
3.这个坐标没有被排查过
通过递归来时实现

void openMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
    
    
	int ret = GetMinecont(mine, x, y);
	if (ret == 0)
	{
    
    
		show[x][y] = ' ';
		if ((x - 1) > 0 && (y - 1) > 0 && (show[x - 1][y - 1] == '*'))
			openMine(mine, show, x - 1, y - 1);
		if ((x - 1) > 0 && (y) > 0 && (show[x - 1][y] == '*'))
			openMine(mine, show, x - 1, y);
		if ((x - 1) > 0 && (y + 1) > 0 && (show[x - 1][y + 1] == '*'))
			openMine(mine, show, x - 1, y + 1);
		if ((x) > 0 && (y - 1) > 0 && (show[x][y - 1] == '*'))
			openMine(mine, show, x, y - 1);
		if ((x) > 0 && (y + 1) > 0 && (show[x][y + 1] == '*'))
			openMine(mine, show, x, y + 1);
		if ((x + 1) > 0 && (y - 1) > 0 && (show[x + 1][y - 1] == '*'))
			openMine(mine, show, x + 1, y - 1);
		if ((x + 1) > 0 && (y) > 0 && (show[x + 1][y] == '*'))
			openMine(mine, show, x + 1, y);
		if ((x + 1) > 0 && (y + 1) > 0 && (show[x + 1][y + 1] == '*'))
			openMine(mine, show, x + 1, y + 1);
	}
	else
		show[x][y] = ret + '0';
}

同时在排查雷的函数上稍微进行修改

Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    
    
	int win = 0;
	while (win < row * col - EASY_COUNT)
	{
    
    
		printf("请输入要排查的坐标: ");
		int x = 0, y = 0;
		scanf("%d %d", &x, &y);
		//坐标的合法性
		//该坐标是不是雷,不是雷,统计雷的个数
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
    
    
			if (mine[x][y] == '1')
			{
    
    
				printf("很遗憾,你被炸死了\n");
				displayboard(mine, row, col);
				break;
			}
			else
			{
    
    
				int count = GetMinecont(mine, x, y);
				show[x][y] = count + '0';
				if (count == 0)
				{
    
    
					openMine(mine, show, x, y);
				}
				displayboard(show, row, col);
				win++;
			}
		}
		else
		{
    
    
			printf("该坐标不合法,请重新输入");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
    
    
		printf("恭喜你排雷成功\n");
		displayboard(mine, row, col);
	}

}

效果图如下在这里插入图片描述
**源码 github链接
点这里
感谢你的耐心阅读!!!

猜你喜欢

转载自blog.csdn.net/qq_52433890/article/details/113728909