浅析C语言扫雷游戏

(注明:作者C语言刚刚入门,也是刚学会扫雷游戏,因能力有限,博客内容难免会出现错误或不完善之处,欢迎读者们批评指正!!!)

一、扫雷游戏涉及的知识点:   

                                                                                                                                                              1.数组。扫雷游戏设计了两个二维数组(一个用来设置雷,一个用来作为玩家的主界面来排雷),所以需要掌握对二维数组初始化、二维数组传参等知识。

2.函数。扫雷游戏对函数的概念、形参和实参、数组作为函数的参数和函数的声明与调用等有较高的要求,所以新手需要熟练掌握这些知识点。

3.分支与循环。数组在游戏效果上的实现十分依赖分支与循环,同学们需要掌握if语句、for语句、while语句、do while语句等。

4.文件的管理。为了写代码的便利和整篇代码的整洁度,扫雷游戏的代码分为三个文件(test.h ,game.c ,test.c  具体作用后续解释)

二、扫雷游戏对于初学者的难点     

                                                                                                                                                         1.游戏的设计思路。可以通过想象游戏的效果将复杂的游戏流程拆分,一个一个进行攻破。

 2.新奇的设计方法。扫雷游戏需要两个不同的数组(一个数组设置雷的位置,一个数组来表示游戏界面,并完成后续排查雷的任务)。扫雷游戏需要通过新奇巧妙地设计方式将这两个数组关联起来,并且在部分代码实现同一个函数控制两个数组。

 3.变量增多以及一些函数名称等英文增多可能会将初学者绕晕(我就这么被绕晕过),此时要将思路理清,清楚自己现在做到哪一步即可。

 4.耐心。第一次试着写扫雷地代码时会遇到多种多样地问题,这非常考验初学者的耐心!第一次的时候可以边写,遇到不会解决的问题时再参考标准代码,搞清自己哪里不会做,哪里理解错了。过一段时间再次尝试不参考标准代码自己完整写一遍。

三、游戏的效果实现                                                                                                                  

1.主界面。进入程序应该先给玩家展示菜单(进入或退出游戏),玩家做出选择后执行命令。 

 2.排查雷的界面。进入游戏后展现出的应该是空白的扫雷单元格(C语言中用“*”代替)                   (如下左图所示:)

 3.界面的变化。当输入排查雷的坐标时,系统应该显示数字(数字表示周围雷的个数),即用字符替换星号。(如上右图所示)

 4.游戏成功与失败的判定。当排雷坐标是设置雷的坐标,系统自动判断玩家被炸死,并显示出所有雷的位置,然后游戏结束;当所有非雷的坐标都被排查完毕,系统应该判断玩家游戏成功。

四、游戏代码设计的大致思路                                                                                                             

首先要设计三个文件(game.c    test.c     test.h)

1.game.c 作用:执行进入游戏后系统应该完成的任务(即第三大点的2、3、4)

2.test.c 作用:包含主函数,打印主界面,作为游戏函数的载体保证整个游戏代码的执行。

3.test.h 作用:函数的声明、头文件的包含、定义行与列。

五、扫雷游戏代码的全设计流程

                                                   (1)test.c

1.主函数的设计。首先引入菜单函数打印主界面,然后通过让玩家输入数字来决定是进入游戏还是退出游戏。

2.然后我们开始写菜单函数的代码。注意,在设计主界面时要注意输出效果的美观性。(如下图所示,一个很简单的打印函数)

·ctrl Fn+F5看一下主界面的效果:(美观性还是不错的)

这样,test.c的任务已经完成了。接下来我们将要处理最难的一部分代码了:

(2)game.c

代码实现:


具体步骤:

1.创建两个二维数组。                                                                                                                     前面我们提到了,扫雷游戏需要创建两个数组(mine数组用来设置雷,show数组用来作为游戏开始之后的界面),所以game.h一开始就要创建两个数组:char mine[...][...]和 char show[...][...]。“...”表示行和列元素的个数,例如如果想创建一个9*9的扫雷棋盘,那么就应该是char mine[9][9]和 char show[9][9]。

