当前位置: 首页 > news >正文

扫雷(C语言)

目录​​​​​​​

前言

一、前提知识

二、扫雷游戏编写

2.2 test文件基本逻辑

2.2.1菜单编写

2.2.2game函数的逻辑

 2.2.2.1定义两个数组

2.2.2.2两个数组数组的初始化

2.2.2.3打印棋盘

2.2.2.4布置雷

2.2.2.5排查雷

2.2.2.6获取坐标附近雷的数量

2.2.2.7什么时候截止

2.2.2.8如何实现点击后展开一片

总结


前言

本篇文章基于前面的学习内容,有一些部分与前一篇的三子棋一样,可能会比较快,但是写逻辑的和游戏实现的时候会详细讲解,来动手写一个简单的扫雷。


一、前提知识

 

我们知道扫雷一个地图上有固定的炸弹,当选到炸弹的时候,游戏就会结束,没选到的时候,这个格子就会说明周围有多少个炸弹,扫雷棋盘的原理还是和上一篇的一样,同样可以用一个二维数组进行编写,我们只需要实现上述的逻辑就可以完成这个扫雷的小游戏,

我们还是使用VS2022创建一个空项目,同样的创建三个文件,一个game.h头文件,一个game.c文件,test.c文件,头文件在头文件里面,源文件在源文件里面创建。 

我们通过test.c文件来编写逻辑的实现,之后game.h和game.c来编写游戏的实现,通过测试的逻辑来调用游戏的实现。

二、扫雷游戏编写

2.2 test文件基本逻辑

2.2.1菜单编写

我们还是用简易的菜单,与上一篇文章一样,可以用一堆星号以及文字来代表一个菜单,同时上面有两个选择,1.选择游戏开始,0.选择游戏结束,直接结束进程。

编写上述模块,menu( ),这个函数在test( )游戏逻辑模块内进行调用。

这里还是用一个do-while循环语句来进行游戏持续的进行,同样的限制条件就是出入的内容,如果是0,那么就是为假,循环就退出,当1或者其他数字的时候,循环不结束。

循环语句里面套用一个switch-case语句,通过这个语句来进行不同选择从而实现不同的效果。

这样就基本实现了菜单选择的功能。

2.2.2game函数的逻辑

1.需要存放好雷的信息,存放排查出雷的信息,我们需要2个二维数组
2.排查坐标的之后,为了防止坐标越界,我们给数组的行增加了两行,列增加了两行。

3.我们希望show数组内都是 * ,希望我们的mine数组都是字符‘0’,这样认为雷都是没有排。

 2.2.2.1定义两个数组

我们首先在game.h里定义行和列,以及多两行和多两列的定义。

之后再test.c中包含一下这个头文件,这样这里的定义的行和列就可以使用了。

接下来首先定义两个数组,一个是mine数组作为还没有进行排查的时候,并且里面布置好了雷的信息,接下来在定义一个排查出雷的信息,命名为show,将两个数组进行初始化。

 

2.2.2.2两个数组数组的初始化

我们用名字命名为InitBoard的函数来进行数组的初始化,通过传入三个参数,数组,行,列,来进行数组。

初始化函数还是在头文件进行声明,在game.c里面进行定义。由于这个函数既有可能是对mine函数进行初始化,又有是对show进行初始化,所以这里的参数数组形参就命名为board就可以。

声明之后在game.c里面进行定义,通过遍历就可以实现初始化,但是这里有一个问题,就是我们想要mine数组里面全是0,而show数组里面全是 * ,但它们俩是使用一个函数的,所以会产生冲突,这时候我们就可以进行多传入一个参数,这就可以解决这个问题。所以改成下面:

我们用set作为这个字符形参,用来接收这个数组里面都是什么字符,好实现数组的初始化。接下来进行定义:

这样就可以初始化了。

2.2.2.3打印棋盘

我们用一个命名为DisplayBoard的函数来进行棋盘的打印。我们创建的是11*11,但是我们只需要打印中间的9*9,外面的一行就是为了考虑数组越界而设置的,所以对于外面这一圈是不需要打印出来的。这时候传入的参数行和列就使用ROW和COL就可以。

首先在头文件中进行声明:

这里注意一下,我们传入参数依然是11*11的数组,因为它本来就是一个11*11的二维数组,如果想直接传入中间的9*9数组是不可能的。

接下来进行在game.c里面实现这个函数:

 

这里通过一个遍历循环,打印完一行之后打印换行符就可以了,这样就可以打印出行和列都是什么,也就可以实现初始化之后打印棋盘的目的。

