几段代码,让你用递归解决C语言扩展排雷(扫雷)

Posted 祝耕夫丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了几段代码,让你用递归解决C语言扩展排雷(扫雷)相关的知识,希望对你有一定的参考价值。


前言

几段话,让你用递归解决C语言扩展排雷,熟悉我的人都知道,我是一个善于将过程写的很详细的精通人性的男“讲师”。

今天给大家整个递归扩展排雷!


一、递归是什么?

程序调用自身的编程技巧称为递归。递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式就在于把大事化小(自己调用自己)

要编写一个函数要确定递归的两个条件

1. 递归结束的条件
2. 递归的调用的公式

二、如何使用递归将周围无雷的棋子排除?

1.递归和扫雷的关系

递归在扫雷中可以解决扩展排雷的问题,当用户排除掉一个棋子,该棋子周围没有雷,则展开,再从该九宫格依次排查,周围是否有雷,无雷则继续展开,有雷则输出周围有几颗雷。我们不必去考虑递归到底执行了几次,最主要的目的就是将问题简化。
当周围有雷,该坐标排查结束,继续排查其他坐标,递归的终止条件即为当排查坐标不为字符’0’(这里我定义为0,代表坐标不是雷)或该坐标被排查过(为*字符)则递归终止。

那么当排查坐标为字符’0’且该坐标未被排查过,递归继续执行。

if (mine[i][j] == '0' && showboard[i][j] == '*')
{
	extendmine(mine, showboard, i, j);//递归函数
}

如果该条件成立,则执行递归。

这里函数中的i和j来不断递归等价于x和y。并求出该坐标周围九宫格范围内的雷数。

我们可以将这个递归函数的实现分为两个步骤:
1. 求出这个坐标周围的雷数,如果为0,则将其变为空白。
2. 排查在该坐标九宫格范围内的其他坐标。(这里我用了循环,也可以使用很多个if语句来实现)

2.代码实现

代码如下(示例):

void extendmine(char mine[ROWS][COLS], char showboard[ROWS][COLS], int x, int y)
{
	int n = 0;
	n = howmanymine(mine, x, y);
	if (n == 0)
	{
		showboard[x][y] = ' ';//如果周围没有雷,将中心赋值为空格
		int i = 0;
		int j = 0;
		for (i = x - 1; i <= x + 1 && i >= 0 && i <= ROW; i++)
		{
			for (j = y - 1; j <= y + 1 && j >= 0 && j <= COL; j++)
			{
				if (i == x && j == y)//跳出(x,y)的位置
				{
					continue;
				}
				if (mine[i][j] == '0' && showboard[i][j] == '*')//坐标自身不是雷且还是初始化字符,进入递归再次扩展排雷
				{
					extendmine(mine, showboard, i, j);//递归函数
				}
			}
		}
	}
	else
		showboard[x][y] = n + '0';//如果附近有雷,展示雷的个数
}

那么扫雷游戏中较难的部分——如何使用递归扩展排雷就可以解决了。
实现效果如下


附录

主程序.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
	printf("********************************\\n");
	printf("*************1.paly*************\\n");
	printf("*************2.exit*************\\n");
	printf("********************************\\n");
}
void game()
{
	char mine[ROWS][COLS] = { 0 };//布置雷的信息
	char showboard[ROWS][COLS] = { 0 };//排查出雷的信息
	init(mine, ROWS, COLS, '0');//初始化函数
	init(showboard, ROWS, COLS, '*');
	setmine(mine, ROW, COL);
	display(mine, ROW, COL);
	display(showboard, ROW, COL);
	playgame(mine,showboard,ROW, COL);
}
int main()
{
	int input = 0;
	srand((unsigned)time(NULL));
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 2:
			printf("退出游戏\\n");
			break;
		default:
			printf("输入错误,请重新输入\\n");
		}
	} while (input!=2);
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//初始化棋盘
void init(char showboard[ROWS][COLS], int rows, int cols,char c)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			showboard[i][j] = c;
		}
	}
}

//放置地雷

void setmine(char mine[ROWS][COLS], int row, int col)
{
	int x, y = 0;
	int count = easy_game;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}
//打印棋盘
void display(char showboard[ROWS][COLS], int row, int col)
{
	int i = 0;
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ",showboard[i][j]);
		}
		printf("\\n");
	}
	printf("\\n");
}


//求出该坐标周围有多少雷
int howmanymine(char mine[ROWS][COLS], int x, int y)
{
	int i, j = 0;
	int count = 0;
	for (i = x - 1; i <= x + 1; i++)//x-1<=i<=x+1
	{
		for (j = y - 1; j <= y + 1; j++)//y-1<=i<=y+1
		{
			count += mine[i][j];
		}
	}
	count = count - mine[x][y] - 8 * '0';//转换为字符数字
	return count;
}

//空白扩展
void extendmine(char mine[ROWS][COLS], char showboard[ROWS][COLS], int x, int y)
{
	int n = 0;
	n = howmanymine(mine, x, y);
	if (n == 0)
	{
		showboard[x][y] = ' ';//如果周围没有雷,将中心赋值为空格
		int i = 0;
		int j = 0;
		for (i = x - 1; i <= x + 1 && i >= 0 && i <= ROW; i++)
		{
			for (j = y - 1; j <= y + 1 && j >= 0 && j <= COL; j++)
			{
				if (i == x && j == y)//跳出(x,y)的位置
				{
					continue;
				}
				if (mine[i][j] == '0' && showboard[i][j] == '*')//坐标自身不是雷且还是初始化字符,进入递归再次扩展排雷
				{
					extendmine(mine, showboard, i, j);//递归函数
				}
			}
		}
	}
	else
		showboard[x][y] = n + '0';//如果附近有雷,展示雷的个数
}
//判断是否获胜
int is_win(char showboard[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (showboard[i][j] == '*')
			{
				count++;
			}
		}
	}
	return count;
}

//主体程序
void playgame(char mine[ROWS][COLS], char showboard[ROWS][COLS], int row, int col)
{
	int x, y = 0;
	int n = 0;//判断循环是否继续
	while (1)
	{
		printf("请输入你要排雷的坐标");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束!\\n");
				display(mine, row, col);
				break;
			}
			else
			{
				int count = howmanymine(mine, x, y);
				showboard[x][y] = count + '0';
				extendmine(mine, showboard, x, y);
				display(showboard, row, col);
				n = is_win(showboard, row, col);
				if (n == easy_game)
				{
					printf("恭喜你排雷成功!");
					display(mine, row, col);
					break;
				}
			}
		}
		else
		{
			printf("输入错误,请重新输入");
		}
	}
}
game.h
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS ROW+2
#define easy_game 9
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
void init(char mine[ROWS][COLS], int rows, int cols,char c);
void setmine(char mine[ROWS][COLS], int row, int col);
void display(char showboard[ROWS][COLS], int row, int col);
void playgame(char mine[ROWS][COLS],char showboard[ROWS][COLS],int row, int col);

以上是关于几段代码,让你用递归解决C语言扩展排雷(扫雷)的主要内容,如果未能解决你的问题,请参考以下文章

C语言小游戏:扫雷实现

C语言实现扫雷(初阶)

如何用C语言快速实现初级版扫雷(步骤详细)

用C语言实现扫雷小游戏(附上思路+项目展示+源代码)

C语言小游戏之扫雷完整版

C语言扫雷的实现