扫雷(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)

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

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

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

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

相关文章

Node.js:模块 包

Node.js:模块 & 包 模块module对象 包npm安装包配置文件镜像源 分类 模块 模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。 简单来说,就是把一个…

恋爱脑学Rust之dyn关键字的作用

在 Rust 语言中,dyn 关键字允许我们在使用特征时创建“动态派发”——即通过一个统一的接口操作多种类型的具体实现。可以把它理解成一种“浪漫的妥协”:当我们不知道未来会爱上谁,只知道对方一定具有某种特征时,dyn 就像一个协议…

vue3项目中实现el-table分批渲染表格

开篇 因最近工作中遇到了无分页情景下页面因大数据量卡顿的问题&#xff0c;在分别考虑并尝试了懒加载、虚拟滚动、分批渲染等各个方法后&#xff0c;最后决定使用分批渲染来解决该问题。 代码实现 表格代码 <el-table :data"currTableData"borderstyle"wi…

Qt自定义控件:汽车速度表

1、功能 制作一个汽车速度表 2、实现 从外到内进行绘制&#xff0c;初始化画布&#xff0c;画渐变色外圈&#xff0c;画刻度&#xff0c;写刻度文字&#xff0c;画指针&#xff0c;画扇形&#xff0c;画内圈渐变色&#xff0c;画黑色内圈&#xff0c;写当前值 3、效果 4、源…

语音识别:docker部署FunASR以及springboot集成funasr

内容摘选自: https://github.com/modelscope/FunASR/blob/main/runtime/docs/SDK_advanced_guide_offline_zh.md FunASR FunASR是一个基础语音识别工具包&#xff0c;提供多种功能&#xff0c;包括语音识别&#xff08;ASR&#xff09;、语音端点检测&#xff08;VAD&#xf…

鸿蒙进阶篇-模态转场

hello大家好&#xff0c;这里是鸿蒙开天组&#xff0c;今天让我们来学习鸿蒙进阶篇-模态转场 模态转场 今天来学习模态转场&#xff0c;就是页面中弹出&#xff0c;全屏&半屏的弹框&#xff1a; 就像这样&#xff0c;模态转场主要分为半模态和全屏模态&#xff0c;上面的…

RGA DEMO 下部

#加载llm模型通过ollama最好别用ollama我是没经济条件 from langchain_community.llms import Ollama llm Ollama(model"qwen1_5-4b-chat-q2_k")#pip install langchain_ollama -i https://pypi.tuna.tsinghua.edu.cn/simple #OllamaEmbeddings 要写地址本地也要写&…

Faces in Things数据集: 由麻省理工学院、微软等联合发布,探索人类视觉错觉的新里程碑

2024-09-24&#xff0c;由麻省理工学院、微软、丰田研究院、NVIDIA联合发布的 Faces in Things&#xff0c;为我们打开了研究人类视觉错觉——尤其是面部错觉&#xff08;Pareidolia&#xff09;的新篇章。专注于人类视觉系统如何在各种随机刺激中检测到类似面孔的结构&#xf…

知识见闻 - Workday公司介绍

人力资源“一哥”Workday的前世今生 01 Duffield 既然要聊Workday&#xff0c;我们首先要认识一个人。David Duffield&#xff0c;又一位企业软件服务行业的绝对大神。 大卫杜菲尔德&#xff08;David Duffield&#xff09;出生于1941年。 40岁&#xff0c;很多职场人都已经认命…

宁德时代嵌入式面试题及参考答案(万字长文)

vector 和 list 的主要区别是什么&#xff1f; 向量&#xff08;vector&#xff09;和链表&#xff08;list&#xff09;是 C 中两种常用的容器。 从底层数据结构来讲&#xff0c;vector 是基于连续的内存存储的动态数组。这使得它可以通过索引快速访问元素&#xff0c;时间复杂…

设计模式08-行为型模式1(命令模式/迭代器模式/观察者模式/Java)

