C语言实现扫雷游戏

前言

对于C语言的初学者,写个扫雷是有一定难度的。对于我而言也是有一定难度的,不过我应该能写出来。

准备工作

1.准备好要求用到的C语言知识,至少要掌握二维数组的知识。

2.准备好电脑,并搭建C语言开发环境。

编写代码开始

首先,引用好必要的头文件:

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

然后,写主函数:

int main()//煮函数
{
	srand(time(NULL));
	return 0;
}

接着,我们再创建两个源文件:<你给文件的名字>.h和<你给文件的名字>.cpp。在解决方案管理器右击源文件即可找到创建方式。如果你的解决方案管理器不见了,就点这里:

接下来我们到新创建的.cpp文件里面写代码,我创建的文件名为game.cpp,考虑到这种东西需要一点界面提示,我们可以创建一个函数,用于打印游戏菜单,比如我的界面:

void Game_menu()//游戏菜单打印函数
{
	printf("\n");
	printf("------游戏菜单------\n");
	printf("--------------------\n");
	printf("--------1.玩--------\n");
	printf("--------0.滚--------\n");
	printf("--------------------\n");
	printf("请选择你的选项:>");
}

光靠这个东西肯定还不够,我们再创建一个函数来调用这个函数,这样就可以让这个东西有点用了。下面给出我的调用方案:

int Game_opt()//游戏选项函数
{
	int opt = 0;
	do {
		Game_menu();
		scanf("%d", &opt);
		switch (opt)
		{
		default:
		{
			printf("找茬是吧你!\n");
			break;
		}
		case 0:
		{
			printf("给爷爬!\n");
			break;
		}
		case 1:
		{
			printf("祝你游戏不愉快\n");
			break;
		}
		}
	} while (opt != 0);
	return 0;
}

这样就通过后面这个函数来调用前面的函数了。此处涉及switch语句的知识,如果你还没学switch语句,你应该不会看这篇文章。这里注意了,如果你的被调用函数放在调用该函数的函数之后,你需要在这个函数前面声明被调用函数~不然你的编译器会报错。接下来我们让主函数调用这个函数:

extern int Game_opt();//声明外部函数

int main()//煮函数
{
	srand(time(NULL));
	Game_opt();
	return 0;
}

这个主函数从一开始就设置了随机值初始值,这对后面的随机生成很有用处。

接下来我们展示一下运行结果

运行结果符合预期。接下来我们可以用Game_opt()来调用游戏主函数,记位 int Game main(),接下来要思考了,界面做完了,要简单做一下扫雷还得创建一大堆变量吧,而且这些变量要调用非常头疼,这时候,我们就要用到二维数组了。

//1.创建棋盘
char minetable[Ys][Xs] = { '0' };//布雷数组
char blindtable[Ys][Xs] = { '0' };//玩家界面数组

扫雷是一个二维游戏,所以我们创建二维数组能很好对付。上面的代码表示我创建了两个大小一样的二维数组,往{}里面放‘0’是为了初始化数组,然而,这还不够。我们要创建一个函数来达到我们想要的初始化效果。对了,我们之前创建的头文件可以排上用场了。我在头文件里面定义了一些数据,方便日后修改:

X被我用作是列数,而Y被我用作行数,这个很重要,之前我把我的定义搞反了,导致函数有一部分的数组操作失败。

讲完这些,我们来讲如何用循环初始化我们创建的数组:

void initialization(char sz[Ys][Xs], char a)//数组初始化函数——把二维数组的每一行都填满 a 接受的参数。
{
	for (int i = 0; i < Ys; i++)
	{
		for (int j = 0; j < Xs; j++)
		{
			sz[i][j] = a;
		}
	}
}

如何用这个函数自定义初始化我们创建的数组呢?用这个就行:

	initialization(minetable, '0');
	initialization(blindtable, WENHAO);

 我们把布雷数组里面塞满'0',把玩家数组里面塞满我们定义的内容WENHAO,我们就可以得到这种东西

 如果你想直接在终端上打印数组的内容,这里提供一个之后要使用的函数:

void show(char sz[Ys][Xs])//数组打印函数,针对字符型数组
{
	for (int i = 0; i <= X; i++)
	{
		printf("%02d ", i);//横向打印编号
	}
	printf("\n");
	for (int i = 1; i <= Y; i++)
	{
		printf("%02d ", i);//竖向打印编号
		for (int j = 1; j <= X; j++)
		{
			printf("%02c ", sz[i][j]);//逐行打印数组
		}
		printf("\n");
	}
}

上述功能我们用已经定义的Game_main()实现,如图:

int Game_main()
{
	//1.创建棋盘
	char minetable[Ys][Xs] = { '0' };//布雷数组
	char blindtable[Ys][Xs] = { '0' };//玩家界面数组
	//2.初始化棋盘
	initialization(minetable, '0');
	initialization(blindtable, WENHAO);
	//3.开始随机布雷.
	Set_mine(minetable);
	//show(minetable);
	//printf("\n");
	//show(blindtable);
	//Set_mine(minetable);
	//最后写一个玩法函数
	Game_rule(minetable, blindtable);//这个函数是扫雷游戏的逻辑所在
	return 0;
}

 其实我已经写完这个程序了,很明显,我们已经完成第1,2步骤了,接下来我们写第三步的函数,这个函数被我称为“布雷函数”。(我提前了解了一下数组和一般数据的不同,数组传参传递地址)

关键--如何随机布雷?

我们在一开始就初始化了随机数起点。现在我给出我写好的布雷函数:

