C语言实现递归版扫雷游戏实例

 更新时间:2022年01月25日 10:09:46   作者:绅士·永  
大家好,本篇文章主要讲的是C语言实现递归版扫雷游戏实例,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下

思路

清晰的逻辑

为方便将其分为三个文件:text.c(测试) game.c(函数实现) game.h(头文件声明)

在排雷的时候为了方便,我们需要将每一行每一列对应的行数,列数打印出来。

#define LEI 10
#define ROW 10
#define LOW 10
 
#define ROWS ROW+2
#define LOWS LOW+2
//在定义棋盘的长宽时,特意加上2,便于标记行数列数。

菜单

打印的菜单只需要有开始游戏、退出游戏的选项即可

void menu()
{
	printf("*************************************\n");
	printf("************1.开始游戏***************\n");
	printf("************0.退出游戏***************\n");
	printf("*************************************\n");
 
}

棋盘

1.雷盘

2.棋盘

扫雷需要先记录雷的信息再进行排雷,如果使用一个棋盘太过于复杂,所以我们使用两个棋盘,一个用于布置雷,一个用于玩家排雷。

两个棋盘初始化

布置雷的棋盘初始化,将字符‘0’作为非雷,字符‘1’作为雷。

玩家盘将字符‘*’作为还没有扫的地方

    board(arr1, ROWS, LOWS, '0');//雷盘
	board(arr2, ROWS, LOWS, '*');//玩家盘

因为两个的初始化方式不同,所以我们采用传参ret初始化

//初始化棋盘
void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < lows; j++)
		{
			arr1[i][j] = ret;
		}
	}

布置雷

布置的雷放置需要随机,所以采用两个随机数来定位坐标。

 
//布置雷
void Get_lei(char arr1[ROWS][LOWS], int row, int low)
{
	int count = LEI;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % low + 1;
		if (arr1[x][y] == '0')
		{
			arr1[x][y] = '1';
			count--;
		}
	}
	//displayboard(arr1, ROW, LOW);//用于测试
}

排雷

当我们输入一个坐标时,我们需要知道这个坐标周围雷的个数,定义一个Get_num函数来获取雷个数。但此时只能获取一个坐标的信息,我们知道一般的扫雷,如果当前坐标雷的个数为0,就会展开,这个过程较为复杂,所以我们使用递归来实现

//玩家盘
static int Get_num(char arr1[ROWS][LOWS],int x, int y)//获得当前坐标周围雷的个数
{
	int count = 0;
	int i = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		int j = 0;
		for (j = y - 1; j <= y + 1; j++)
		{
			if (arr1[i][j] == '1')
			{
				count++;
			}
		}
 
	}
	return count;
}
//判断是否展开,实现函数
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
	{
		int ret = Get_num(arr1, x, y);
		if (ret != 0)
			arr2[x][y] = ret + '0';//记录雷的个数
		//递归散开
		else if (arr1[x][y] != ' ')
		{
			arr2[x][y] = '0';
			arr1[x][y] = ' ';
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					Judge(arr2, arr1, i, j);
				}
			}
		}
		else
		{
			return;
		}
	}
}

判断输赢

输:即每排一次雷,检查一下雷盘对应的信息,如果是雷,就被炸死,如果不是,就继续排雷。

赢:当玩家将所有的非雷的区域都排查出来时,判断为赢。(这里采用一个计数器,没排一次雷计数器就++一下,当计数器与总的非雷的区域数目相同时,判断为赢)

void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入坐标:>");
		scanf("%d,%d", &x, &y);
		if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
		{
			if (arr1[x][y] == '1')
			{
				arr2[x][y] = '#';
				displayboard(arr2, ROW, LOW);//排雷
				printf("遗憾你输了\n");
				break;
			}
			else
			{
				Judge(arr2, arr1, x, y);
				displayboard(arr2, ROW, LOW);//排雷
			}
		}
		else
		{
			printf("输入错误!\n");
		}
 
		//判断扫雷是否赢
		int i = 0, flag = 0;
		for (i = 1; i <= ROW; i++)
		{
			int j = 0;
			for (j = 1; j <= LOW; j++)
			{
				if (arr2[i][j] != '*')
				{
					flag++;
				}
			}
		}
		if (flag == ROW*LOW - LEI)
		{
			printf("你赢了!\n");
			break;
		}
	}
}

