用C语言来实现简易的扫雷游戏(详细讲解)

前言

扫雷游戏想必大家都听说过,或者上手玩过,没有接触过的话,就让我先简单的介绍扫雷的基本玩法:

游戏目标:

尽快找到所有地雷的位置,并标记出来,同时避免点击到地雷。当所有非雷的方块都被打开时,游戏胜利;如果误点到地雷,则游戏失败。

游戏操作:

如果点击到的方块下面没有地雷,方块会显示一个数字或者空白。数字代表该方块周围的 8 个相邻方块中地雷的数量;如果显示为空白,表示周围 8 格内没有地雷;如果不幸点击到有地雷的方块,地雷就会 “爆炸”,游戏结束。

介绍完毕之后,现在我们可不可以自己来编写一段程序,来实现简易的扫雷游戏呢?下面我们开始动手实践:

我使用的编译器是VS 2022

1.扫雷游戏的实现和分析

1.1.使用控制台实现简易的扫雷游戏,所以我们要打印出棋盘,9*9格式或者13*13格式;

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

1.3.游戏中的雷的布置是随机的;

1.4.排查雷

现在,先来看看我们要实现的效果:

2.棋盘的实现

本次设计一个9*9的棋盘,在扫雷的过程中,雷的布置和雷的排查,它们的信息都需要被存储,所以我们需要一定的数据结构来存储这些信息,因为是9*9的棋盘,所以首先容易想到的就是创建一个9*9的二维数组来存放信息:

扫雷游戏中肯定有雷与非雷的区别呀,那么,我们该怎么来表示雷与非雷之间的区别呢?这样,我们用字符‘1’来表示雷,字符‘0’来表示非雷。好,雷与非雷之间已经区别开来,但是,我们又遇到一个问题,我们要扫雷呀,怎么实现向扫雷游戏那样点击到的方块下面没有地雷,方块会显示一个数字或者空白呢?并且当显示你所点击的区域范围内存在一个雷时,要与雷区别开来,因为雷是用字符‘1’来表示的,存在1个雷和点击处就是雷,这两者之间无法区别,那么,怎么解决这个问题呢?我们可以创建两个数组,一个用来布置雷,一个用来显示玩家游玩时的棋盘,并且棋盘上用字符‘*’来初始化棋盘,这样问题就解决了。然而,我们怎么统计点击处附近存在多少雷呢?

如上图,当我排查内部时,很容易就统计出了周围存在几个雷,但是,当我排查棋盘的边缘时,该怎么统计呢?有的人就说,直接像内部统计雷那样统计就行了呀!但是,有没有想过你怎么知道在数组范围外,所存储的数据是什么,这可是越界访问了呀。所以,该怎么解决这个问题呢,或者说,怎么让它不越界访问呢?只要9*9范围外的一圈都是数组的就行了呗,也就是创建一个11*11的数组,打印棋盘时就打印9*9范围就可以了:


3.用代码来实现

1.创建一个菜单

菜单的功能有进入游戏和退出游戏两种:

怎么实现选择功能呢,可以使用switch语句,然而为了实现多次游玩的效果,可以再使用do while循环,并且编写一个函数game(),之后所有的函数都从它那里调用:

当输入的数字既不是1,也不是0时,给予提示。

2.初始化棋盘

由之前的分析可知要创建两个字符二维数组,且行列都为11,但是为了之后方便改写棋盘的大小,我们可以用#define来定义几个常量

为什么还要定义两个常量来表示9呢,因为之后我们打印的棋盘是9*9的格式的,之后想要加大难度,改为50*50的就更方便了。

数组如图所创建。boom数组是用来存放雷的,show数组是用来给玩家展示的

下面开始初始化棋盘,雷棋盘和展示棋盘都要初始化,所以有

将整个棋盘都要设计成自己想要的样子,所以要传ROWS,COLS作为参数;

二维数组用双层for循环来初始化,由上文提到,雷棋盘先全用字符‘0’来初始化,之后在用字符‘1’来填充,作为雷;展示棋盘用字符‘*’来初始化。那么问题来了,光标所指的地方该写什么?是字符‘0’,还是字符‘*’,显然无论是哪个都不行,否则要创建两个InitBoard函数,一个用‘0’,一个用‘*’,如何解决这个问题呢?只要在传参时,将自己要初始化的字符作为参数传给函数就可以啦

