扫雷游戏
从上微机课开始,在没有网而且啥也不会的情况下,扫雷成了打发时间的唯一乐趣,玩过没写过,今天来试试;
需要实现的功能
- 显示周围区域 💣 雷的个数;
- 周围没有雷则自动展开;
- 剩下的全部为雷则自动胜出;
游戏实现的思路
0. 逻辑分析
- 布置雷,由于既需要存放布置雷的数据,又要展示隐藏雷后的数据给玩家,所以需要两个 char 数组,分别存放相应的数据;
- 排查雷,玩家输入坐标,如果是雷,结束游戏,如果不是雷,则显示周围雷的个数,如果周围区域都没有雷,则自动展开空白区域;
- 判定是否自动胜出;
1. main 函数
在 main 函数中写出程序的整体框架,然后再具体实现:
1 |
|
这里为什么要定义 ROW 和 ROWS 以及 COL 和 COLS 呢?以图为例:
如图,在后面需要统计以玩家输入的坐标为中心的九宫格(绿色区域)中雷的数量时,如果按照真实展示的网格(红色区域)来计算的话,数组下标会越界,所以在行和列的周围各增加一行或一列,初始化时全部填充为默认内容,这样就不会产生下标越界的问题了;
2. 菜单
1 | void display_menu() |
菜单简陋,聊胜于无;
3. 开始游戏
1 | void play_game(char mine[ROWS][COLS], char show[ROWS][COLS]) |
首先初始化布置雷的数组:将数组的元素全部填充为字符0
(不是数字 0),后面布置的雷则会填充字符1
(不是数字 1);
然后初始化展示给玩家的数组:将数组的元素全部填充为字符*
;
这两步的意义是:当玩家输入坐标后,用坐标去存储雷盘中匹配信息,如果是雷,则退出游戏,如果不是雷,则根据返回信息,在展示雷盘中显示周围雷的个数,如果指定范围没有雷,则自动展开空白区域;
最后,为了方便调试,将两个数组的信息都输出到屏幕上;
4. 初始化存储雷盘和展示雷盘
1 | void init_board(char arr[ROWS][COLS], int rows, int cols, char filler) |
上面的代码没啥好说的,遍历数组,然后用给定的字符填充;
1 | void display_board(char arr[ROWS][COLS], int row, int col) |
为了输入坐标时更直观,这里打印行序号和列序号;
至此,就可以测试一下了,输出初始化后的雷盘:
工整的显示,完美,同时也说明了打印列序号为何要从 0 开始;
5. 布置雷
雷盘有了,接下来就是布置雷了;
1 | void set_mine(char arr[ROWS][COLS], int row, int col) |
布置雷很简单,生成随机数后,只要坐标合法,就将存储雷盘对应的坐标位置由字符0
替换为字符1
即可;
布置完成了,测试一下:
数一数,刚好 10 个雷,与预定义的雷数量一致;
6. 开始玩游戏
获胜的规则很简单:雷盘中没有空白区域则获胜;
1 | void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) |
首先,获取用户输入,然后判断输入是否越界,越界则重新输入;
判断用户输入的坐标是否是雷,是雷则结束游戏;
如果用户输入的坐标不是雷,则进行如下操作:
以当前坐标为中心,计算周围 3 * 3 的九宫格中雷的数量,规则如下:
- 如果此范围中有雷,则将雷的数量写入展示雷盘对应的坐标中,游戏继续;
- 如果此范围中没有雷,则以当前九宫格的每个元素为中心,再次统计周围 3 * 3 的范围中雷的数量;
- 直到坐标周围有雷则结束展开空白区域;
7. 获取坐标周围雷的数量
1 | int get_mine_count(char mine[ROWS][COLS], int x, int y) |
字符0
的 ASCII 值为 48,字符1
的 ASCII 值为 49,以此类推,用任意数字字符的值减去字符0
就是这个字符的整型值,例如:’1’ - ‘0’ = 1;
8. 自动展开空白区域
1 | void show_blank_space(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int *p) |
9. 判断是否获胜
1 | if (win == ROW * COL - MINES) |
刚开始,写了一个计算胜出的函数,无非就是遍历数组的每个元素,判断是不是初始化时填充的字符(这里初始化时填充的是*
),如果存储雷盘中有初始化时填充的字符,则游戏继续,否则玩家胜出;
但这种方法性能太低了,每输入一次就需要遍历整个数组,所以这里使用了指针,每次输入且输入有效时,统计不是雷的坐标,然后用坐标总数减去雷的数量与统计的数量进行比较,如果数量相同,则说明剩下的都是雷了,玩家自动胜出;
10. 试玩 - 测试
为了方便测试后面的逻辑,将雷的数量设置为 80,也就是说只有一个不是雷:
自动胜出的逻辑正常,现在就差自动展开了;
自动展开正常;
11. 完整代码
1 |
|