text.c实现

#define  _CRT_SECURE_NO_WARNINGS 1
 
#include "game.h"
//菜单
void menu()
{
	printf("*************************************\n");
	printf("************1.开始游戏***************\n");
	printf("************0.退出游戏***************\n");
	printf("*************************************\n");
 
}
 
 
void game()
{
	//初始化棋盘
	char arr1[ROWS][LOWS] = { 0 };//雷盘
	char arr2[ROWS][LOWS] = { 0 };//玩家盘
	board(arr1, ROWS, LOWS, '0');
	board(arr2, ROWS, LOWS, '*');
	//打印棋盘
	//displayboard(arr1, ROW, LOW);//布置雷
	displayboard(arr2, ROW, LOW);//排雷
	//布置雷
	Get_lei(arr1,ROW,LOW);
	//排雷
	Out_lei(arr2,ROW,LOW, arr1);
 
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d",&input);
		switch (input)
		{
		case 1:
		{
			printf("扫雷\n");
			game();
			break;
		}
		case 0:
		{
			printf("退出游戏\n");
			break;
		}
		default:
		{
			printf("选择错误\n");
			break;
		}
		}
	} while (input);
 
	return 0;
}

game.c实现

#define  _CRT_SECURE_NO_WARNINGS 1
 
#include "game.h"
 
//初始化棋盘
void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < lows; j++)
		{
			arr1[i][j] = ret;
		}
	}
}
 
//打印棋盘
void displayboard(char arr1[ROWS][LOWS], int row, int low)
{
	printf("<———扫雷游戏———>\n");
	int i = 0;
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		if (i == 1)
		{
			for (j = 0; j <= low; j++)
			{
				printf("%2d ", j);
			}
			printf("\n");
		}
 
		for (j = 1; j <= low; j++)
		{
			if (j == 1)
			{
				printf("%2d ", i);
			}
			
			printf("%2c ", arr1[i][j]);
		}
		printf("\n");
	}
	printf("<———扫雷游戏———>\n");
 
}
 
//布置雷
void Get_lei(char arr1[ROWS][LOWS], int row, int low)
{
	int count = LEI;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % low + 1;
		if (arr1[x][y] == '0')
		{
			arr1[x][y] = '1';
			count--;
		}
	}
	//displayboard(arr1, ROW, LOW);
}
//玩家盘
static int Get_num(char arr1[ROWS][LOWS],int x, int y)
{
	int count = 0;
	int i = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		int j = 0;
		for (j = y - 1; j <= y + 1; j++)
		{
			if (arr1[i][j] == '1')
			{
				count++;
			}
		}
 
	}
	return count;
}
//判断是否展开,实现函数
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
	{
		int ret = Get_num(arr1, x, y);
		if (ret != 0)
			arr2[x][y] = ret + '0';
		//递归散开
		else if (arr1[x][y] != ' ')
		{
			arr2[x][y] = '0';
			arr1[x][y] = ' ';
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					Judge(arr2, arr1, i, j);
				}
			}
		}
		else
		{
			return;
		}
	}
}
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入坐标:>");
		scanf("%d,%d", &x, &y);
		if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
		{
			if (arr1[x][y] == '1')
			{
				arr2[x][y] = '#';
				displayboard(arr2, ROW, LOW);//排雷
				printf("遗憾你输了\n");
				break;
			}
			else
			{
				Judge(arr2, arr1, x, y);
				displayboard(arr2, ROW, LOW);//排雷
			}
		}
		else
		{
			printf("输入错误!\n");
		}
 
		//判断扫雷是否赢
		int i = 0, flag = 0;
		for (i = 1; i <= ROW; i++)
		{
			int j = 0;
			for (j = 1; j <= LOW; j++)
			{
				if (arr2[i][j] != '*')
				{
					flag++;
				}
			}
		}
		if (flag == ROW*LOW - LEI)
		{
			printf("你赢了!\n");
			break;
		}
	}
}
 
 

