C语言之扫雷游戏的实现

        今天用c语言做一个扫雷游戏

首先我们要确定扫雷游戏的主题,大概上百行代码,所以我们需要分多文件进行写代码。主要分为三大文件,一个是头文件game.h,两个是c语言源文件game.c和main.c。头文件game.c里面主要是放函数声明,头文件和宏定义,game.c主要是放游戏主体函数的实现和定义,main.c主要引用前面两个文件,并且进行主体结构的写入。

  首先是在main.c写上我们的main函数,为了我们的main函数简化美观和提高移植性,我们可以在main.c里面定义一个test函数,然后把主要结构写在里面。就像我们平时在玩游戏时一样,我们在test函数里面首先要输出一个菜单,让玩家输入选择输入input选择开始游戏还是退出游戏,1表示开始游戏,0表示退出游戏,如果玩家输入错误还要提示输入错误并且让玩家重新输入,那么我们在这里就要用到do while循环,while的条件里面就加上input,这样只要input不是0就可以再次循环输入,这个和菜单输入简直天造地设的一个循环。那么我们就可以得到下面的test函数:

void test()
{
	int input = 0;
	do
	{
		printf("***********************\n");
		printf("********1.satrt *******\n");
		printf("********0.exit  *******\n");
		printf("***********************\n");
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:break;
		case 0:break;
		default:printf("输入错误,请重新输入\n"); 
		}
	} while (input);
	
}

我们可以看到,四行的printf很是啰嗦,这违背了我们想要简化代码逻辑的初衷,所以我们可以使用一个menu函数把这四行代码收纳封装

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

void test()
{
	int input = 0;
	do
	{
		printf("请选择:");
		scanf("%d", &input);
		
		switch (input)
		{
		case 1:break;
		case 0:break;
		default:printf("输入错误,请重新输入\n"); 
		}
	} while (input);
	
}

这样看起来就更加好看了。

然后就是我们输入了case为1时,我们就要开始游戏了,那么还是按照之前的规则,游戏函数我们也做一个game函数封装主要的函数,作为主要流程的存放处,由于这个game函数我们放了很多主体函数,所以根据它的重要性,我们就把它放在我们的mian.c里面,这样我们就方便对游戏主要逻辑进行修改。

我们知道一个扫雷游戏我们需要一个棋盘,然后我们还要一个存放雷的二维数组和一个用来给玩家看到的棋盘。我们把存放雷的数组命名为mine数组,数组里面用0代表没有雷,用1代表有雷,再把给玩家看到的数组命名为show数组,show数组初始全部为*,玩家不可见,我们暂时决定做一个9*9的棋盘,但是我们会发现一个问题————

我们作为一个玩家玩游戏的时候需要选择排查的坐标,之后我们要给玩家看到我们选择的那个坐标周围八个区域到底有没有雷,有几个雷,这个我们需要通过mine数组和选择的坐标附近几个坐标进行计数,如果我们设计的是9*9的数组,会有下面的情况:

当我们选择坐标(2,5)时很见到那可以直接数出数量,但是当我们选择(8,6)时,我们会发现我们需要去特殊讨论很多种情况,那样我们的代码就会变得特别啰嗦。为了简便的代码和逻辑,我们可以把二维数组再扩大一圈,像这样:

我们再把这个全部放上0,保证没有雷就好了,为了统一一下,我们的show数组也可以做这样的扩大,于是我们的数组就要设置为11*11的了,然后我们要开始定义数组,我们如果是定义数组元素个数还是用一个一个数字的话,如果我们要改变棋盘大小,我们就要重复做很多工作,这样会让我们疲惫不堪,所以我们就可以在头文件里面使用宏定义,这样就可以简化工作了。

//宏定义区域
#define ROW 9   //行
#define COL 9   //列

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

之后我们如果想要改变行和列的长度,就可以在头文件对宏定义区域改数字就可以了。

