数组与函数的实践:扫雷游戏

一、游戏分析与设计

1、扫雷游戏实现的逻辑

       在写一个代码之前,我们需要去分析这个代码的基本逻辑,搞清楚我们该如何从0一步步去实现它。扫雷游戏相信大家都玩过,它是在一个x*y的棋盘上来进行游戏的,一般是9*9的棋盘,而棋盘越大,难度就越大,这里我们暂时不考虑更高难度的扫雷游戏,就以9*9的大小来实现扫雷游戏。

       那我们就先从扫雷游戏的步骤开始分析,首先我们需要点击棋盘上的一个小方块,系统收到我们的指令之后会对这个位置进行判定,如果是雷那么我们就会被炸死,如果不是雷那么就会显示这个位置周围的雷的个数,然后我们再根据它给出的信息将所有的雷找出来即为游戏胜利。那么根据以上信息我们可以发现首先我们需要创建一个空间来容纳游戏空间,即棋盘,那么我们就可以把这个空间视为一个二维平面,而上面的小方块则是空间上一个个坐标。因此我们可以很容易想到利用二维数组来表达这个空间,数组中每个数的下标即为坐标。然后就是输入坐标之后对坐标的判断了,首先判断是否是雷,然后判断周围雷的个数,再给出反馈,最后是对游戏胜利条件的判断。

2、代码实现的结构框架

       那么扫雷游戏实现的逻辑分析完了,接下来就需要对代码的结构框架进行构思并理清其中较难实现的代码的实现逻辑。

结构框架:

       当我们进入一个游戏的时候,首先先看到的是自然是开始界面,当然由于本人技术不足,所以只能使用控制面板来实现整个游戏的运行,所以开始界面就一切从简。那么开始界面创建好之后我们肯定得创建一个二维数组来存放游戏所需要的棋盘,然后对这个数组进行初始化,再在棋盘上布置好雷,最后就是排雷以及对排雷坐标的判定。

难点一:

       在创建了一个二维数组之后我们来思考一下:这一个二维数组要同时容纳存放雷的坐标,排查出的位置的坐标,反馈给玩家的棋盘这么多的信息,那么我们该如何做到呢?很显然这是很难的(初学者,不太清楚到底可不可以)。那么我们不妨再创建一个二维数组,一个用来存放雷的坐标信息,一个用来存放排查出的位置的坐标。

难点二:

       在我们玩扫雷游戏的时候,当我们点击一下之后,如果那个位置不是雷,那么就会显示出它周围雷的个数。那么在这里我们该如何去实现这个功能呢?首先我们取棋盘上一点,坐标为(x,y),那么它周围一圈的点的坐标从上往下,从左至右为:(x-1,y-1)、(x-1,y)、(x-1,y+1)、(x,y-1)、(x,y+1)、(x+1,y-1)、(x+1,y)、(x+1,y+1)。那么包含这个点在内,这就是一个3*3的矩阵。那么这样我们就可以以(x,y)为基点,利用for循环,if判断来实现坐标周围雷的个数的判断。那么如果我们写到这就结束了的话,那我们在运行的时候就会发现会打印出来乱码,这是因为当坐标点位于棋盘的边缘的时候它的周围的坐标点会有一部分不处于数组内,在计算周围雷的个数的时候就会出现错误,既然如此,那我们不妨在数组外面再加一圈,即创建一个11*11的数组,这样在计算周围雷的个数时既使所有的坐标都位于数组中,多出来的一圈还不影响计算。

二、代码实现

       在写一个项目的时候我们要注意不能把所有的代码都写在一个文件里面,如果我们写的是一个大型项目,那动辄几千几万行甚至更多的代码都放在一个文件中你想一下看起来会有多臃肿?其他程序员看起来会有多费劲?因此我们要将实现不同功能的部分分别放入不同的文件中,这样也能方便后续更改。在这个代码中我将游戏的界面,实现游戏的逻辑放在text.c文件中。实现游戏的代码放在game.c中。引用的库函数,需要声明的函数放在了game.h中。