game.h实现

#pragma once
 
#include <stdio.h>
#include <stdlib.h>
 
#define LEI 10
#define ROW 10
#define LOW 10
 
#define ROWS ROW+2
#define LOWS LOW+2
 
//初始化棋盘
void board(char arr1[ROWS][LOWS],int rows,int lows,char ret);
 
//打印棋盘
void displayboard(char arr1[ROWS][LOWS], int row, int low);
 
//布置雷
void Get_lei(char arr1[ROWS][LOWS], int row, int low);
//玩家盘
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS]);

递归部分详解

递归条件:1.有停止的条件。2.每一次递归都会向这个条件靠拢。

那么这里的停止条件是什么呢?

递归:当返回雷的个数为0时,就符合继续递归的条件,我们需要将当前坐标周围的点全部排除。且需要将已经排查了的坐标做一个标记,否则就会不停的排查下去,就会形成死递归。所以

停止条件:当前这个坐标是已被排查过的,就停止递归。

因为每一次排查都会的一个标记,所以这就是那个不断向停止条件靠拢的过程。

//判断是否展开,实现函数
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
	if (x > 0 && x <= ROW && y > 0 && y <= LOW)
	{
		int ret = Get_num(arr1, x, y);
		if (ret != 0)
			arr2[x][y] = ret + '0';
		//递归散开
		else if (arr1[x][y] != ' ')
		{
			arr2[x][y] = '0';//玩家盘
			arr1[x][y] = ' ';//雷盘
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					Judge(arr2, arr1, i, j);
				}
			}
		}
		else
		{
			return;
		}
	}
}

总结

到此这篇关于C语言实现递归版扫雷游戏实例的文章就介绍到这了,更多相关C语言递归版扫雷内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++入门教程之引用与指针

    C++入门教程之引用与指针

    初学C++时,很容易把指针和引用的用法混在一起,下面这篇文章主要给大家介绍了关于C++入门教程之引用与指针的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • C++函数重载介绍与原理详解

    C++函数重载介绍与原理详解

    这篇文章主要为大家介绍了C++函数重载介绍与原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • C++初阶之list的模拟实现过程详解

    C++初阶之list的模拟实现过程详解

    在C++中我们经常使用STL,那个在那些我们常用的数据结构vector,list的背后,又是如何实现的呢?这篇文章主要给大家介绍了关于C++初阶之list的模拟实现的相关资料,需要的朋友可以参考下
    2021-08-08
  • C++实现单词管理系统

    C++实现单词管理系统

    这篇文章主要为大家详细介绍了C++实现单词管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 利用C语言实现猜数字小游戏

    利用C语言实现猜数字小游戏

    这篇文章主要为大家详细介绍了利用C语言实现猜数字小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • C++关于类结构体大小和构造顺序,析构顺序的测试详解

    C++关于类结构体大小和构造顺序,析构顺序的测试详解

    这篇文章主要介绍了C++类结构体大小和构造顺序,析构顺序的测试,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • C语言直接选择排序算法详解

    C语言直接选择排序算法详解

    直接选择排序就是遍历整个数组,每遍历一遍的目的是找出该数组中的最大数和最小数对应的下标,然后将最小数和数组的第一个数进行交换,最大数和数组的最后一个数进行交换,然后缩小范围再次遍历
    2022-08-08
  • c语言循环加数组实现汉诺塔问题

    c语言循环加数组实现汉诺塔问题

    本文主要介绍了c语言循环加数组实现汉诺塔问题,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C++实例讲解四种类型转换的使用

    C++实例讲解四种类型转换的使用

    在C++语言中新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast。这四个关键字都是用于类型转换的,类型转换(type cast),是高级语言的一个基本语法。它被实现为一个特殊的运算符,以小括号内加上类型名来表示,接下来让我们一起来详细了解
    2022-06-06
  • C++实现字符串和整数的相互转换

    C++实现字符串和整数的相互转换

    这篇文章主要为大家详细介绍了C++实现字符串和整数的相互转换的方法,文中的示例代码讲解详细,对我们学习C++有一定的帮助,需要的可以参考一下
    2023-01-01

最新评论