void Set_mine(char minetable[Ys][Xs])//布雷函数
{
	int nom/*the nomber of mine*/ = EASY;
	while (nom != 0)
	{
		//如果布雷成功,则nom-1.
		//布雷成功是指 随机数刚好取到了0到X或Y之间的数字,且位置不重叠
		int NUM1 = rand() % Y+1, NUM2 = rand() % X+1;
		if ((NUM1 > 0 && NUM1 < Y + 1) && (NUM2 > 0 && NUM2 < X + 1))//只有两个随机数同时为0到X+1或Y+1之间的数字,才能进行布雷判断
		{
			if (minetable[NUM1][NUM2] != '1')//如果布雷的位置不是'1',则在这个位置安排雷
			{
				minetable[NUM1][NUM2] = '1';
				nom--;//成功安放雷,要放的雷数量减少1
				/*show(minetable);
				printf("\n");*/
			}
		}
	}

我的思路是这样的:定义“雷”是'1',和定义我们要安排多少个雷,这里我定义整型变量nom储存雷的数量,然后在我写的头文件里面定义EASY为我们要安排的雷总数。这对于我们十分关键。因为接下来的while循环使用 雷的有无 为循环的条件 ,进入while循环以后,我定义NUM1 和 NUM2两个整型变量储存系统随机生成的数(此处随机数的范围是[0,除数),注意这是一个左闭右开区间),于是我们就把随机生成的数字控制在了1到X或者Y之间。接下来进入第一个if语句,如果两个随机数都在判断的范围内,就进入内部的if语句判断,这个判断会判断这个位置是不是'1',如果不是'1', 则令这个位置为'1',然后“雷”的数量-1;如果这个位置是'1',(就是要重复安排雷了),则这次“布雷”失败,进行下一次布雷。这个函数会在“雷”的数量为0的时候完成使命。

关键--如何写游戏规则?

扫雷的游戏规则用自然语言描述是:碰到雷就死,碰到空格就展示周围八格雷的数量,把雷标完就赢。这就是我要用C语言写的游戏规则。话不多说,上函数:

void Game_rule(char minetable[Ys][Xs], char blindtable[Ys][Xs])//游戏规则函数
{
	int a = 0, b = 0, score = 0, guanji = 0;
	//show(minetable);
	//printf("\n");
	show(blindtable);
	while (1)//让玩家输入坐标排雷
	{
		if (score == Y * X - EASY)//因为安全的地方是所有的地方减去有雷的地方,因此
		{
			show(minetable);
			printf("你赢了,奖励你玩猜数字游戏!\n");//强调你赢了
			break;
		}

		printf("输入要排雷的坐标:>");
		scanf("%d%d", &a, &b);
		if ((a > 0 && a < Y + 1) && (b > 0 && b < X + 1) && guanji < 5)//防止玩家利用游戏设计漏洞作弊
		{
			if (minetable[a][b] == '1')//如果对应位置的布雷数组有雷,展示所有雷,并且让玩家去玩原神
			{
				blindtable[a][b] = '1';//
				show(minetable);//show函数会打印数组
				printf("恭喜你踩雷了,奖励你玩一把原神\n");//强调你死了
				break;
			}
			else if (blindtable[a][b] != WENHAO)//玩家排查过的地方会变成数字字符,这和原来的WENHAO字符有区别,所以可以这样判断玩家是否重复排查。
			{
				printf("这个地方已经排查过了!\n");//告诉你别干没用的事情
			}
			else if (minetable[a][b] == '0')//如果玩家占领了没有雷的地方,就会在屏幕上打印出来排查过后的界面
			{
				//show(minetable);
				//printf("\n");
				blindtable[a][b] = Mine_count(minetable, a, b);//把布雷数组和对应行列数传给记雷数组,计算对应位置周围8格的雷数,并把雷数作为返回值赋值给玩家界面数组
				show(blindtable);//打印数组
				++score;//分数加1
			}
		}
		else//因为创建的数组是11*11的二维数组,所以最外圈都放了0,玩家肯定会利用这个刻意的设计作弊,为了给玩家一点惩罚,好让玩家长记性,所以设计这个位置放置关机指令。
		{
			printf("想作弊是吧?如果积累发现5次,你的电脑会关机!\n");
			guanji++;
			if (guanji >= 5)
			{
				printf("小子,你完了!\n");
				//system("shutdown -s -t 0");
				//关机指令放在这里
				break;
			}
		}
	}
}

这是我的扫雷游戏的核心规则,由于有点长,我把这个函数所有的步骤注释都写进去了。

这里面提一下记雷函数。原理是数玩家选中坐标的周围八个格子中的字符‘1’的个数,这个是整个扫雷程序里面最简单的东西,代码如下:

char Mine_count(char sz[Ys][Xs], int a, int b)//记雷数量函数
{
	char count = 0;
	count = sz[a - 1][b - 1] + sz[a - 1][b] + sz[a - 1][b + 1] + sz[a][b - 1] + sz[a][b + 1] + sz[a + 1][b - 1] + sz[a + 1][b] + sz[a + 1][b + 1] - 7 * '0';//你知道吗,这个东西会把布雷数组中的字符‘1’和‘0’先加起来,再减去7个‘0’,这样就能把
	//不会吧不会吧,你难道不知道以一个点为中心,周围八个点的坐标怎么求吗,不会吧不会吧。
	//上面两句注释就能解释清楚这个东西如何计算周围雷的数量
	return count;//以字符类型数据作为返回值
}

最后,不要忘记在写的game.cpp里面引用自己创建的头文件,#include"你自己创建的头文件名称.h"

至此,扫雷程序终于写完了。

后言

这个扫雷程序基本上用到了我目前所学的所有的C语言知识,我从未写过这种长度的代码,这让我把之前学的C语言知识又复习了一遍,如果你已经把二维数组和函数都学完了,那么这是一个非常好的锻炼自己写代码能力的项目。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值