【C语言入门篇】C语言实现简易扫雷游戏
🌈个人主页:开敲
🔥所属专栏:C语言
🌼文章目录🌼
0.实现过程所用到的C语言知识
C语言分支与循环、二维数组、函数
1.首先我们来了解以下什么是扫雷游戏
这就是扫雷游戏的主页面,可以看到,基础版的扫雷由9*9的格子组成,格子当中的内容我们不得而知,当我们随便点击一个格子时
就会显示出一大片区域,同时,还会显现出一堆数字,这些数字代表着他们所在位置的周围8个格子内有多少颗雷,比如:
红圈中的1代表着他周围的8个格子内,也就是蓝色圈范围内有一颗雷,那么很显然,蓝色圈内只有一个格子的未显现,因此,那个格子就是雷,同理,数字2代表周围8个格子内有2颗雷。而我们要做的就是找出所有不是雷的格子,找完就赢了,如果找到的是雷,那么就输了。
2.扫雷游戏的主体框架
2.0文件的创建
在开始写代码之前,我们需要创建三个文件来完成代码的实现,分别是一个头文件(game.h),两个源文件(game.c和text.c)。在头文件里面,我们实现函数的声明,在源文件text.c里面,是我们游戏的主体,在源文件game.c里面,是我们游戏各个模块逻辑的实现。
2.1 游戏菜单界面
为了使得游戏具有仪式感,游戏菜单界面的打印肯定是必不可少的,在text.c中我们写进如下代码
这里我们创建了一个菜单函数,因此我们要对其进行定义,该函数较为简单,直接写在主函数上方即可
这样我们的菜单就打印完成了,接下来要判断是否开始游戏
不论如何,游戏的开始至少要打印一个游戏菜单界面,因此,这里采用了do while 循环,根据输入的input的值来判断是否进入游戏,输入1则进入game()游戏主体,输入0则退出游戏,输入非1非0则提示输入错误。接下来,就要实现游戏的主体部分了。
2.2创建二维数组实现扫雷界面
首先我们要使用二维数组来实现我们扫雷的游戏界面,需要用到两个数组,一个用来放置雷,不对外显现,一个用来对外显现,分别是mine和show在text.c文件主函数的上方写出game()函数,在函数内部创建二维数组,那么二维数组的行和列如何定义比较好呢。这里我们可以在头文件中使用宏来定义这样定义的好处是,当我们想要扩展棋盘的时候,只需要改变这里的数值即可。(这里不明白没关系,讲到后面都会明白的)
这样我们就可以使用ROW和COL的值来作为二维数组的行和列了,但是,我们想要实现9*9的扫雷就不能只创建9*9的二维数组,因为当我们在扫雷的时候,需要排查周围8个格子有多少课雷,因此当我们排查到边界的格子时,就会导致二维数组越界,因此,创建的时候,我们需要创建11*11的二维数组,向外扩展一圈。因此还需要定义一个宏
我们二维数组创建的行和列就使用ROWS和COLS但是当我们使用的时候会发现,编译器报错了。这是因为,我们是在头文件game.h当中定义的,源文件中想要使用必须要包含头文件,所以只需要包含一下头文件即可,同时,我们在头文件当中也已经包含了<stdio.h>的头文件,因此,只要我们在两个源文件当中都包含game.h的头文件就不需要包含其他的头文件了,只需要在game.h中添加就行
这样,我们实现扫雷所需要的二维数组就创建完毕了。
2.3初始化二维数组
接下来我们需要初始化数组来为后续作铺垫
这就是两个初始化的函数,我们需要在头文件game.h中声明,在game.c中实现
这里可以发现,我在创建函数的时候多穿了一个'*'和'0'参数,这样做的好处就是我想让哪个数组初始化成什么就让哪个数组初始化成什么,不会写死导致两个数组初始化成一样的。接下来,就在game.c里实现这个函数写一个for循环,从第1行到第rows行,第1列到第cols列,全部初始化为形参所接收的实参
接下来,需要写打印数组的函数。
2.4打印数组
创建打印数组的函数细心的你肯定发现了我在创建的时候,并没有传ROWS和COLS,而是传ROW和COL。这是因为,虽然我们创建的是11*11的数组,但是实际我们要看到的是9*9的界面,因此,只需要打印9*9的大小即可,接下来实现函数这里同样使用for循环打印第1行到第row行和第1列到第col列的值,值得注意的是,这里打印使用的是%c,因为我们数组初始化的就是字符'0'和字符'*',下面看看运行效果
为了美观,我们还可以在每行每列的前面加上行标和列标以及游戏标题
运行效果
这样,数组的打印就完成了。这里说一下,接下来埋雷的操作是在mine数组当中埋入,因此,mine数组在实际的游戏过程中不会显示出来,显示给玩家的是show数组,因此,这里可以将Display(mine,ROW,COL)函数注释掉,只打印show数组。
2.5埋雷
接下来我们要进行埋雷的操作,首先需要知道埋雷的个数,以及埋雷的位置。首先是埋雷,埋雷的个数我们可以像前面定义ROW,COL一样,使用宏定义的方式定义,这样后续想要更改雷的个数会非常方便。
然后是埋雷的位置,埋雷需要做到随机,也就是每一局的游戏雷的位置都不相同,因此这里我们需要用到rand()函数来为我们生成随机数,要用rand()函数需要调用srand()
(这里的srand函数不作解释(因为我也还没学到),会用即可)。
调用srand函数后就可以写埋雷的函数了
因为rand()函数生成的是0~32767之间的数,因此,将rand()函数生成的数模上9余下的就是0~8的数,再加上1就是1~9的数了,然后将生成的数作为行和列的坐标进行埋雷。埋雷使用while循环,同时初始化count的值为需要埋雷的个数,通过判断count是否为0选择是否进入循环埋雷。埋雷时,需要判断当前坐标下是否已经有雷了,如果该坐标下的字符为'0',则说明该位置尚未埋雷,埋完一个count就减1,知道埋完全部count变为0。
运行效果
2.6扫雷
接下来就是最后的环节——扫雷。扫雷功能最为复杂,主要分为判断输入坐标是否合法、合法坐标下是否为雷、合法坐标下周围雷的个数、扫完全部雷后的游戏胜利。
首先时第一步,写出扫雷函数,扫雷需要在mine数组中进行操作,同时还会用到show数组。
然后判断x,y坐标是否在合法范围内
若在合法范围内,判断是否为雷,是雷则游戏失败
如果不是雷,则判断周围雷的个数,并且将雷的个数显示在show数组当中,这里需要写个函数来辅助完成
GetMineCount()函数的作用是统计该坐标下周围8个格子内雷的个数,因此需要用到mine数组。这里的GetMineCount()函数直接写在FindMine函数上即可。
因为需要统计雷的个数,因此函数类型为整型。
这里要统计周围8个格子雷的个数就需要知道周围8个格子的坐标
这样就可以找出周围的8个坐标,然后统计大小
将周围八个坐标的值相加放入sum中即可统计出大小。这里有个重点,可以看到,每次sum+=的值都减去了'0',这是为什么呢?因为,在mine数组当中存储的不是数字0和1,而是字符的'0'和'1',而字符在内存中存储的是ASCII码值,因此,要转换为数字的话,只需要减去字符'0'即可(这里不懂的可以去查一下ASCII码表,自己试着算一下),然后返回sum的值,然后用一个变量来接收GetMineCount函数的返回值
然后将show数组内对应坐标下的内容更换为count,但是并不是单纯的直接把count放过去,因为数组的类型是char类型,因此需要存放的是字符数字,因此,只需要再将count的值加上'0'即可,然后打印出查询后的show数组内容。
当然,查询坐标是反复的,因此,要将其写进循环,那么循环的条件是什么呢?显然,当我们查询完所有的非雷坐标后,游戏便会胜利,这时,循环便结束了,因此,我们可以算出非雷坐标的个数,用一个变量接收,每次查询到非雷的坐标则减1,直到减为0循环结束。
这样,扫雷函数也就完成了,我们可以通过设置雷的个数来检验是否正确。这样,简易版扫雷游戏就算完成了。