五、行为型模式 **行为模式的定义&#xff1a;**行为型模式是对不同的对象之间划分职责和算法的抽象化。行为型模式定义了系统中对象之间的交互与通信&#xff0c;研究系统在运行时对象之间的相互通信与协作&#xff0c;进一步明确对象的职责&#xff0c;包括对系统中较为复杂的…

【设计模式】结构型模式(二):代理模式

结构型模式&#xff08;二&#xff09;&#xff1a;代理模式 3.代理模式&#xff08;Proxy&#xff09;3.1 主要特点3.2 组成部分3.3 示例代码3.3.1 Subject 接口3.3.2 RealSubject 实际对象3.3.3 Proxy 代理对象3.3.4 客户端代码3.3.5 运行结果 3.4 总结 3.代理模式&#xff0…

第二十八章 Vue之自定义指令

目录 一、引言 二、自定义指令的注册和使用方式 2.1. 自定义指令-全局注册使用 2.2. 自定义指令-局部注册使用 三、自定义指令完整代码 3.1. 自定义指令全局注册/使用 3.1.1. main.js 3.1.2. App.vue 3.2. 自定义指令局部注册/使用 3.2.1. main.js 3.2.2. App.vue …

Charles简单压力测试

1.接口请求次数&#xff0c;并发量&#xff0c;请求延迟时间均可配置 1.1选中需要进行测试的接口&#xff0c;鼠标右键选中【repeat advance】 2.设置并发参数 下面的图中&#xff0c;选择了1个接口&#xff0c;每次迭代中1个接口同时请求&#xff0c;迭代1000次&#xff08;…

【uniapp3】分享一个自己写的h5日历组件

简言 分享一下自己基于uniapp写的日历组件。如果不太满足你的需求&#xff0c;可以自己改造。 日历 实现分析&#xff1a; 页面显示 - 分为顶部显示和日历显示&#xff0c;我这里做了多行和单行显示两种情况&#xff0c;主要是当时看着手机的日历做的&#xff0c;手机上的…

Java设计模式(代理模式整理中ing)

一、代理模式 1、代理模式定义&#xff1a; 代理模式&#xff1a;由于某些原因要给某对象提供一个代理以控制对该对象的访问&#xff0c;这时访问对象不适合或者不能够直接引用目标对象&#xff0c;代理对象作为访问对象与目标对象之间的中介进行连接调控调用。 2、代理模式的…

Thumb 汇编指令集,Thumb 指令编码方式,编译 Thumb 汇编代码

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ Thumb指令集 ARM 指令集&#xff1a;最早在 1985 年随第一代 ARM 处理器问世。ARM 指令集一开始是 32 位固定长度的指令&#xff0c;用于各种计算任务。 Thu…

Leetcode - 周赛421

目录 一&#xff0c;3334. 数组的最大因子得分 二&#xff0c;3335. 字符串转换后的长度 I 三&#xff0c;3336. 最大公约数相等的子序列数量 四&#xff0c;3337. 字符串转换后的长度 II 一&#xff0c;3334. 数组的最大因子得分 暴力方法就不演示&#xff0c;这里介绍一个…

文件管理工具的按路径名称归类功能大公开,将大量文件批量复制或移动到指定路径,办公软件达人的秘密武器

是否还在为成堆的文件归类而苦恼&#xff1f;想要一键就能将海量文件按路径名称轻松归类&#xff0c;无论是复制还是移动&#xff1f;别急&#xff0c;今天就让文件批量改名高手软件的按路径名称归类功能来拯救你的文件管理世界&#xff01;让我们一起告别繁琐&#xff0c;迎接…

建设NFS服务器并实现文件共享

关闭防火墙和s0 systemctl stop firewalld setenforce 0 安装NFS yum install nfs-utils -y 新建共享目录并设置权限 echo "hello" > /nfs/shared/test1 chmod -Rf 777 /nfs/shared/ 配置服务端的NFS配置文件 vim /etc/exports /nfs/shared *(ro) 启动…