C语言——扫雷小游戏(递归展开版)

news2024/11/15 13:29:06

哈喽,大家好,上次我们已经学习了三子棋小游戏,今天我们来学习扫雷小游戏了。

目录

1.游戏介绍

2.函数部分

2.1菜单

2.2game()函数

2.3mian()函数

2.4初始化棋盘

2.5打印棋盘

2.6布置雷

2.7排查雷

2.8统计雷

2.9递归,展开一片区域

3.完整代码展示 


1.游戏介绍

想必大家都玩过扫雷这款小游戏吧?

在一个棋盘上随机摆放数个雷,这些雷用户无法看见,只能一个个将雷排查出来,用户点击一个格子,如果这个格子含有雷,游戏就以失败告终,如果这个格子不是雷,就会在这个格子上显示周围8个格子共有多少个雷,如下图:

 今天我们就用C语言来实现这个扫雷小游戏

2.函数部分

下面是游戏要用到的函数:

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void DisPlayBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//统计雷
int GetMineCount(char mine[ROWS][COLS], int x, int y);
//递归,展开一片区域
void DfsMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col);

2.1菜单

菜单非常简洁,用户输入1表示开始游戏,输入0则退出小游戏

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

2.2game()函数

game()函数包含一个游戏的执行过程,将一些函数组合了起来,形成游戏的完整过程。在这儿我们定义了两个数组,mine数组表示存放的雷,show数组表示存放排查出雷的信息。

void game()
{
	char mine[ROWS][COLS];//存放的雷
	char show[ROWS][COLS];//存放盘查出雷的信息
	//初始化棋盘
	//mine数组最开始全是‘0’
	//show数组最开始全是‘*’
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	DisPlayBoard(show, ROW, COL);
	
	//布置雷
	SetMine(mine, ROW, COL);
	//排查雷
	FindMine(mine, show, ROW, COL);
}

2.3mian()函数

main函数是整个程序中必不可少的一个部分。

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			system("cls");
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
}

2.4初始化棋盘

初始化棋盘将两个数组初始化。mine数组全部初始化为‘0’,表示最开始还没有存放雷。show数组最开始初始化为‘*’。

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

2.5打印棋盘

打印棋盘这个步骤很简单,但为了方便玩家,我们顺便把棋盘的行号和列号也打印出来。如下图:

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

2.6布置雷

布置雷就是让电脑随机生成10个不重复的坐标,这些坐标就是雷的位置

void SetMine(char board[ROWS][COLS], int row, int col)
{
	//布置十个雷
	//随机生成坐标
	int count = ESAY_COUNT;
	while(count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

2.7排查雷

用户输入要排查的雷的坐标,如果该坐标是雷,就输出"很遗憾,你被炸死了“,否则统计这个位置周围的八个位置雷的数量,存到show数组对应坐标位置里。同时这里扩展了一个递归展开,可以展开一片非雷区域。

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;
	int win = 0;
	while (win < row * col - ESAY_COUNT)
	{
		system("cls");
		DisPlayBoard(show, ROW, COL);
		printf("请输入要排查雷的坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				break;
			}
			else
			{
				//该位置不是雷,就统计这个坐标周围有几个雷
				int count = GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				if (count == 0)
				{
					//递归,展开一片区域
					DfsMine(mine, show, x, y, ROW, COL);
				}
				show[x][y] = count + '0';
				DisPlayBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
	if (win == row * col - ESAY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
	}
	DisPlayBoard(mine, ROW, COL);
}

2.8统计雷

这个函数只要返回坐标(x,y)周围雷的数量即可。

int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return (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] + mine[x - 1][y] - 8 * '0');
}

2.9递归,展开一片区域

这块可以说是一个扩展的内容了,当我们点到一个周围没有地雷的格子,这些区域就会自动展开。

 这里需要用到函数递归来实现,可以将其看作是一个深度优先搜索

void DfsMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col)
{
	int count= GetMineCount(mine, x, y);
	show[x][y] = count + '0';
	if (count != 0)
	{
		return;
	}
	int xx[] = { 1,1, 1 ,-1,-1,-1,0, 0 };
	int yy[] = { 1,0,-1, 0, 1, -1 ,1,-1};
	int i = 0;
	for (i = 0; i < 8; i++)
	{
		int dx = x + xx[i];
		int dy = y + yy[i];
		if (dx >= 1 && dx <= row && dy >= 1 && dy <= col && mine[dx][dy]=='0' && show[dx][dy] == '*')
		{
			DfsMine(mine, show, dx, dy, ROW, COL);
		}
	}
}

3.完整代码展示 

game.h文件

#pragma once

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


#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define ESAY_COUNT 10 //布置雷的个数

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void DisPlayBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//统计雷
int GetMineCount(char mine[ROWS][COLS], int x, int y);
//递归,展开一片区域
void DfsMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col);

game.c文件

#include"game.h"

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

//打印棋盘
void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("--------扫雷--------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}


//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
	//布置十个雷
	//随机生成坐标
	int count = ESAY_COUNT;
	while(count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;
	int win = 0;
	while (win < row * col - ESAY_COUNT)
	{
		system("cls");
		DisPlayBoard(show, ROW, COL);
		printf("请输入要排查雷的坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				break;
			}
			else
			{
				//该位置不是雷,就统计这个坐标周围有几个雷
				int count = GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				if (count == 0)
				{
					//递归,展开一片区域
					DfsMine(mine, show, x, y, ROW, COL);
				}
				show[x][y] = count + '0';
				DisPlayBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
	if (win == row * col - ESAY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
	}
	DisPlayBoard(mine, ROW, COL);
}

//递归,展开一片区域
void DfsMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col)
{
	int count= GetMineCount(mine, x, y);
	show[x][y] = count + '0';
	if (count != 0)
	{
		return;
	}
	int xx[] = { 1,1, 1 ,-1,-1,-1,0, 0 };
	int yy[] = { 1,0,-1, 0, 1, -1 ,1,-1};
	int i = 0;
	for (i = 0; i < 8; i++)
	{
		int dx = x + xx[i];
		int dy = y + yy[i];
		if (dx >= 1 && dx <= row && dy >= 1 && dy <= col && mine[dx][dy]=='0' && show[dx][dy] == '*')
		{
			DfsMine(mine, show, dx, dy, ROW, COL);
		}
	}
}

//统计雷
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return (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] + mine[x - 1][y] - 8 * '0');
}

test.c文件

#include"game.h"

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

