1. 前言
扫雷,相信大家并不陌生,这是一款充斥着童年回忆的经典益智游戏。它能锻炼我们的思维,完成游戏也可以获得巨大的成就感。
本篇博客将采用C语言来模拟实现简单的扫雷游戏,以纪念我心目中的怀旧游戏No.1!
2. 整体思路
扫雷游戏棋盘大小:9 * 9
扫雷,不仅需要自动布置雷,而且需要输入坐标进行雷的排查,排查后需要在排查点展示周围八个点雷的个数。
所以我们需要用二维数组来表示扫雷的棋盘,但仅仅定义一个棋盘,那么在一个棋盘中需要表示的要素太多,且在排查雷时难度过大。
所以我们不妨换一种思路,使用两个棋盘,棋盘一用来放置雷,棋盘二用来存放排查后的数据。
棋盘分工:
棋盘一:非雷用0表示,雷用1表示,此棋盘不暴露,仅仅用来布置雷而已。
棋盘二:排查位置周围雷数用数字表示,未排查部分均用*表示,此棋盘需要在每次排查后展示。
示意图:
但是进行排查时,对于边界部分。对周围元素进行访问时,如果大小定为9 * 9
会出现数组访问越界
的情况,所以我们将行和列的大小调整为11 * 11
,最后打印时打印中间区域即可。
示意图:
3. 游戏分工
该项目分为三个文件:
test.c
:游戏的逻辑game.h
:函数声明,符号的定义game.c
:游戏的实现
其中game.h,game.c为游戏模块,test.c为测试区域
4. 游戏菜单
依然是大家熟悉的菜单界面。
游戏开始前,需要有菜单来供玩家选择进入游戏,游戏至少进行一次,因此使用do...while
循环。
对应代码:
void menu() { printf("**********************************\n"); printf("************* 1.play *************\n"); printf("************* 0.exit *************\n"); printf("**********************************\n"); } int main() { int input = 0; do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: printf("扫雷\n"); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,请重新选择\n"); break; } }while(input); }
运行结果:
5. 游戏功能
友情提示:
以下模块均用于实现游戏功能,对应的功能均在test.c的game()函数中调用、game.h中进行声明和相关常量的定义,函数功能在game.c中实现。
在.c文件中均需引自定义的头文件#include"game.h"。
对于函数的声明我会省略,以下模块展示的内容主要为在game.c文件中实现的游戏功能。
5.1 前提准备
扫雷棋盘打印大小为 9 * 9
,但在排查雷时,数组容易越界,为避免越界,我们将每个边界周围加上一行或一列,数组大小定义为11 * 11
,打印时输出9 * 9即可:
#pragma once #define ROW 9 #define COL 9 #define ROWS ROW + 2 //11 * 11 #define COLS COL + 2
5.2 棋盘的初始化
- 布置雷的棋盘的初始化:将元素都初始化为
0
- 排查雷的棋盘的初始化:将元素都初始化为
*
思路:由于初始化的元素不同,所以在传参时可以把想初始化的元素传过去,在函数用字符类型进行接收。
test.c文件中的准备:
void game() { //布置雷的棋盘 char mine[ROWS][COLS] = { 0 }; //排查雷的棋盘 char show[ROWS][COLS] = { 0 }; //初始化棋盘 init_board(mine, ROWS, COLS, '0');//雷盘初始化为0 init_board(show, ROWS, COLS, '*');//展示盘初始化为* }
对应代码:
void init_board(char arr[ROWS][COLS], int rows, int cols, char set) { int i = 0; for (i = 0; i < rows; i++) { int j = 0; for (j = 0; j < cols; j++) { arr[i][j] = set; } } }
5.3 布置雷
思路:
对于雷的布置,我们仅需要布置9 * 9区域的雷即可。
布置雷的个数为10个,我们采用定义的方式,方便随时修改雷的个数,雷的个数需要在头文件中定义:#define EASY_COUNT 10
自动随机值的提供需要利用时间戳来完成,利用rand、srand、time函数来完成相关操作,srand函数在test中调用,布置雷的坐标为1-9,因此随机值表现形式为:rand() % row or col + 1
雷的布置采用循环的方式
对应代码:
void set_mine(char mine[ROWS][COLS], int row, int col) { int count = EASY_COUNT; int x = 0; int y = 0; while (count) { x = rand() % row + 1;//1-9 y = rand() % col + 1;//1-9 if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } }
5.4 打印棋盘
对于棋盘的打印,我们只需要打印出分隔线和对应的坐标即可。
思路:
- 棋盘打印依旧是 9 * 9。
- 棋盘只需打印
存放排查后数据的棋盘
,不要暴露布置雷的棋盘,否则就被看到结果了。 - 需要对棋盘对应的行列进行打印,方便玩家查看坐标。
- 使用分隔线,避免上下棋盘黏在一起。
对应代码:
void show_board(char arr[ROWS][COLS], int row, int col) { int i = 0; printf("------------扫雷------------\n");//分割线 for (i = 0; i <= col; i++) { printf("%d ", i);//输出对应列信息 } printf("\n"); for (i = 1; i <= row; i++) { int j = 0; printf("%d ", i);//输出对应行信息 for (j = 1; j <= col; j++) { printf("%c ", arr[i][j]); } printf("\n"); } printf("------------扫雷------------\n"); }
打印效果: