C语言实现扫雷【经典】

news2024/11/24 20:34:37

前言
  本篇文章要实现的是扫雷游戏,其代码实现与上一篇的三子棋游戏类同,都是在棋盘的基础上,与电脑进行对抗,不同的是,扫雷游戏一开始电脑就已经随机布置好了所有“雷”。
在这里插入图片描述

请戳 --->三子棋

扫雷游戏

  • 1. 扫雷游戏玩法
  • 2. 设计思路
    • 2.1 准备工作
    • 2.2 主函数设计
    • 2.3 设计棋盘
      • 2.3.1 初始化棋盘
      • 2.3.2 打印棋盘
    • 2.4 布置雷
    • 2.5 排除雷
      • 2.5.1 代码实现
  • 3. 总结
    • 3.1 game.h文件所有内容
    • 3.2 game()游戏函数整体
  • 结束语


1. 扫雷游戏玩法

经典玩法:

扫雷就是要把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败

游戏主区域由很多个方格组成。选择一个方格,方格即被打开并显示出方格中的数字

而方格中数字则表示其周围的8个方格隐藏了几颗雷;如果点开的格子为空白格,即其周围有0颗雷,则其周围格子会自动打开。

在这里插入图片描述

本机玩法:

游戏开始,玩家在棋盘格上输入正确的行列坐标选择位置,若选择到的是非地雷,就会显示出周围8个格子存在雷的数量,直到把所有非雷的格子都选出来,游戏胜利;若“踩雷”了,则游戏失败

看似简单的扫雷游戏,想要胜利,走的每一步都需要推算

2. 设计思路

游戏都需要一个开关去控制它,所以一个菜单界面是必不可少的,通过菜单去选择play还是exit

而对于游戏的实现:

1.首先需要创建一个n*n的棋盘格,可以用二维数组实现,自定义它的大小

2.在玩家选择位置前,就要布置好雷的数量,随机埋下雷的位置,并用一个二维数组来存放布置好的雷

3.玩家通过提示,输入正确的坐标选择位置,如果选择的是非雷坐标,就显示出周围雷的数量,用一个二维数组来存放排查出的雷的信息(数量)

坐标选择后的状态有两种:

  • 选择的坐标是非雷的,显示周围雷的数量,一直到排查完所有的雷,即所有的坐标都选择完了且没有踩雷,游戏胜利
  • 选择的坐标是有雷的,游戏失败

2.1 准备工作

🍥 建立 test.c 源文件 – 测试游戏代码
🍥 建立 game.c 源文件 – 游戏的实现
🍥 建立 game.h 头文件 – 游戏函数声明

2.2 主函数设计

为了控制游戏的进行,我们设置一个菜单选项,选1时玩游戏,选择0,则退出游戏。

🍤 代码实现:

//test.c

int main()
{
	//菜单
	printf("----1. play----\n");
	printf("----0. exit----\n");
	//进行选择
	int input;
	printf("请选择:");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();//游戏函数
		break;
	case 0:
		printf("退出游戏\n");
		break;
	default:
		printf("选择错误,请重新选择\n");
		break;
	}
	return 0;
}

当玩家想要一直玩游戏,该怎么办呢? 加入循环
同时,为了使主函数简洁明了,我们将菜单放在主函数外面,使用menu函数来实现

//test.c

void menu()
{
	printf("----1. play----\n");
	printf("----0. exit----\n");
}
int main()
{
	int input;
	srand((unsigned int)time(NULL));//设置随机种子
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

🍤 菜单显示:
在这里插入图片描述

2.3 设计棋盘

想打印一个9x9的棋盘格实现游戏,我们就需要先创建两个二维数组(11x11),一个存放布置好的雷,一个存放排查出的雷的信息。

为什么是11x11?
考虑到棋盘边缘的位置,周围并不能的格子不能都满足8个,所以为了防止在统计坐标周围的雷的个数的时候越界,所以让数组设计为11x11,这里的11x11并不会全部打印出来

在这里插入图片描述

char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息

仔细观察就会发现,这里的数组大小为什么是ROWSxCOLS,而不是11x11呢?

在下面设计棋盘时,我们的大小与这里是相同的,而为了后期可以方便的调整大小,我们就在game.h文件中就定义这两个全局变量的大小

🍤 代码实现:

#define ROW 9//显示的棋盘大小
#define COL 9

#define ROWS ROW+2//棋盘真正大小
#define COLS COL+2

2.3.1 初始化棋盘

//game.c

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;
		}
	}
}

