C语言实现简易的扫雷游戏

C语言扫雷游戏_toBlog

C语言实现简易的扫雷游戏

 

从玩家角度分析扫雷游戏:

游戏主要分为几个步骤: 运行程序==>开始菜单==>选择开始游戏或者结束游戏==>选择开始==>展示棋盘格==>玩家开始排查雷==>判断排查结果,如果是雷游戏结束,如果不是显示排查坐标周围有几个雷并且递归展开. 然后以此循环往复直到玩家胜利或者被雷炸死==>游戏结束

游戏设计的角度分析:

由于还没学到图形界面,游戏的实现暂时只能使用控制台完成, 为了实现整个游戏逻辑, 列出以下重要组成部分:

  1. 需要有可供玩家选择的开始菜单,简单实现 玩游戏或者退出游戏两个主要功能

  2. 扫雷的棋盘是9X9的格子, 使用二维数组的方式存储棋盘格信息

  3. 初始化棋盘后默认随机布置10个雷

  4. 玩家可以输入坐标排查雷

    • 如果位置不是雷,就显示周围有几个雷

    • 如果位置是雷,游戏结束

    • 把所有非雷全部排除出来,玩家获取胜利

游戏的界面:

0123456789
1*********
2*********
3*********
4*********
5*********
6*********
7*********
8*********
9*********
0123456789
1*********
2***00****
3**000****
4***010***
5***1*2***
6***00****
7*********
8*********
9*********

扫雷的过程中,布置的雷和排查出的雷的信息都需要存储,所以我们需要⼀定的数据结构来存储这些 信息。 因为我们需要在9 * 9的棋盘上布置雷的信息和排查雷,我们⾸先想到的就是创建⼀个9*9的数组来存放 信息。

如果这个位置布置雷,我们就存放1,没有布置雷就存放0.

创建工程

创建头文件 mine_game.h

源文件 main.c mine_game.c

" referrerpolicy="no-referrer" alt="image-20231206113109339">

搭建游戏框架:

主函数main.c创建运行逻辑,当游戏开始时会调用game()函数

在头文件game.h引入一些必要的头文件库

 

创建game.c文件为game.h上声明的函数补全定义

接下来开始构思函数game()的创建

在进入这个函数时,通过srand函数设置rand的随机钟子值,我们通常用time函数获取时间戳作为随机种子值

创建两组字符数组,定义两个字符数组,一组用来存放布置好的雷的信息,另外一组用来显示玩家的游戏进展界面,判断胜负也是由这字符数组判定得来

对二维数组的初始化就是定义棋盘格子的长宽,使用两个常量来表示ROW COL

所以再回到game.h添加常量的定义,顺便定义了场景中需要雷的个数MINECOUNT

考虑到游戏过程需要对棋盘格mineshow数组比较,判断玩家排查的地方是不是没有雷,如果有雷的话直接游戏结束。

如果没有雷的话,要遍历当前坐标周围的八个数组,计算出雷的个数, 并把值返回给show数组当前坐标显示给玩家

而如果对边界的坐标求周围雷个数必然会有访问越界的问题, 每一次检测循环加入对边界的检测虽然也能解决问题,但代码的逻辑判断又得增加.

目前的解决办法是给整个二维数组外扩一圈成 11(ROW+2) 11(COL+2)的数组,在这里分别定义ROWS COLS两个常量

确定好这些后,回到game.c先对两个数组分别初始化

mine 数组所有元素全部初始化为 '0'

show数组所有元素全部初始化为 '*'

定义一个专门用于初始化数组的函数

初始化完毕后,给mine数组布置上雷

使用DisplayBoard自定义函数查看两个数组的显示,测试运行确认是否无误

玩家开始排查雷,定义一个FindMine函数用于排查的整个过程

ClearAllAround(mine, show, x, y, &count);是自定义的一个函数:

在查询到的位置没有被排查过且不是雷的时候,开始递归向四周不断查询雷的情况,当遇到以下情况才停止递归:

1.当遇到9X9之外的边界的时候

2.到当前show[x][y]的坐标求得周围8个坐标分布至少有一个雷的时候

到这一步 基本就实现了扫雷的功能,game.c的代码如下:

 

完成扩展:添加标记功能

整个代码结构稍微调整

定义函数PlayerStep:

FindMine放到了该函数内部,并且整个排查雷的循环交给PlayerStep完成

PlayerStep函数通过while循环让玩家选择标记雷或者排查雷,玩家在每一步的开始都要选择排查雷或者标记雷,从而跳转到对应的函数

MarkMine是新创建的标记雷函数,每次运行都会返回整型1或者0用作游戏是否结束的分支判断

FindMine函数修改后如下:

修改后使函数返回一个整数类型的值

满足游戏胜利或被炸死的条件返回一个整数 1,实现跳出当前PlayerStep的while循环

判定剩余非雷个数的变量count拿到了最外面,因为整个排雷的循环移植到了PlayerStep函数中,如果继续放在FindMine函数体里面的话会造成每一个玩家步数都重置了count的值,现在是通过传指针的方式修改count

MarkMine函数内容如下:

MarkMine函数功能就是实现玩家对坐标的标记,统一符号为'M'.其内部也是通过一个循环判断玩家输入的坐标是否非法,如果非法,请重新输入. 非法的坐标有以下2点:

1.坐标超出范围

2.坐标对应show[row][col]的值不等于'*'或者'M'

满足以上条件后值为'*'的赋值为'M','M'的赋值为'*'.等于玩家随时可以标记和取消标记

最终判断标记的总量有没有等于雷的总量,如果满足条件执行比较函数compareMarket,当然同时也要限制标记的最大个数需要等同于雷的个数,防止玩家无限标记的方式赢得游戏

函数compareMarket用于比较mineshow数组,判断所有的标记是否都恰好是雷.条件满足则返回布尔值true判定玩家胜利,跳出PlayerStep循环开始下一轮游戏的.

 

 

完整代码如下:

game.h:
game.c:
main.c

评论