1、游戏界面代码的实现

       首先,我们要来打印游戏界面,那么这一步是无论后面我们怎么操作都要先进行的一步,所以在这里我们可以使用do-while来达到想要的效果。

 这就是游戏界面部分的代码,有兴趣的小伙伴可以自己再对其进行优化,让游戏界面更加好看。

2、创建二维数组并进行初始化

       那么接下来就是游戏的主体部分了,在上面我们也是创建了一个函数game,接下来的操作都在这个函数中来实现。

然后再是初始化

 

       在这里我们再次使用函数来容纳初始化数组的代码,这样我们就只用写一遍初始化代码就行了,第二次使用的时候只需要改一下传参就可以了。 注意:这时候初始化代码就需要放入game.c文件中,因为这已经是实现游戏功能的部分了。

3、生成随机数并布置好雷

       生成随机数可能有一些小伙伴不太明白,我就在这里简单讲一下,不做过多的赘述。生成随机数我们首先要引用一个库函数:<stdlib.h>。

这就是生成随机数的语句,rand函数会返回⼀个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的⼤⼩是 依赖编译器上实现的,但是⼤部分编译器上是32767。但是当我们去运行它的时候就会发现每一次的结果都是一样的,这是为什么呢?其实rand函数⽣成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法⽣成的随机数。真正的随机数的是⽆法预测下⼀个值是多少的。⽽rand函 数是对⼀个叫“种⼦”的基准值进⾏运算⽣成的随机数。 之所以前⾯每次运⾏程序产⽣的随机数是⼀样的,那是因为rand函数⽣成随机数的默认种⼦是1。 如果要⽣成不同的随机数,就要让种⼦是变化的。因此我们就要用到另一个函数srand来初始化随机数的⽣成器,从而生成我们想要的随机数。

       我们可以发现上面的srand函数中还有time函数,这是因为在程序中我们⼀般是使⽤程序运⾏的时间作为种⼦的,因为时间时刻在发⽣变化的, 函数time就可以获得这个时间。这时候rand函数所产生的就是真正的随机数了,但是需要注意的是time函数返回的类型是time_t类型的,time_t类型本质上其实就是32位或者64位的整型类型。这时候是不能被srand函数所识别,因此我们需要用unsigint int将time函数的返回值强制转化成int类型。

4、打印游戏棋盘

       打印棋盘我就不多赘述了,直接看代码吧。

5、扫雷的判定与反馈

       前面的代码写完之后就来到了扫雷游戏的第二个难点。按照前面我们所设想的代码逻辑,首先我们要先判断这个坐标是不是雷。

 如果这个点不是雷那么就进行下一个判断:判断坐标点周围有几颗雷。按照前面我们所分析的,将坐标点周围一圈看作一个3*3的数组,并且可以通过坐标点的下标来求出其它几个坐标点的下标,这时候就可以判断各个坐标是否是雷了。

在完成了对坐标点周围雷个数的判断之后,游戏的主体就已经写完了,接下来就是对游戏胜利条件的判断了。首先,这段代码肯定 不止运行一次,因此我们要将其放进一个循环里面去,在这里我们可以使用for循环也可以使用while循环。那么这个循环要运行几次呢?游戏的区域为9*9,也就是81个格子,放置了10个雷,那么当我们循环到71次的时候如果还没有被炸死那么我们就已经排出了所有的雷。同时这也可以作为游戏胜利的条件。为了后续更改方便,在这里我使用一个变量来表示循环的次数。

三、游戏的拓展

在写完之后我们也可以再对其进行一个拓展,让其与网页版扫雷游戏更加相似,如:

是否可以选择游戏难度:

简单:9*9棋盘,10个雷;

中等:16*16棋盘,40个雷;

困难:30*16棋盘,99个雷;

如果排查位置不是雷,周围也没有雷,可以展开周围的一片:

这个需要用到函数的递归,量力而行。

是否可以标记雷
是否可以加上排雷的时间显示
  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值