❤️童年回忆之扫雷大作战【C语言进阶】超详细教程,不看就亏啦❗❗❗

前言

❤️ 铁汁们大家好,欢迎大家来到出小月的博客里, 🤗🤗🤗之前呢,我分享了C语言的函数篇。。。。今天呢,给大家分享一个童年回忆小游戏“扫雷游戏”,这个小游戏系统地把之前学的循环语句,还有函数都结合起来了,希望大家看完我这篇文章都能够“涨芝士”,感觉小月写的还不错的话,记得👍🏻点赞加关注😘鼓励一下博主哦,不然下次可找不到我啦❗❗


作者简介

❤️ 作者的gitee:出小月
❤️ 作者的主页:出小月的《程序员历险记》
❤️专栏:《C语言》,《数据结构初阶》
😊希望大家都能够:好好学习,天天编程❗❗❗



一、扫雷游戏介绍

🐻《扫雷》这个游戏大家可能并不陌生,我们小的时候经常玩,记得高三的时候,早自习下课,有人就在白板上玩扫雷,哈哈哈,回忆一波。。。不会有小伙伴没有没有玩过吧❓❓没关系,小月这里再介绍一下下😁😁😁
🦒游戏目标是根据点击格子出现的数字(如果这个格子上面的数字是3,就说明周围的八个位置其中有三个雷格子)找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。
在这里插入图片描述

🐹来!咱们一起看这个图片这是一个9*9个格子的棋盘,中间的三代表黑方框圈起来的的格子里有三个是雷,是雷的,打咩,不能踩❗❗❗这大家应该都明白了吧!

二、扫雷游戏最终页面

🐹首先,上来给一个菜单,输入一进入游戏,输入0退出游戏
在这里插入图片描述
我输入下标开始自动排查
在这里插入图片描述
我输入3 9,被炸死了
在这里插入图片描述
游戏基本就是这个,接下来就分析一下!!!

三、扫雷步骤分析

1、菜单

🐷展示一个页面,提示用户,你选择1就进入游戏,你要是选择0就退出游戏,主要是为了更美观❗❗❗
在这里插入图片描述

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

2、总体框架

🐻这个总体框架和三子棋的框架一模一样,我就不解释了。。。
可以看看这个三子棋游戏对框架的解释