我们这里把game函数放到case1中去,这样就就可以调用这个函数了。下面看运行结果:

通过以上代码运行,最后就输出了两个二维数组,一个是9*9的全是0的mine数组,这里的0是字符‘0’,如果直接写数字,那么打印出来什么都看不见。另一个则是全是 * 的show数组。但这样看着并不怎么美观,就可以打印一下行号和列号。通过字符后面加上空格,以及打印行数列数,即可实现。

把打印这个函数写成下面的形式:

 

运行结果如下:

 

这样就非常的美观了。

但实际上我们不会打印布置好的雷的,我们只会显示排查雷的信息就可以了,所以只需要打印一个show的棋盘就可以。接下来布置雷,布置完雷之后才开始排雷。

2.2.2.4布置雷

我们这里用SetMine这个名字来代表布置雷的的函数,在game函数中调用这个函数就可以实现布置雷,而这个雷是在9*9的二维数组里面进行布置,所以这个函数的参数有三个,一个是要布置雷的数组,还有行和类。

同样的还是在头文件中进行声明:

传入的时候还是传入11*11的mine数组。 

game.c中进行定义实现 :

 

我们要随机的布置雷,同时因为扫雷有不同的难易程度,这里假设9*9的棋盘上有十个雷,所以先在头文件中定义一个EASY_COUNT来代表雷的个数有十个。

 之后在布置雷的函数中用count来接收这个EASY_COUNT的值,这里写一个循环,只要count还存在,就执行循环内容,这样就可以实现了一个一个布置雷的效果,知道雷全布置完这个循环就结束了。

雷的生成有限制,因为这个数组棋盘是11*11的,我们只用到了中间的9*9,所以行数是从1到9,列是1到9。但随机数的生成该怎么实现行和列的随机值而且还符合这个限制呢?我们就可以让随机生成的值去模上row,col,之后再加1,这样就可以实现1-9。但做这些之前首先要给出一个随机数生成的标志。

 要用到上述函数需要包含头文件,所以在game.h里面包含上:

接下来布置雷:

如果要布置的地方不是雷,我们就要布置雷进去,所以这里是一个if语句用来实现判断以及布置了的实现:

 

 如果这个坐标位置里面是‘0’这个字符,那么就把它变为‘1’,这就相当于布置成功了,这时候count就减去1,说明布置的雷少了一个。

我们可以在test.c中来看看效果,把打印mine棋盘这个函数写在布置雷之后,编译运行:

 这样就实现的催记布置十个雷在mine数组里面,注意==和=号的区别,我在写的时候就写错了,看半天哈哈哈。

2.2.2.5排查雷

我们这里用命名为FindMine的函数来进行排雷。排查雷其实就是看一下这个是不是雷,如果是就被炸了,如果不是,就统计一下周围有几个雷,而且把这个值放到选择的这个坐标。所以FindMine函数是从mine这个数组里面查找雷的信息之后放到show数组里面,而且依旧是9*9的格子,所以里面的参数有两个数组,还有行和列。

还是一样的我们在头文件里面进行声明,之后game.c文件里面进行排雷函数的实现编写。

 这里就是实现的排查雷的过程,我们这里用到一个while循环来代表游戏一直进行不间断,直到当我输入的坐标这个位置的字符为1,那么就是踩到了炸弹,就是接游戏结束,打印出mine数组的棋盘,如果没有遇到炸弹,就用一个自定义函数来获取这个坐标附近一圈的炸弹的数量,并且把这个坐标的字符改为附近炸弹的多少,由于这里数组里面都是字符,所以我们需要想一想字符所对应的ASCLL码,因为0字符对应的是48,所以只要加上n就可以实现ASCLL码转数字字符了。接下来再打印show数组。如果输入的坐标不是在这个范围之内,就直接输出“坐标非法,请重新输入”,由于是while循环,所以循环一直进行。

注意这里那个提示输入排查坐标那句代码应该写在循环里面,因为如果写在外面,它就只提示一次,下一次就不会再提示了。

2.2.2.6获取坐标附近雷的数量

这里用命名为get_mine_count的函数来代表获取雷附近的数量,就直接在game.c里面写就可以:

一个格子附近有八个格子,我们只需要把这八个格子的字符的ASCLL码值加在一起,之后减去8个‘0’就可以得出来周围有几个雷,因为如果一个坐标没有雷的话就是‘0’,只有有雷的时候才是‘1’。

完成这些之后运行一下:

我们可以看见,在mine数组里面第二行第四列放置了一个雷,当我们选中1 4之后,它就会显示这个坐标周围有一个雷,这样这个排雷就可以运行起来了。