然后我们就可以定义两个11*11的二维数组了,对了,我们在这个game.h头文件里面定义了,我们就要在main.c和game.c里面用#include"game.h"引用头文件才可以使用我们定义的东西,然后我们就得到了棋盘的二维数组

	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };

接下来我们概要对我们的数组进行初始化,比如说我们这个mine数组要全部初始化为‘0’而我们的show数组要初始化为‘*’,那么我们接下来就要定义一个初始化函数。

void InitBoard(char arr[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			arr[i][j] = '0';
		}
	}
}

但是我们发现,如果我们就这样做这样的函数的话,我们就还需要改变函数里面的内容才可以对连两个棋盘都初始化,所以,我们应该在函数的形参部分再定义一个字符,通过改变输入的字符就可以适应两个棋盘的初始化。

void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			arr[i][j] = set;
		}
	}
}

接下来我们只要再在头文件声明一下这个函数,然后我们就可以在main.c里面使用这个函数对这两个数组进行初始化了。

	InitBoard (mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

然后我们要知道自己初始化的数组对不对,我们可以先写一个棋盘打印函数

//棋盘打印函数
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

这里我们输入的数值是row和col,因为我们增加数组大小到11*11为的是防止数组越界,但是我们实际想要的只有9*9的那一部分,所以我们就只需要用到9*9部分打印

然后我们可以试试效果+

很完美,就是如果我们要玩游戏的时候,好像很难找坐标,那么我们就要对我们的代码做一点点小小的改动:

void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

这样我们的棋盘就可以做出一个可以打印坐标编号的效果了:

这样就好了很多,然后我们发现,我们的放雷的棋盘要用1代表一个雷,但是仙子啊我们还没有做放雷的操作,所以我们现在要做一个放雷的函数:

首先我们要考虑放几个雷,这里我们使用宏定义去定义一个MINECOUNT为10,如果我们之后想要做雷的数目的变换的话,就可以直接在头文件里面更改就好了。然后就是我们的随机布置雷,我们就要定义两个坐标,坐标之前为没有雷的话就把它改为雷,这样我们就要用到随机数的函数,我们要使用时间戳来实现,我们就要在game.h里面再多引用两个头文件

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

这样我们就可以完成我们的函数了

//放雷函数
void SetMine(char mine[ROWS][COLS], int row, int col)
{
	srand((unsigned int)time(NULL));
	int count = MINECOUNT;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
	
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

这样就好了,我们就可以把它放在棋盘打印函数前面,用棋盘打印函数试试能不能正常运行

可以看到,非常的完美。然后我们就可以继续我们的代码实现了。我们放完雷之后,就可以让我们的玩家开始排雷了。接下来我们就可以设置一个排雷函数,大概就是玩家选择一个坐标,我们的代码判断这个坐标在mine数组里面是不是雷,如果是就结束游戏,否则就继续游戏,并且玩家可以看到自己刚刚选择的坐标周围雷的总数

//数雷函数
int CountMine(char mine[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;
	int sum = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)
		{
			sum += mine[i][j];
		}
	}
	sum -= '0' * 9;
	return sum;
}
//排雷函数
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = row*col-MINECOUNT;
	while (win)
	{
		printf("请选择您要排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= ROW && y >= 1 && y <= COL && show[x][y] == '*')
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了,游戏结束\n");
				DisplayBoard(mine, row, col);
				break;
			}
			else if (mine[x][y] == '0')
			{
				int ret = CountMine(mine, x, y);
				show[x][y] = ret + '0';
				DisplayBoard(show, row, col);
				win--;
			}
		}
		else if (show[x][y] != '*' && x >= 1 && x <= ROW && y >= 1 && y <= COL)
			printf("已经排查过的坐标\n");
		else
			printf("坐标无效,重新输入\n");
	}
	if (win == 0)
	{
		printf("YOU WIN\n");
	}
}

这样我们就完成了这个扫雷游戏代码,快来一把酣畅淋漓的扫雷游戏吧!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值