void test()
{
	int input = 0;
	do {
		menu();
		printf("请选择->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
}

3、游戏内容

🐹我们要准备两个数组,数组一放置布置好的雷,数组二存放排查出的雷的信息。
🦒刚开始我们要把第一个数组全部初始化为‘ 0 ’,把数组二全部初始为‘ * ’。
🐻然后,我们要把数组一中是雷的位置置为‘ 1 ’,就要随机生成是个下标,把下标位置的字符设置成‘ 1 ’。
🐷数组二上的数组呢?我们就在数组一中根据玩家输入的下标看周围有几个雷,有几个就把数字放到数组二中相应的位置。

思路大概就是这❗❗
在这里插入图片描述
这里定义ROW=9;ROWS=ROW+2;

void game()
{
	//需要存放布置好的雷的信息,存放排查出的雷的信息,需要两个二维数组
	//排查坐标时为了防止数组坐标越界,我们把行增加2,列增加2
	char mine[ROWS][ROWS] = { 0 };//布置好的雷的数组
	char show[ROWS][ROWS] = { 0 };//排查出的雷的数组
	//默认mine数组都是字符零,默认show数组都是字符‘*’
	initboard(mine, ROWS, COLS, '0');
	initboard(show, ROWS, COLS, '*');
	printboard(show, ROW, COL);
	setmine(mine, ROW, COL);
	finemine(mine, show, ROW, COL);
}

4、初始化数组

🤗我们要把数组一全部置为‘ 0 ’,数组二全部置为‘ * ’。

1、那如果我们要把第一个数组置为‘ 0 ’,我们知道肯定要遍历二维数组然后把每一个元素置为‘ 0 ’,那我是不是得再写一个函数把数组二再遍历一下全部元素置为‘ * ’,
这麻烦不麻烦❓当然麻烦,我们可以直接把0或者‘ * ’直接当作一个参数传到函数就行啦!

void initboard(char board[ROWS][COLS], int rows, int cols, char ret)
{
	for (int i = 0; i < rows; i++)
	{
		int j = 0;
		for ( j = 0; j < cols; j++)
		{
			board[i][j] = ret;
		}
	}
}

但是这里我们得先理解一个点,就是假如我们是99的棋盘,那我们要是排查到边的话,它周围就会越界,那我们就变成1111的棋盘,但是我们只用9*9的格子就行
在这里插入图片描述

5、打印棋盘

🤗考虑到之后我们要排查某个位置的雷时需要玩家输入下标,此时如果有行的标号,有列的下标,看着就会更直观。
在这里插入图片描述

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

6、设置雷

🤗我们要设置几个雷,就循环几次,循环的内容就是:随机生成坐标,看这个坐标的位置是不是‘ 0 ’,如果是0,就把这个坐标置为1。
🐹随机生成下标就要用rand函数,如果我们要生成0-9的下标,就是rand%ROW+1(这里ROW是9
🤨rand函数可以随机生成一个数字,范围是0-32767,大家可以试一下,如果直接这样写,每次返回值都是一样的,因此我们要使用rand之前使用srand函数函数原型:
void srand (unsigned int seed);这里的参数是unsigned int seed,我们经常使用time来做参数,只要每次播种的时间不同,生成的参数就不同,得到的随机数就不同
srand就是这样的srand((unsigned int)time(NULL));它在函数中写一次就行,因此我们可以把它放在main函数中(函数参考百度);

void setmine(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = easy_count;//这里的easy_count是10,就是生成是个雷
	x = rand() % row + 1;
	y = rand() % col + 1;
	for (int i = 0; i < count; i++)//循环生成雷
	{
		x = rand() % row + 1;//随机生成下标
		y = rand() % col + 1;
		if (board[x][y] == '0')//如果是0,就置为1
		{
			board[x][y] = '1';
		}
	}	
}

7、排查雷

🐻mine数组是布置雷的数组,show数组是你输入下标展示的排查雷的数组,当玩家输入要排查的下标时,正常情况下就在mine数组的周围找找有几个雷,有几个雷,就把这个数字放到show数组中这个下标的位置上,那怎么统计这个位置的周围有几个雷呢❓❓❓下面分析;如果这个玩家输入的下标对应mine数组的位置发现刚好是‘ 1 ’,那就是被炸死了,炸死了,我就把mine数组打印出来,让他看看雷。
🤨还有一个问题就是,那什么时候赢呢?我把所有不是雷的位置都排查完就赢了,那不是雷的位置是9*9-10=81个,因此设置一个循环,循环81次,用win计数每次成功排查一个下标,win就加一;如果我已经排查过的下标,你又输入了,就提示你“该坐标被排查过”,介绍本次,循环,进入下一次循环。
😁退出循环就意味着,赢了!

void finemine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	printf("请输入要排除的下标");
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<row*col-easy_count)
	{
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y]!='*')
			{
				printf("该坐标被排查过了");
				continue;
			}
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				printboard(mine, row, col);
			}
			else
			{
				//OpenShow(mine, show, x, y);
				int ret = mine_count(mine,x,y);
				show[x][y] = ret + '0';
				printboard(show, row, col);
				win++;
			}
		}
		else
		{
			printf("坐标非法请重新输入");
		}
	}
	if (win == row * col - easy_count)
	{
		printf("恭喜你,你赢了");
		printboard(mine, ROW, COL);
	}
}

8、坐标周围雷的个数

🤨我们设置雷的时候把雷设置的字符1,把不是雷的设置的字符0,字符零的ASC码值是48,那当然字符1-字符0=1,因此统计的时候让周围每个位置的都减去字符0,就是要减去8个字符零。
在这里插入图片描述

int mine_count(char mine[ROWS][COLS], int x, int y)
{
	return (mine[x][y - 1] + mine[x][y + 1] + mine[x - 1][y] + mine[x + 1][y]
		+ mine[x - 1][y - 1] + mine[x - 1][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0');
}

9、递归展开周围的区域

🤨我们上面最终页面是展开了一大片,但是现在我们是查找一个坐标就只展开了一个位置,因此我们要递归的展开周围区域,有三个条件
1、这个位置不是雷
2、它的周围没有雷
3、该坐标没有被排查过

void OpenShow(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)//展开周围的区域
{
	if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1) {
		return;
	}
	if (show[x][y] != '*') {
		return;
	}
	int n = mine_count(mine, x, y);
	show[x][y] = n + '0';
	if (n > 0) {
		show[x][y] = n + '0';
		return;
	}
	if (n == 0) {
		OpenShow(mine, show, x - 1, y);
		OpenShow(mine, show, x - 1, y - 1);
		OpenShow(mine, show, x, y - 1);
		OpenShow(mine, show, x + 1, y - 1);
		OpenShow(mine, show, x + 1, y);
		OpenShow(mine, show, x + 1, y + 1);
		OpenShow(mine, show, x, y + 1);
		OpenShow(mine, show, x - 1, y + 1);
	}
}

因此我们要修改上面查找雷的代码

else
			{
				OpenShow(mine, show, x, y);
				int ret = mine_count(mine,x,y);
				show[x][y] = ret + '0';
				printboard(show, row, col);
				win++;
			}

总结

😁😁😁好啦,今天的分享到此结束,看到这里大家应该都明白了吧,不明白没关系,直接私信小月,记得要,点赞、收藏加关注哦👍🤞🤞小月后面还会分享更多哦!!!

  • 41
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 68
    评论
评论 68
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

出小月(充电停更版)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值