这个时候我们想一下,我们在设置雷之后必然会有一个系统自动计算排雷坐标周围雷的个数这样一个过程,如果我们只设置9*9的二维数组,那么在棋盘边缘的坐标要排查雷就会变得比较困难。

像上面这张图,数字“1”表示经过系统排查周围八个坐标,只有一个雷。所以我们写的排查雷代码的功能即为判断周围八个坐标雷的个数,这个时候如果遇到处在边缘的坐标那就很不好判断了,因为我们需要判断的所选坐标周围的八个坐标,这个时候必然会有坐标“出界”,不在我们定义的范围内。为了解决这个问题,我们可以在游戏界面(也就是9*9的界面)外面再加一圈棋盘,如下图:


注意:外面多加的这一层绿色的边界在游戏中是显示不出来的,而是为了方便系统在“后台”计算雷的个数。所以,我们后续要做的初始化是要将棋盘扩展到11*11,而打印游戏界面、设置雷、排查雷还是使用9*9的棋盘。

这里就会有一个问题:有时候需要9*9的棋盘有时候需要11*11的棋盘在同一个数组中是怎样实现的?观察代码实现图片中的内容发现我们是使用了ROWS,COLS,ROW,COL。这样做的目的是用一个可修改的量来代替单纯的数字,这样如果想修改棋盘的大小就不用一个一个地去改数字了。这样几个可修改的量要在头文件中定义地,如下图:

这样只要修改定义量后面地数字就能改变二维数组表示的范围,同时保证可以设置两种大小的数组

2.初始化函数。                                                                                                                                   根据游戏的效果实现所说,mine数组初始化时应该全是由字符‘0’组成,在设置雷的时候将雷用字符‘1’表示。而show数组是游戏界面,初始化的时候应该全部用‘*’表示,并且在后续第三点中打印出来。所以,现在初始化函数的任务很明确了:将mine函数全部初始化为字符0,将show函数全部初始化为星号。那么那么难点随之而来:怎样实现一个函数初始化两个函数?答案是引入一个新的变量set。

因为在引用函数的时候,mine函数和show函数加上了第四个参数:                                                   Startset(mine,ROWS,COLS,'0');//初始化mine函数
 Startset(show, ROWS,COLS, '*');//初始化show函数                                                                          所以,初始化函数最终初始化数组为第四个参数。

3.打印函数。(printf)                                                                                                                         只打印show函数,向玩家展示游戏界面。

除了打印星号之外,还要跟着打印坐标以便玩家在玩的输入坐标。

4.设置雷函数(Setmine函数)                                                                                                           设置雷函数就是针对mine数组设计的函数,实现效果是让mine数组记录雷的位置。这个函数的难点在于要让系统自动设置雷的位置,也就是使系统随机找到若干个坐标并给这些坐标标记上“雷”的标识。这个时候就要用到 rand函数(生成随机数函数)来帮我们实现随机标记坐标的功能。

(1)首先复习一下要改变 rand函数的种子要引入 srand函数,要避免手动修改种子而使 rand函数种子时刻发生改变要引入 time 函数,也就是 srand((unsigned int)time(NULL))。                              (2)然后要随机选取坐标并标记为“雷”。代码实现如下图:                                                            

(3)所用的while循环中的变量count代表了期望设置雷的个数,可以自己调整count 的值来改变期望设置雷的个数。                                                                                                                              (4)注意:初始化数组时是设置的字符而不是单纯的数字,所以等号右边的数字要用双引号。

·设置完成后我们可以加一个打印 mine数组的代码看一下布置雷的效果:(1代表雷,0代表没有雷)

5.排雷函数(Findmine函数)

要注意,第四个步骤是给 mine函数设置的雷( show函数无法设置),而排查雷是利用show函数的界面排查,这里有一个关键点就是 mine函数要将雷的信息先提交给系统再利用 show函数去表达。所以Findmine函数中需要两个数组的参数。即Findmine(mine,show,ROW , COL)。

代码实现如下:

