扫雷游戏项目实现详解

        扫雷这个游戏大家一定不陌生,但是这个游戏的底层运行逻辑大家肯定没有去想过,那本章就带着大家去实现这样的一个扫雷游戏。

1.扫雷游戏分析和设计

        扫雷游戏底层代码并不是我们想象中的很难,它其实很简单,知道分支,循环,函数,数组这几个知识点就可以去实现它,接下来我们来看看如何实现。

        首先,我们要先了解扫雷游戏的功能

使⽤控制台实现经典的扫雷游戏

游戏可以通过菜单实现继续玩或者退出游戏

扫雷的棋盘是9*9的格⼦
默认随机布置10个雷
可以排查雷
如果位置不是雷,就显⽰周围有⼏个雷
如果位置是雷,就炸死游戏结束
把除10个雷之外的所有⾮雷都找出来,排雷成功,游戏结束

2.菜单处理

      根据以上扫雷游戏的功能,我们首先可以先打印出菜单,在菜单中,我们要说明开始游戏和退出,这一步很简单,不过中实现菜单之前我们要了解一个常识,在实现一个项目的时候,我们会封装多个文件进行实现,这样既可以方便调试,也可以让别人更好的去观察你的代码。
test.c // ⽂件中写游戏的测试逻辑
game.c // ⽂件中写游戏中函数的实现等
game.h // ⽂件中写游戏需 要的数据类型和函数声明等
     
打印菜单和选择游戏开始与退出,我们就可以在test.c中实现
当我们选择1是就可以进入游戏,我们把游戏实现封装在一个game函数里,可以更好去管理自己的代码,选择0就是退出,在这个过程中,我们可以利用,switch语句实现,如果我们想在玩一次,就可以利用do—while循环来处理
有人可能发现了,为什么你的头文件是#include"game.h"呢,不应该是#include<stdio.h>,我们知道.h文件是头文件的意思,而由上述知道我们创建了一个game.h的文件,而这个文件所包含的内容就是我 们程序中所需要的头文件和数据类型与函数声明
我们在.c文件中怎么引用我们创建的.h文件呢,其是就是把<>号换成""号就可以了
有人不明白为什么要搞这么麻烦呢,就如为上述所说 可以方便调试,也可以让别人更好的去观察你的代码。

3.扫雷界面处理

这一步我们就来实现我们的游戏代码了,同样,写扫雷底层运行逻辑之前,我们首先要打印出扫雷的界面,例如我们要一个9x9的界面,如下图所示

    

我们发现,扫雷的布局是由多行多列组成的,这一步我们是不是就可以用二维数组来解决,

不过别忘了打印二维数组之前,要对它进行初始化,因此我们需要两个函数,一个表示二位数组的初始化,一个代表二维数组的打印。

board表示二维数组,row,cols/col表示二维数组行与列,set表示对二维数组初始化的字符。

有人可能发现,ROWS和COLS是啥,其实这两个代表的是数字,下面为大家解释

#define的用途是替换,也就是说ROWS其实就是11,为什么要弄成这个样子,这样可以更好的让我们开创多行多列的数组,因为我们在数组的初始化中,我们只需要改变ROWS和COLS后面的数据就行,不用去一个一个的改数据,不仅容易漏改,还可能改错,因此,#define很好的解决了这个问题,同样#define我们可以写到头文件中去

有人觉得奇怪为什么初始化期盼与打印棋盘所输入的数据不同,为什么初始化行列都是11,打印却是9呢?

这一步就很有讲究了,我们知道我们要打印的是9x9的界面,但是初始化为什么是11呢,首先就是我们玩的棋盘是9x9,但是,我们还需要展示每一列和每一行的数字,更好的方便我们要扫的点位,有人会说,这个我知道了,那给10不就行了,为什么要给11呢,我们知道当我们扫的点位不是雷时,就会有数字

这个数字就代表周围八个格子中有多少个雷,

当我们扫最底下时,如果只给10的话,最下⾯的三个坐标就会越界,为了防⽌越界,我们在设计的时候,给数组扩⼤⼀圈,雷还是布置在中间的9*9的坐标上,周围⼀圈不去布置雷就⾏,这样就解决了越界的问题。所以我们将数组创建成11*11是⽐较合适。

因此我们所创建的如下的数组

初始化代码如下:

这个代码代表游戏实现,写在game.c中

打印代码如下:

不知道大家注意到没有,为什么我打印行列时,从1开始而不是从0开始呢

大家知道这一步是打印列的标记

我们先看看从0开始打印会发生什么

为什么行标多个零,*号为什么多一列和多一行,其实很好理解,

这一部分我们由于是从零开始的,外层和内层都循环了10次,因此就会发生这样一个状况,我们从1开始的话,标记对的上,*号行列也对的上。

我们发现仅仅一个菜单就有这么多坑,因此我们更不应该疏忽大意。

4.布置雷

知道了扫雷界面后,我们就可以布置雷了。

我们在棋盘上布置了雷,棋盘上雷的信息(1)和⾮雷的信息(0),假设我们排查了某⼀个位置后,这个坐标处不是雷,这个坐标的周围有1个雷,那我们需要将排查出的雷的数量信息记录
存储,并打印出来。那这个雷的个数信息存放在哪⾥呢?如果存放在布置雷的数组中,这样雷的信息和雷的个数信息就可能或产⽣混淆和打印上的困难。
这⾥我们肯定有办法解决,⽐如:雷和⾮雷的信息不要使⽤数字,使⽤某些字符就⾏,这样就避免冲突了,但是这样做棋盘上有雷和⾮雷的信息,还有排查出的雷的个数信息,就⽐较混杂,不够⽅便。
这⾥我们采⽤另外⼀种⽅案,我们专⻔给⼀个棋盘(对应⼀个数组mine)存放布置好的雷的信息,再给另外⼀个棋盘(对应另外⼀个数组show)存放排查出的雷的信息。这样就互不⼲扰了,把雷布置mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且打印show数组的信息。
同时为了保持神秘,show数组开始时初始化为字符 '*',为了保持两个数组的类型⼀致,可以使⽤同⼀套函数处理,mine数组最开始也初始化为字符'0',布置雷改成'1'。
因此对于我们上述打印出扫雷界面,则是,存放排查出的雷的信息,而布置雷的数组,则不打印出来。
首先我们就要再创建一个二维数组,代表雷的信息,同时我们不把它打印出来
后面就开始对mine数组布置雷
与前面一样,我们首先在game.h中定义
在game.c中实现函数
对于布置雷,我们要明白首先几个条件就是:
1.雷的坐标要随机
2.雷的坐标在9x9内
3.雷的个数要适量
对于随机我们可以用随srand函数解决,如果大家不知道srand函数,可以去翻翻我的 《猜数字详解》这篇文章,里面详细说明了srand函数的使用,在这里我就不再赘述了。
同时要使雷的坐标在9x9内可以用rand函数,详细也可以参考我的 《猜数字详解》这篇文章。
雷的个数很简单,就是布雷循环多少次,就代表几个雷。

5.排查雷

排查雷的话,首先就是要输入坐标,如果输入的坐标是雷的话,结束,如果不是,就返回,周围雷的信息,结束条件还有一个就是所有雷完全被排除。
输入坐标很容易,怎么判断这个坐标是不是雷,我们知道mine数组里面存储的是雷的数据,而‘1’代表就是雷,因此,我们可以把mine数组传过去,把坐标代入,判断就行了,循环条件的话,棋盘大小--雷的个数。

当这个坐标不为雷,该怎么进行,我们知道当这个坐标不为雷时,会检查周围有几个雷,并把数字打印在屏幕上,我们可以对坐标周围进行相加减去周围不为雷时候,就可以得出周围有几个雷,由于,雷代表的是字符,因此我们需要+‘0’,表示数字,对于周围有几个雷的个数,我们也可以封装成一个函数,代码如下

到此我们简易的扫雷游戏就完成了。

下面是扫雷游戏的扩展,有兴趣可以去尝试一下

是否可以选择游戏难度
简单 9*9 棋盘,10个雷
中等 16*16棋盘,40个雷
困难 30*16棋盘,99个雷
如果排查位置不是雷,周围也没有雷,可以展开周围的⼀⽚
是否可以标记雷
是否可以加上排雷的时间显⽰

6.结语

看完这篇文章以后,你是否对前面的知识有了一个更深刻的理解,对于扫雷,没必要强求一下就学会,不过到后面还是要自己写出来,加油!!!

  • 10
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值