🍤 调用:

//test.c

void game()
{
	char mine[ROWS][COLS];//存放布置好的雷
	char show[ROWS][COLS];//存放排查出的雷的信息
	//初始化棋盘
	//1.mine数组最开始全‘0’、
	//2.show数组最开始全‘*’
	InitBoard(mine,ROWS,COLS,'0');
	InitBoard(show,ROWS,COLS,'*');
}

2.3.2 打印棋盘

DisplayBoard函数实现棋盘打印,为了玩家有更好的游戏体验,我们在棋盘格的最顶端和最左边提示坐标信息,方便玩家快速的锁定行列数。

//game.c

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++)
	{
		printf("%d ", i);//最左边打印行数
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

打印棋盘时,只用打印出9x9大小的棋盘格

//打印棋盘
DisplayBoard(show, ROW, COL);//打印棋盘函数调用

🍤运行结果:

在这里插入图片描述

2.4 布置雷

在game.h文件中先定义全局变量EASY_COUNT,控制雷的数量

#define EASY_COUNT 10

在布置雷时,要先生成随机坐标,然后判断该坐标是否可以放雷

  • rand函数产生随机值
  • 每一个格子只能存放一个雷,前面初始化棋盘时,已经将所有的格子(11x11)全初始化为’0’,所以在布置雷,只能在为’0’的格子中存放
//game.c

void SetMine(char board[ROWS][COLS], int row, int col)
{
	//布置雷
	//生成随机的坐标,布置雷
	int count = 10;
	while (count)
	{
		int x = rand() % row + 1;//为了控制随机值大小,防止越界,范围:1-9
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

🍤 调用头文件:

//game.h

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

2.5 排除雷

玩游戏选择坐标时,会有三种结果:

1. 选择存放了雷的坐标,游戏结束

玩家先输入坐标,该坐标行列大小在定义的范围内,然后判断是否是存放了雷的坐标。

在之前我们已经初始化了所有位置都是‘0’,只有随机存放了雷的位置,会变为‘1’,而当输入的坐标的内容为‘1’时,即玩家踩雷了,游戏结束。

2. 选择了安全的坐标,且显示周围8个坐标的雷的数量

如果输入的坐标的内容为‘0’,则计算出周围8个位置的雷的数量,并打印在此坐标上。

在这里,我们用GetMineCount函数单独计算,返回雷的数量

假设已知坐标x,y,其他周围的坐标就可以表示为:
在这里插入图片描述

🍤 代码实现:

//game.c

int GetMineCount(char mine[ROWS][COLS],int x,int 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');
}

🍩游戏胜利的实现

定义一个变量win,在每次选择非雷的坐标后累加1,当win=棋盘总个数(9x9)-存放了雷的个数,即win==row* col - EASY_COUNT,也就排除了所有的雷,游戏胜利。

3. 坐标选择错误

当我们选择的行列坐标超出设定的范围,就提示玩家输入错误,重新输入。

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

2.5.1 代码实现

//game.c

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0;
	int win = 0;
	while (win<row*col-EASY_COUNT)
	{
		printf("请输入要排查的坐标,如:1 2:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				int count=GetMineCount(mine, x, y);//统计周围8个位置的雷的数量
				show[x][y] = count + '0';
				DisplayBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入!\n");
		}
	}
	if(win == row* col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功…^-^…");
		DisplayBoard(mine, ROW, COL);
	}
}

3. 总结

3.1 game.h文件所有内容

#include<stdlib.h>
#include<time.h>
#define EASY_COUNT 10
#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+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);

3.2 game()游戏函数整体

//test.c

void game()
{
	char mine[ROWS][COLS];//存放布置好的雷
	char show[ROWS][COLS];//存放排查出的雷的信息

	//初始化棋盘
	//1.mine数组最开始全‘0’、
	//show数组最开始全‘*’
	InitBoard(mine,ROWS,COLS,'0');
	InitBoard(show,ROWS,COLS,'*');

	//打印棋盘
	DisplayBoard(show, ROW, COL);

	//1.布置雷
	SetMine(mine,ROW,COL);

	//2.排查雷
	FindMine(mine, show, ROW, COL);
}

🍩注: 每一个.c文件最前面,需要用 #include "game.h" 进行声明


结束语

扫雷的实现就到这里了,感觉这篇文章有帮到你的话,点赞支持一下哟。
  我们下一篇文章再见。
在这里插入图片描述

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

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

相关文章

【Visual Studio】VTK 显示小球例子,在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 关于更多此例子的资料&#xff0c;可以参考&#xff1a;【Visual Studio】在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK。 文章目录 版本环境VTKTest.…

Nginx upstream 负载均衡配置

[toc] ## 问题: 自7/4 以来, 所有设备同时出现 Network Error, 导致业务无法正常进行, 频率 3次/每分钟; ## 现场情况及原因分析: 3楼: 8条产线 4楼: 20条产线 5楼: 5条产线 点数: 33条线 * 平均 (5台工位 1台电视看板 3台测试仪 ) ≈ 300 - Nginx 日志占用: access 日志 …

【MySQL备份与还原、索引、视图】练习

一、备份与还原 /***************************样例表***************************/CREATE DATABASE booksDB;use booksDB;CREATE TABLE books(bk_id INT NOT NULL PRIMARY KEY,bk_title VARCHAR(50) NOT NULL,copyright YEAR NOT NULL);INSERT INTO booksVALUES (11078, Lear…

UNIX网络编程卷一 学习笔记 第二十三章 高级SCTP套接字编程

SCTP是一个面向消息的协议&#xff0c;递送给用户的是部分的或完整的消息。只有当发送大消息时&#xff0c;在对端才会递送部分的消息。部分消息被递送给应用后&#xff0c;多个部分消息组合成单个完整消息不由SCTP负责。在SCTP应用进程看来&#xff0c;一个消息既可由单个输入…

线性代数的一些小细节

1 .矩阵的满足结合律&#xff0c;但不满足交换律 验证和证明如下图&#xff1a; 如下&#xff0c;UWQ三个矩阵的2种结合&#xff0c;证明矩阵乘法满足结合律 下图中&#xff0c;AB 和BA的值可能是不同的&#xff08;相同的条件是图中相互对应的4项相同&#xff0c;即对称矩阵…

防范 XSS 攻击的措施

防范 XSS 攻击的措施 XSS&#xff08;Cross-site scripting&#xff09;攻击是一种常见的网络安全漏洞&#xff0c;它可以通过注入恶意代码来攻击用户的计算机和浏览器&#xff0c;从而窃取用户的敏感信息或执行恶意操作。本篇文章将介绍防范 XSS 攻击的措施&#xff0c;并提供…

Spring设计模式及部分技术讲解

讲师:邓澎波 Spring面试专题 1.Spring应该很熟悉吧?来介绍下你的Spring的理解 有些同学可能会抢答,不熟悉!!! 好了,不开玩笑,面对这个问题我们应该怎么来回答呢?我们给大家梳理这个几个维度来回答 1.1 Spring的发展历程 先介绍Spring是怎么来的,发展中有哪些核心的节…

Linux文件

目录 系统级I/O 简介 接口 文件描述符fd 重定向 缓冲区 文件系统 软硬链接 动静态库 静态函数库 动态库 系统级I/O 简介 输入/输出&#xff08;I/O&#xff09;是在主存和外部设备&#xff08;磁盘驱动器、终端和网络&#xff09;之间复制数据的过程。输入操作是…

opencv-04 像素处理

opencv-04 像素处理 在 OpenCV 中&#xff0c;最小的数据类型是无符号的 8 位数。因此&#xff0c;在 OpenCV 中&#xff0c;实际上并没有二值图像这种数据类型&#xff0c;二值图像经常是通过处理得到的&#xff0c;然后使用0表示黑色&#xff0c;使用 255 表示白色。 可以将…

【基本算法】三分法模板

洛谷三分法https://www.luogu.com.cn/problem/P3382 题目描述 如题&#xff0c;给出一个 N 次函数&#xff0c;保证在范围 [l,r] 内存在一点 x&#xff0c;使得 [l,x] 上单调增&#xff0c;[x,r] 上单调减。试求出 x 的值。 输入格式 第一行一次包含一个正整数 N 和两个实数…

吐血整理,Jmeter分布式性能压测-常见问题+解决(详细整理)

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

使用npm和nrm查看源和切换镜像

一、使用npm查看当前源、切换淘宝镜像、切换官方源 &#xff08;1&#xff09;npm查看当前源&#xff1a; npm get registry &#xff08;2&#xff09;npm设置淘宝镜像源&#xff1a; npm config set registry http://registry.npm.taobao.org &#xff08;3&#xff09;n…

注册中心技术Eureka、Nacos

说明&#xff1a;在微服务框架中&#xff0c;各个服务之间都是独立的。理论上来说&#xff0c;各个服务之间是可以直接通信的&#xff0c;但实际上因为服务之间通信需要管理和规划&#xff0c;如请求怎么负载均衡、请求怎么降级处理等等&#xff0c;所以就需要使用一个技术&…

企业绿色发展关键环节:产品碳足迹管理

近年来&#xff0c;产品生产消费对环境造成的影响越来越受到重视。“产品碳足迹”作为衡量产品对环境影响的重要指标&#xff0c;已成为企业在产品生命周期管理中不可忽视的元素。“产品碳足迹”&#xff08;Product Carbon Footprint, PCF&#xff09;是指产品在生产、制造、运…

【剧前爆米花--前端三剑客】JavaScript(WebAPI)中的相关方法和实例

作者&#xff1a;困了电视剧 专栏&#xff1a;《JavaEE初阶》 文章分布&#xff1a;这是一篇关于JavaScript&#xff08;WebAPI&#xff09;的文章&#xff0c;在这篇文章中我会简单介绍一些常用的js方法&#xff0c;并给出他们的应用实例&#xff0c;希望对你有所帮助&#xf…

代码随想录day2 | 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II

文章目录 一、977.有序数组的平方二、209.长度最小的子数组三、59.螺旋矩阵II 一、977.有序数组的平方 977.有序数组的平方 暴力法&#xff1a;O(NlogN) 先所有数字平方&#xff0c;然后再快排&#xff0c;时间复杂度取决于快排 class Solution { public:vector<int> s…

Openlayers实战:加载天地图

国家地理信息公共服务平台“天地图”(以下简称“天地图“)是国家基础地理信息中心建设的网络化地理信息共享与服务门户。 其属于国家队的,有一定的权威性。 在Openlayers中如何加载天地图呢,方法很简单,用XYZ的形式。 它分为底图和标注,可以灵活的做配合使用。 效果图 源…

java学习路程之篇三、知识点、类、模块、项目、操作、下载、安装、IDEA

文章目录 1、IDEA开发工具2、IDEA的下载和安装3、IDEA中的第一个代码4、IDEAZ中的类、模块、项目的操作 1、IDEA开发工具 2、IDEA的下载和安装 3、IDEA中的第一个代码 4、IDEAZ中的类、模块、项目的操作

PX4实战 各种问题的参数调整解决方案

桨叶旋转频率引起的噪声 比较好的震动 不好的震动 一般好的振动特性时&#xff0c;三轴加速度的原始数据值都会在很小的范围内波动&#xff0c;在3范围内就是非常好的振动环境了。 分析飞行器的幅频特性&#xff0c;一方面除了查看飞行器的振动特性好坏&#xff0c;另一方面…

技术架构的演进-八大架构

目录&#xff1a; 常见概念评价指标单机架构应用数据分离架构应用服务集群架构读写分离 / 主从分离架构引入缓存 —— 冷热分离架构垂直分库业务拆分 —— 微服务容器化引入——容器编排架构总结 1.常见概念&#xff1a; 应用&#xff08;Application&#xff09; / 系统&am…