实际上我们玩的时候,我们只输出show这个数组,mine数组是不打印出来的,所以我们就可以把输出mine的数组的代码注释掉。

写到这里的时候,就可以进行游玩了,但是什么时候截止就会变成一个问题。

2.2.2.7什么时候截止

因为这个棋盘是9*9的棋盘,也就是81个格子,只要我们找到71个不是雷的格子,就可以结束运行,这样就代表了扫雷都扫到了。

这里就简单的实现一下,通过命名一个win的变量来代表排除雷的数量,当win的值小于71的时候,循环一直进行,当不满足这个条件的时候,还需要判断一下雷是否真的等于71,如果不等于,那么就是被炸了,如果等于,就输出排雷成功。

我们可以修改以下define定义的雷的数量,我们修改成80个之后,只有一个坐标不是雷,那么输入进去后看输出的内容,就可以判断自己是否写对了。当我们排雷成功后,再打印一下mine数组,让我们看一下最后的棋盘。

但这里还有一个问题:

当我们排查过这个坐标后,我们输入这个坐标后我们不想让它继续排查,所以应该看一下被没被排查然后再进行判断是否为雷:

利用continue就可以实现这一功能,如果被排查过它这个坐标应该是这个坐标周围的雷的数量,如果没被排查过这个就是星号,通过这个逻辑就可以解决这一问题。

2.2.2.8如何实现点击后展开一片

我们再玩的时候,正常是选择一个坐标后它可以展开一片,这个坐标的周围的八个坐标分别判断,依次类推,所以就可以实现这一样式。这里我们就可以通过一个递归来解决,但这个递归可以自己想一想,这里只讲一些大致的逻辑和思路。


总结

这里给出源代码:扫雷游戏: C语言版本扫雷游戏 (gitee.com)

大家可以参考上述代码进行自己的学习。

本篇文章基于上一篇的内容很容易实现,知识都是连贯的,只要肯有耐心就可以一直会下去。

相关文章:

扫雷(C语言)

目录​​​​​​​ 前言 一、前提知识 二、扫雷游戏编写 2.2 test文件基本逻辑 2.2.1菜单编写 2.2.2game函数的逻辑 2.2.2.1定义两个数组 2.2.2.2两个数组数组的初始化 2.2.2.3打印棋盘 2.2.2.4布置雷 2.2.2.5排查雷 2.2.2.6获取坐标附近雷的数量 2.2.2.7什么时候…...

【实践功能记录8】使用UseElementSize实现表格高度自适应

一、关于 UseElementSize UseElementSize 是一个 Vue 组合式 API 的实用工具,通常用于获取 DOM 元素的尺寸信息,例如宽度、高度等。它通常与 v-slot 一起使用,以便在模板中直接访问这些尺寸信息。 地址:https://vueuse.org/core/u…...

SMO算法 公式推导

min ⁡ α 1 2 ∑ i 1 N ∑ j 1 N α i α j y i y j K ( x i ⋅ x j ) − ∑ i 1 N α i s.t. ∑ i 1 N α i y i 0 0 ≤ α i ≤ C , i 1 , 2 , ⋯ , N (9-69) \begin{aligned} & \min_{\alpha} \quad \frac{1}{2} \sum_{i1}^{N} \sum_{j1}^{N} \alpha_i \alpha_j…...

nodejs包管理器pnpm

简介 通常在nodejs项目中我们使用npm或者yarn做为默认的包管理器,但是pnpm的出现让我们的包管理器有了更多的选择,pnpm相比npm具有以下优势: 速度更快,pnpm在安装依赖时,会将依赖包缓存到全局目录,下次安…...

【postman】工具下载安装

postman作用 postman用于测试http协议接口,无论是开发, 还是测试人员, 都有必要学习使用postman来测试接口, 用起来非常方便。 环境安装 postman 可以直接在chrome 上安装插件,当然大部分的同学是没法连接到谷歌商店的,我们可以在电脑本地…...

Java_Springboot核心配置详解

Spring Boot以其简洁、高效和约定优于配置的理念,极大地简化了Java应用的开发流程。在Spring Boot中,核心配置是应用启动和运行的基础。本文将详细介绍Spring Boot中的两种配置文件格式、基础注解的配置方式、自定义配置以及多环境配置。 一、Spring Bo…...

太速科技-9-基于DSP TMS320C6678+FPGA XC7V690T的6U VPX信号处理卡

基于DSP TMS320C6678FPGA XC7V690T的6U VPX信号处理卡 一、概述 本板卡基于标准6U VPX 架构,为通用高性能信号处理平台,系我公司自主研发。板卡采用一片TI DSP TMS320C6678和一片Xilinx公司Virtex 7系列的FPGA XC7V690T-2FFG1761I作为主处理器&#…...

