【C语言】童年的扫雷游戏(递归展开)你也可以做出来,将他发给你的网瘾室友玩吧 ——含详细注释及解析

目录

一、预览

1.测试文件(text.c)

2.函数声明(game.h)

3.函数实现(game,c)

二、思路分析

1.打印菜单以及初始化棋盘

2.布置雷

* 3.排查雷(递归展开)

三、导出为 .exe

1. 将Debug转换成Release

2. 重新生成解决方案

3. 找到.exe

 Summery💐



扫雷也是对C语言学习前期学习的一个很好的总结,其中包含了二维数组,循环,函数以及递归等等C语言知识点,完成这个小游戏,锻炼你的代码思维吧🤔                                                                                                                     

                                                                                                    ”

一、预览

1.测试文件(text.c)

#include"game.h"

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

void game()
{
	char mineBoard[ROWS][COLS] = { '\0' };    //一个用于内置雷
	char showBoard[ROWS][COLS] = { '\0' };    //一个用于玩家排雷,并打印

	InitBoard(mineBoard, ROWS, COLS,'0');   //初始化两个棋盘
	InitBoard(showBoard, ROWS, COLS,'*');

	SetBoard(mineBoard, ROW, COL);     //布置雷
	DisplayBoard(showBoard, ROW, COL);    //打印棋盘
	FindMine(mineBoard, showBoard, ROW, COL);    //排雷
}

void text()
{
	srand((unsigned int)time(NULL));   //设置时间戳

	int input = 0;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("共有%d个雷\n",MODE_EAZY);
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,重新输入\n");
			break;
		}
	} while (input);
}

int main()
{
	system("color 0A");   //改变字体颜色

	text();
	return 0;
}

2.函数声明(game.h)

#include<stdio.h>
#include<stdlib.h>    //改变字体颜色
#include<time.h>    //生成随机数中time函数所用

#define ROW 9
#define COL 9

#define ROWS ROW+2     //防止越界
#define COLS COL+2


#define MODE_EAZY 10

void InitBoard(char Board[ROWS][COLS], int rows, int cols, int set);   //初始化

void DisplayBoard(char Board[ROWS][COLS], int row, int col);   //打印棋盘

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

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

3.函数实现(game,c)

#include"game.h"

void InitBoard(char Board[ROWS][COLS], int rows, int cols, int set)  //初始化棋盘
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			Board[i][j] = set;
		}
	}
}

void DisplayBoard(char Board[ROWS][COLS], int row, int col)
{
	printf("* * * * * * *排雷* * * * * * *\n\n");

	for (int j = 0; j <= col; j++)          //打印列数
	{
		printf("%d ", j);
	}
	printf("\n");

	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);                   //打印行数

		for (int j = 1; j <= col; j++) 
		{
			printf("%c ", Board[i][j]);     //打印棋盘
		}
		printf("\n");
	}

	printf("\n* * * * * * *排雷* * * * * * *\n");
}

void SetBoard(char Board[ROWS][COLS], int row, int col)
{
	int count = MODE_EAZY;        //布置10颗雷
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (Board[x][y] != '1')    //该位置已有雷,循环再随机生成一个坐标
		{
			Board[x][y] = '1';
			count--;
		}
	}
}

int Count(char mine[ROWS][COLS], int x, int y)   //计算(x,y)坐标周围的雷的数量
{
	return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] +
		mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] +
		mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0');   //将字符转换为整型
}