(1)我们注意到系统是如何表达存在mine函数中的信息:先让玩家输入想排查的坐标,再通过 mine函数来判断选择的这个位置是否是雷。是雷游戏直接结束,这个操作比较简单;难点在于如果不是雷要改变 show函数打印的游戏界面(即:将星号改成数字,数字表示所选取的坐标周围有几个雷)。这个时候就需要想办法让系统计算一个坐标周围雷的个数了。

(2)countmine函数计算一个坐标周围雷的个数。因为雷的信息都在 mine 数组里,这个时候所创建的新函数 countmine 就又要调用 mine 数组。大致思路是:将输入坐标周围8个坐标的值相加,再减去8*‘0’(因为数组里的数字是字符形式,所以不能简单地当数字相加减。每一个字符有一个对应的ASK码值,所以将字符相加再减去数字0对应字符的ASK码值就是数字值,而一个单位的数字值,也就是1,代表的是有一个雷。所以最后计算结果是几就代表周围有几个雷)。        countmine函数代码实现如下图:

(注明:这个代码把输入的坐标也放进去了,因为既然要统计周围雷的个数就说明了选取的坐标本身不是雷,可以在统计的范围中。)

(3)输赢的判断。当输入坐标与系统随机设置的雷的坐标一致时,系统显示你被炸死了并结束游戏;当排完所有的雷后,系统要自动判断玩家游戏成功。

六、扫雷游戏初步代码的完善

---------只存在一个棋盘界面                                                                                                              ---------能将可能是雷的位置进行标记                                                                                                  ---------周围没有雷直接展开                                                                                                                                                    

(1)只存在一个棋盘界面。可以使用桌面清理函数 system("cls"),这样,上一轮排查雷函数打印的界面就不会再出现。

这样玩家相当于就在一个棋盘上面操作了。

(2)雷的标记。在网页版扫雷游戏里,标记雷的方式是单击鼠标右键,这时游戏界面上会出现一个红旗的标志,代表这个位置是雷。

在C语言写的扫雷游戏里,我们也可以有相同的思路:每次排查完雷之后,可以给玩家一个标记雷的机会,玩家可以输入坐标,然后游戏界面中对应坐标就会由“*”变为“!”,代表这个位置被标记过了。代码实现如下图:

注意:每次有可能要标记多个坐标,这时我们添加一个 while 循环就可以解决。                               这个函数要被插入在 findmine 函数中(因为这个函数的指令要在每次输入完排查雷的坐标后进行),在完成 record 函数的指令后,还要再次打印棋盘展示出标记后的样子:

(3)周围没有雷直接展开。

扫雷游戏中,为了节约玩家的时间和提高效率会采用大面积展开的方式,如下图:

这一部分需要用到函数递归的知识。代码设计思路:

                                                                                                                                                                 1.首先我们还是对玩家排查的坐标进行判定,如果是周围有雷,就直接显示出雷的个数,不用进行展开的操作了;如果系统发现展示的数字是0(代表这个坐标周围没有雷),那么此时就要对这个坐标周围八个坐标进行展开。                                                                                                           2.展开后又要对周围八个坐标每一个坐标进行判定(当然有可能最开始排查的坐标就是在棋盘边界线上,这个在代码里给定一个范围即可),判定内容还是第一点所展示的。所以,这样一种套娃式的效果需要用函数递归来完成。(代码如下图)

从上面的代码我们发现:当周围没有雷的时候,我们是把show 数组中的星号换成了空格,这样产生出来的效果也类似于网页版扫雷。递归函数在代码中的具体位置如下:

递归函数其实是之前初步扫雷游戏代码的升级(原来printboard函数后面接的应该是将show数组对应坐标由星号改为周围雷的个数,而现在接的是expand 函数),expand 函数包含了将星号改为周围雷的个数这一步骤,多的内容就是判定坐标周围没有雷后进行的函数递归。

总结:

扫雷游戏的代码是由好几个小部分代码组成的,这几个小代码块各司其职,将一个复杂的问题拆分为几个相对简单的问题。小代码块比较难的是初始化两个不同数组的思路、递归函数等,耐心研究攻破某部分的难题最后一定能拼接为一个完整的高效代码。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值