3.打印棋盘

初始化棋盘完成后,来打印以下棋盘来看看初始化是否成功,使用两层for循环就可以将二维数组中的每个元素打印出来,因为我们要打印的是9*9的棋盘,所以传参时,传ROW,COL:

打印出的结果如下图:

(“展示棋盘”和“雷棋盘”,这串字读者可以不用打印出来,这里打印是为了更好的观看)

但是,大家有没有注意到这样打印不方便我们输入坐标来排雷,每次要输入坐标的时候都要自己用肉眼数,太过于麻烦,怎么使它变得容易呢?只要将坐标打印出来即可:

按照图示来编写代码,首先我们要先打印行,0~9一个for循环就可以解决,注意这里打印完毕后,需要换行,避免使棋盘错位:

接着打印列,由图可知,列的标号是先于棋盘打印的,所以代码可以如下编写:

我们要打印9*9的棋盘,所以下标都从1开始。打印每一行后,记得换行。打印的0和*都是字符,所以使用占位符%c。


4.布置雷

雷是布置在雷棋盘中的,并且是在9*9的范围内布置,所以函数传参为:

布置雷最重要的就是随机布置,也就是生成随机坐标,坐标随机了,按坐标所布置的雷也就随机了。那么,如何产生随机数,C语言为我们提供了两个函数:rand()srand()可以生成随机数。但是,随机数生成的范围太大了,而我们只需要生成1~9之间的数字,要解决这个问题,只需要rand()%r + 1,rand()%c+1,二者分别生成横坐标和纵坐标的随机数,若想要了解两者函数,可以根据网址了解:rand - C++ Referencesrand - C++ Reference,了解函数后,我们知道,srand要生成随机数需要一个可以变化的种子,依赖这个种子就可以,那么什么是随时变化的呢,那就是时间。由此,我们需要借助time函数来实现我们想要的功能,想了解time函数,可以访问:time - C++ Reference

随机数解决完毕后,现在可以定义雷的数目,我们可以像前文那样,使用#define来定义常量

雷是由‘1’来表示的,并且布置点还没有雷;要设置完我们预定的雷的数量,我们可以使用while循环,所以我们可以如下编写程序:

每当布置完一个雷后数量就减1,if的判断,就避免了雷布置在同一块位置。下面,我们将布置雷后的棋盘打印出来:

由两图比较可知,雷的分布是随机的,并且每一局都是如此。


5.扫雷

现在来到最后一个环节---扫雷。

(1).现在来分析扫雷,首先,我们肯定要自己输入坐标,所以要创建2个变量x,y;

 其次还要判断我们输入的坐标,是否合法,也就是说是否在大于等于1,小于等于9这个范围 内;即便在这个范围内,还要判断输入的坐标在棋盘上是否是雷的坐标,也就是判断  boom[x][y]是否等于‘1’,等于就炸死了,游戏结束,并且打印出雷棋盘;

(2).倘若不等于‘1’,那就要开始统计该坐标八个方位存在几个雷,为了方便,我们可以创建函数SumBoom来统计,并且将函数的返回值赋值给show[x][y],毕竟我们扫雷的时候看到的棋盘是show数组,如此以来,我们便可知道扫雷函数的参数是哪些了;

(3).要达到反复扫雷的效果,可使用while函数,那么循环的终止条件是什么?我们可以定义一个变量sum来统计我们扫雷正确的次数,也就是在雷有10颗的情况下,sum小于71时,就一直循环,直到达到71,若达到71,可视为游戏胜利。

分析完毕,开始实现:

注意:在创建函数SumBoom时,返回的是整数,但是数组所存储的元素都是字符类型,要转换为对应的整型只需要在它基础上减去一个字符‘0’即可;其次,show数组所存放的数据类型都是char类型,所以返回值要加上字符‘0’,来转换成对应的字符型。

4.总结

现在将所有的代码展示出来,供大家参考:

运行游戏:


其实,这个代码之所以叫做简易扫雷游戏,是因为它没有向网页版的一样,一点开就扫出一大片,要想达到此效果,可以使用递归来实现,篇幅很长感谢你的耐心看完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值