void FindMine_plus(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y,int*win)
{
	if (mine[x][y] == '0')   //若该坐标不是雷,则对计数win-1
		*win-=1;

	char sum = Count(mine, x, y) + '0';    //+'0' 将整型数字转换成字符型的数字
	show[x][y] = sum; 

	if (show[x][y] == '0')
	{
		show[x][y] = ' ';      //如果周围没有雷,则该坐标变为空格,并对其周围的坐标递归
	}
	
if (show[x][y] == ' ')   //递归条件:没有越界且递归过去的坐标没有被排过雷
	{
		if (x - 1 >= 1 && x - 1 <= 9 && y - 1 >= 1 && y - 1 <= 9 && show[x - 1][y - 1] == '*')
			FindMine_plus(mine, show, x - 1, y - 1, win);

		if (x - 1 >= 1 && x - 1 <= 9 && y >= 1 && y <= 9 && show[x - 1][y] == '*')
			FindMine_plus(mine, show, x - 1, y, win);

		if (x - 1 >= 1 && x - 1 <= 9 && y + 1 >= 1 && y + 1 <= 9 && show[x - 1][y + 1] == '*' )
			FindMine_plus(mine, show, x - 1, y + 1, win);

		if (x >= 1 && x <= 9 && y - 1 >= 1 && y - 1 <= 9 && show[x][y - 1] == '*' )
			FindMine_plus(mine, show, x, y - 1, win);

		if (x >= 1 && x <= 9 && y + 1 >= 1 && y + 1 <= 9 && show[x][y + 1] == '*')
			FindMine_plus(mine, show, x, y + 1, win);

		if (x + 1 >= 1 && x + 1 <= 9 && y - 1 >= 1 && y - 1 <= 9 && show[x + 1][y - 1] == '*')
			FindMine_plus(mine, show, x + 1, y - 1, win);

		if (x + 1 >= 1 && x + 1 <= 9 && y >= 1 && y <= 9 && show[x + 1][y] == '*')
			FindMine_plus(mine, show, x + 1, y, win);

		if (x + 1 >= 1 && x + 1 <= 9 && y + 1 >= 1 && y + 1 <= 9 && show[x + 1][y + 1] == '*')
			FindMine_plus(mine, show, x + 1, y + 1, win);
	}

}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = row * col - MODE_EAZY;     //win为非雷的数量

	while (win)
	{
		printf("请依次输入行、列坐标排查雷:\n");   
		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;
			}

			if (show[x][y] != '*')    //第二种,该坐标以排过
			{
				printf("该坐标已被排查\n");
				continue;
			}

			FindMine_plus(mine,show,x,y,&win);    //第三种则是该坐标不是雷,并对其周围展开
			DisplayBoard(show, row, col);
		}

		else
		{
			printf("坐标非法,重新输入\n");
		}
	}

	if (win == 0)    //win等于0表示剩下的坐标全为雷
	{
		printf("排雷成功!\n");
		DisplayBoard(mine, row, col);
	}
}

二、思路分析

这儿我把我自己分析的草稿分享给大家,希望对大家理解有帮助⬇️

1.打印菜单以及初始化棋盘

① 首先打印菜单,定义变量input,输入1表示进入游戏,输入0表示退出,输入其他则重新输入

② 用do-while循环,第一次不用判断直接进入循环,再用switch分支语句,根据input的值判断是开始游戏还是跳出循环,结束游戏

③ 我们需要初始化两个棋盘:

一个用于布置雷 —— 用 ‘ 1 ’ 表示雷,用 ‘ 0 ’ 表示非雷,便于之后坐标周围雷的计数统计(不用打印出来)

一个用于排查雷 —— 用 ‘ * ’ 表示暂未排查的坐标,用字符型的数字表示排查之后周围雷的个数;

2.布置雷

生成随机数 模(%)9 及得到 0 - 8 的数,再 +1 则课得到 1-9 的数作为坐标;

定义变量,值为雷的个数,每设置一个雷对其减一,注意坐标已有雷得情况

* 3.排查雷(递归展开)

要想获得文章开头排雷得效果,就得写出递归得代码

 注意点:

  当一个坐标周围没有雷时,选择递归周围的坐标,每次递归过去也相当于排查该点的雷,所以要对之前定义的变量win减一   ※需要传地址过去!!!

  递归过去之后同样对周围的坐标统计雷的数量,如果还是没有雷继续递归周围坐标,这时需要特别注意的是:递归死循环导致栈溢出⬇️

 为了避免上图情况,需要对递归加上判断条件  -->  show[x - 1][y - 1] == ' * '  ,意思为递归的这个坐标之前没有排查过✔️

 ③ 递归还需要特别注意的一点:不能递归 9 × 9 棋盘之外的坐标(因为之前为了边缘坐标统计周围雷数,将两个二维数组的长宽均加了2)

所以加上判断条件   x - 1 >= 1 && x - 1 <= 9 && y - 1 >= 1 && y - 1 <= 9  (以一条递归为例)

三、导出为 .exe

1. 将Debug转换成Release

2. 重新生成解决方案

生成 -> 重新生成解决方案

3. 找到.exe

 将他复制粘贴给你的室友和老师吧!⬇️

 Summery💐

扫雷可以写成没有递归的形式,但是没有展开的那种效果,扫雷的效率也就自然低了,这个扫雷游戏的难点就在于这个递归的实现,需要我们对各种情况的全面考虑!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dusong_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值