void game()
{
	char mine[ROWS][COLS];//存放的雷
	char show[ROWS][COLS];//存放盘查出雷的信息
	//初始化棋盘
	//mine数组最开始全是‘0’
	//show数组最开始全是‘*’
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	DisPlayBoard(show, ROW, COL);
	
	//布置雷
	SetMine(mine, ROW, COL);
	//排查雷
	FindMine(mine, show, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 2:
			system("cls");
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	
}

游戏效果展示:(为了方便截图,已注释了清屏的代码)

 哈哈哈,这次游戏疏忽大意导致游戏失败了~

总结:今天我们学习了扫雷小游戏,再次使用多文件编程的形式,同时也体验了玩自己所写的游戏,如果我写的有什么的不好之处,请在文章下方给出你宝贵的意见。如果觉得我写的好的话请点个赞赞和关注哦~😘

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/510395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

眼球追踪、HDR、VST,从代码挖掘Valve下一代VR头显

擅长爆料、挖掘线索的Brad Lynch&#xff0c;此前发布了Quest Pro等设备的线索文章引发关注。​近期&#xff0c;又公布一系列与“Valve Deckard”VR头显相关消息&#xff0c;比如支持眼球追踪、HDR、VST透视、Wi-Fi网络等等。在SteamVR 1.26.1测试版更新、Steam用户端、Gamesc…

lazada、shopee转化率低怎么办?做好这几点,让你的店铺转化率提升

如若lazada, shopee如果转化率低&#xff0c;商家需要做好以下几个方面&#xff0c;通过以下几点来提高。毕竟只有流量没有转化率&#xff0c;店铺管理不好。 1、产品类别的选择 一个好的类别本身就是一个很好的排水渠道&#xff0c;可以给我们带来大量的流量&#xff0c;高流…

数据结构与算法基础(王卓)(38):排序、全部PPT、笔记整理

首先&#xff0c;庆祝本系列完结撒花&#xff01; 对了&#xff0c;后续应该会把王卓老师所有的PPT附带笔记全部打包上传百度云 回头我把链接贴出来&#xff0c;感兴趣的朋友可以Mark一下&#xff0c;希望可以帮助到大家 如果有什么写的不对的地方&#xff0c;先给大家说声抱…

23年的软件测试前景?我卷自动化测试卷出头了,拿下22K*15薪...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 测试工程师主要干…

Linux一学就会——管道通信

管道通信 进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的资源。 通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xff09;发生了某种事件&…

通过计算系统稳定性比较迭代次数

有一类差值结构可能有一行中的数字比其他行的都多&#xff0c;因此有天然的底部&#xff0c;很容易确定平均列的顺序。但是可能有的差值结构相同的底部不止一个&#xff0c;这次比较双底部差值结构迭代次数的顺序。 ( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入有3个节…

2023年US News最佳MBA排名出炉,申请需要哪些条件?

在出国留学的大环境下&#xff0c;MBA文凭一直都非常受欢迎&#xff0c;美国商学院是中国学生热衷的留学方向&#xff0c;而针对管理者的MBA项目也受到追捧。 US News 统计了美国130个全日制MBA的毕业生起薪&#xff0c;2023年毕业生的平均工资为 $105,684&#xff0c;Top 10 …

纽扣电池/含纽扣电池商品亚马逊美国澳洲站点合规认证要求!

纽扣电池/含纽扣电池商品亚马逊美澳站点合规认证 亚马逊美国站纽扣电池&#xff08;含纽扣电池产品&#xff09;合规要求标准&#xff1a; 16CFR1700.15部分(防毒包装标准) 16CFR1700.20部分(特殊包装的检测程序) ANSI C18.3M(便携式锂原电池的安全标准) 警示标签声明要求(…

对于零基础小白来说,转行学云计算和java哪个更好一些?求推荐

对于零基础小白来说&#xff0c;转行学云计算和java哪个更好一些&#xff1f; 云计算和Java是两个不同的技术领域&#xff0c;虽然它们都与计算机网络、分布式系统和互联网应用程序等相关&#xff0c;但它们的学习重点和应用场景也不同。虽然他们都是非常有前途的IT领域&#x…

Web3中文|比特币 BRC-20 让“闪电网络”再受热议

一位幸运的矿工在上周日晚上赚取了 6.701 枚BTC&#xff08;约 200,000 美元&#xff09;的交易费用&#xff0c;超过了当前的 6.25 BTC 的区块奖励。这一极为罕见的事件说明了与 Ordinals 协议相关的区块链活动导致了用户成本的飙升。 高昂的比特币交易费用 2022年底&#xff…

RT-DETR原理与简介(干翻YOLO的最新目标检测项目)

概述与简介 RT-DETR是一种实时目标检测模型&#xff0c;它结合了两种经典的目标检测方法&#xff1a;Transformer和DETR&#xff08;Detection Transformer&#xff09;。Transformer是一种用于序列建模的神经网络架构&#xff0c;最初是用于自然语言处理&#xff0c;但已经被证…

反射机制【Java】

文章目录 定义获得Class对象的方式反射的具体使用几个重要的类及方法反射的优缺点 在一些特定的场景中&#xff0c;我们可能会需要获取一些私有的成员变量或方法的信息&#xff0c;但直接在类外调用是无法成功获取到的&#xff0c;因此我们就需要一种机制来获取一些需要的变量或…

多媒体通信有些SCI期刊推荐? - 易智编译EaseEditing

以下是一些多媒体通信领域的SCI期刊推荐&#xff1a; IEEE Transactions on Multimedia&#xff1a; 这是IEEE计算机学会旗下的一个期刊&#xff0c;涵盖了多媒体信号的处理、编码、压缩、传输和交互等方面的研究。 ACM Transactions on Multimedia Computing, Communication…

操作系统原理 —— 七种常见的调度算法(十三)

大家都知道&#xff0c;学习这种类型的算法&#xff0c;在很多时候&#xff0c;我们只是学习它的一种思想&#xff0c;那有没有好的学习调度算法的思路呢&#xff1f; 我们可以基于一下路线&#xff0c;来学习调度算法&#xff1a; 1、算法思想2、算法规则3、这种调度算法是用…

Excel 冻结指定行 / 列

目录 假设你的表格是这样的&#xff1a; 1. 确定你要冻结的行列数 2. 计算下一个单元格的位置 3. 选中红框的单元格&#xff0c;视图 > 冻结窗格 > 冻结拆分窗格 4. 出现下面红框中的线即代表功能已经实现。 在使用 Excel 的过程中&#xff0c;经常会需要保持某一行 / 某…

【目标检测】入门教程之yolo v1理论与实战

every blog every motto: There’s only one corner of the universe you can be sure of improving, and that’s your own self. https://blog.csdn.net/weixin_39190382?spm1010.2135.3001.5343 0. 前言 目标检测入门实战教程 1. 正文 1.1 感性认识 我们想做的事&…

【shell脚本】数组

数组 一、数组1.1数组的定义方法1.2数组包括的数据类型1.3获取数组的元素1.4数组追加1.5向函数传入数组的值 二、排序算法2.1冒泡排序2.2直接选择排序2.3插入排序2.4反转排序 一、数组 1.1数组的定义方法 格式 方法一&#xff1a; 数组名&#xff08;1 2 3 4 5&#xff09;#…

Ubuntu本地快速搭建web小游戏网站,公网用户远程访问【内网穿透】

文章目录 前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar内网穿透3.2 创建隧道3.3 测试公网访问 4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名 转载自cpolar极点云的文章&#xff1a;在Ubunt…

一款国产开源数据同步中间件,支持多种数据源和预警功能

DBSyncer是一款开源的数据同步中间件&#xff0c;提供MySQL、Oracle、SqlServer、PostgreSQL、Elasticsearch(ES)、Kafka、File、SQL等同步场景。 支持上传插件自定义同步转换业务&#xff0c;提供监控全量和增量数据统计图、应用性能预警等。 特点 组合驱动&#xff0c;自定…

数据表的创建和管理 (数据库)

目录 一、数据表结构的创建 1、利用create命令创建表 2&#xff0e;关于创建表时运用约束的说明 &#xff08;1&#xff09;空值约束&#xff08;NULL or NOT NULL&#xff09; &#xff08;2&#xff09;主键约束&#xff08;primary key constraint&#xff09; &#x…