在线UI设计工具:创意与效率的结合

随着UI设计领域的快速增长,设计师们纷纷投身于这一行业,选择一款合适的UI设计工具变得至关重要。除了经典的UI设计软件,在线UI设计工具因其灵活性和便捷性,越来越受到设计师们的喜爱。这种不受时间和地点限制,且不依赖…...

【MyBatis源码】SqlSessionFactoryBuilder源码分析

文章目录 概述类结构从 InputStream 创建 SqlSessionFactoryXMLConfigBuilder构建ConfigurationXMLConfigBuilder初始化方法parse()方法parseConfiguration属性(properties) 概述 SqlSessionFactory 是 MyBatis 的核心接口之一,提供创建 Sql…...

Percona XtraBackup数据备份方案

一、简介 官方文档:https://docs.percona.com/percona-xtrabackup/innovation-release/index.html Percona XtraBackup 是一款适用于基于 MySQL 的服务器的开源热备份实用程序,可让您的数据库在计划的维护时段内保持完全可用。无论是 24x7 高负载服务器还是低交易量服务器,…...

聚“芯”而行,华普微亮相第五届Silicon Labs Works With大会

2024年10月24日,由致力于以安全、智能无线连接技术建立更互联世界的全球领导厂商Silicon Labs主办的第五届Works With开发者大会在上海雅乐居万豪侯爵酒店成功举办。 作为全球性的物联网年度“盛宴”,本届大会群英荟萃,不仅有着来自生态大厂的…...

Java 用户随机选择导入ZIP文件,解压内部word模板并入库,Windows/可视化Linux系统某麒麟国防系统...均可适配

1.效果 压缩包内部文件 2.依赖 <!--支持Zip--><dependency><groupId>net.lingala.zip4j</groupId><artifactId>zip4j</artifactId><version>2.11.5</version></dependency>总之是要File类变MultipartFile类型的 好像是…...

【C++】C++17结构化绑定、std::optional、std::variant、std::any

二十二、C17中的结构化绑定、std::optional、std::variant、std::any 本部分是一个小系列&#xff0c;介绍C17中新引入的、用来解决各种不同返回情况的、标准库新组件。 1、C的结构化绑定 结构化绑定structured bindings是C17中引入的一项特性&#xff0c;它允许开发者方便地…...

C#的起源。J++语言的由来?J#和J++傻傻分不清?

C#的起源 C#读音是C Sharp, 它是微软为了对抗Java而生&#xff0c;最早是J&#xff0c;效率比Java还好&#xff0c;后来被Sun公司起诉J破坏了平台无关性&#xff0c;微软重新开发C#. C#和Java一样都定位为中间件语言&#xff0c;用虚拟机执行编译的字节码以达到跨平台目的。从语…...

Flutter 在 对接 google play 时,利用 android studio 可视化生成 已签名的aab包

android studio 可视化生成 aab包 第一 &#xff1a; 先说注意事项 在Flutter项目里面&#xff0c;直接打开当前项目是不行的&#xff0c;不显示相应操作&#xff0c;需要在Android 目录打开&#xff0c;直白点就是直接打开项目里面的Android 目录 不然会出现的一些问题 第一…...

使用web.dev提供的工具实现浏览器消息推送服务

文章目录 前言实现工具和效果实现原理实现过程前端接收用户订阅请求将用户订阅信息更新到后端后端实现接收并保存订阅信息的接口后端实现消息推送的逻辑前言 对于电商独立站来说,新品上架或者促销活动上线及时通知到用户是很重要的,通知的渠道有很多,其中就包括浏览器消息推…...

计算机系统结构为什么用architecture 而不是structure?

architecture本意是建筑学、建筑艺术&#xff0c;其含义就是建筑的样子和背后的设计思想&#xff0c;用于计算机科学可以表达计算机的系统结构和后面的设计原理&#xff1a;它长什么样&#xff1f;它为什么长这样&#xff1f; 与architecture 对应的词是structure &#xff08…...

sqoop问题汇总记录

此篇博客仅记录在使用sqoop时遇到的各种问题。持续更新&#xff0c;有问题评论区一起探讨&#xff0c;写得有不足之处见谅。 Oracle_to_hive 1. main ERROR Could not register mbeans java.security.AccessControlException: access denied ("javax.management.MBeanTr…...

Git 创建新的分支但清空提交记录

有时候需要创建新的分支&#xff0c;但是原有分支的提交非常多&#xff0c;不好区分哪些是创建分支之后的提交。 那么就把原分支的提交全部去掉 要从 分支1 创建 分支2&#xff0c;并确保 分支2 不包含任何提交历史&#xff0c;同时文件与 分支1 的最后一次提交一致&#xff0…...

SQL PRIMARY KEY

SQL PRIMARY KEY 概述 在关系型数据库中&#xff0c;主键&#xff08;PRIMARY KEY&#xff09;是一个非常重要的概念。它是表中每一行数据的唯一标识符&#xff0c;用于保证数据的完整性和准确性。本文将详细介绍SQL中的主键&#xff0c;包括其定义、作用、如何创建和修改主键…...

软件测试学习笔记丨Flask操作数据库-对象与数据模型

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/23440 对象与数据模型 数据模型&#xff1a;是数据特征的抽象&#xff0c;抽象层次上描述了系统的静态特征、动态行为和约束条件&#xff0c;为数据库系统的信息表示与操作提供一个抽象的框架…...

IntelliJ IDEA使用 MybatisX-Generator 插件 自动生成Entity+Mapper+Mapper.xml等代码

一、Intellij安装MybatisX插件&#xff1a; 首先点击 Intellij->Preference->Plugins&#xff0c;然后搜索MybatisX&#xff0c;点击安装&#xff1a; 2 打开数据库 在IntelliJ IDEA 连接Mysql数据库&#xff0c;选择表&#xff0c;点击右键&#xff0c;选择 Mybatis…...

vue中如何为不同功能设置不同的默认打印设置(设置不同的打印机)

浏览器自带的window.print 功能较简单&#xff0c;这里使用LODOP露肚皮打印 以下是vue2示例&#xff1a; 从官网中下载Lodop和C-Lodop官网主站安装包并安装到本地电脑可以全局搜索电脑找到安装文件LodopFuncs.js&#xff0c;也可以直接复制我贴出来的文件 //用双端口加载主JS…...

经纬恒润INTEWORK-VBA新版本正式发布

在汽车电子研发领域&#xff0c;随着开发测试的深入&#xff0c;工程师们常常面临着一个共同的问题&#xff1a;如何高效地在多样化的开发测试场景中切换&#xff0c;并确保不同工具间的紧密协作。不同场景、不同工具的切换与使用给工程师带来高昂的学习成本和前后端信息传递的…...

金蝶云数据集成至MySQL的高效解决方案

金蝶云数据集成至MySQL的高效解决方案 金蝶云星空数据集成到MySQL的技术案例分享 在企业信息化过程中&#xff0c;数据的高效集成和管理是关键环节。本文将聚焦于一个具体的系统对接集成案例&#xff1a;金蝶云星空的数据如何通过轻易云数据集成平台无缝对接到MySQL数据库。本…...

Day02 C++ 环境设置

2024.11.1 C 环境设置 如果您想要设置 C 语言环境&#xff0c;需要确保电脑上有以下两款可用的软件&#xff0c;文本编辑器和 C 编译器。 一、文本编辑器 通过编辑器创建的文件通常称为源文件&#xff0c;源文件包含程序源代码。 C 程序的源文件通常使用扩展名 .cpp、.cp 或…...

AQS是什么

AQS&#xff1a;AbstructQueuedSynchronizer是java.util.concurrent.locks包中的一个类&#xff0c;是多线程同步器&#xff0c;J.U.C包中的多个组件的底层实现都使用到了它。如&#xff1a;Lock、CountDownLatch、Semaphore. 从本质上来说AQS实现了两种机制的锁&#xff0c;排…...

Spring IOC容器简介

Spring IoC&#xff08;Inversion of Control&#xff0c;控制反转&#xff09;容器是Spring框架的核心组件之一&#xff0c;负责管理应用程序中的对象及其依赖关系。IoC容器通过依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;实现对象的创建、配置和管理…...

【backstopjs】入门安装环境

1.首先全局安装BackstopJS npm install -g backstopjs 安装失败,常见报错&解决办法&#xff1a; 报错&#xff1a; (venv) D:\workspace\Otaku\backstop>npm install -g backstopjs npm warn deprecated inflight1.0.6: This module is not supported, and leaks mem…...

LocalDate 类常用方法详解(日期时间类)

LocalDate 类常用方法详解 LocalDate 是 Java 8 引入的日期时间API中的一个类&#xff0c;用于表示不含时间和时区的日期&#xff08;年、月、日&#xff09;。以下是一些常用的 LocalDate 方法&#xff1a; 创建 LocalDate 实例 now()&#xff1a;获取当前日期 LocalDate t…...