目录
一、扫雷游戏规则介绍:
二、游戏功能分析及设计思路:
1 .游戏功能分析:
a.菜单(menu)模块:
b.游戏(game)模块:
2.所需文件:
三、代码实现:
1.菜单(menu)模块代码:
2.游戏(game)模块代码:
a.棋盘初始化(InitBoard):
b.棋盘打印 (ShowBoard):
c.地雷设置(SetMine):
d.获取周围地雷数量 (GetMineNumbers)
d.排查地雷(FindMine)
四、完整代码:
1.game.h文件代码:
1.game.c文件代码:
3.test.c 文件代码:
一、扫雷游戏规则介绍:
扫雷是一款很大众的益智类游戏,游戏规则如下:
一个扫雷盘面由许多方格组成,方格中随机分布着一定数量的雷(mine),一个格子中至多只有1雷。胜利条件是打开所有安全格,失败条件是打开了一个雷格(踩雷)。这款游戏分为初级(9*9),中级(16*16),高级(16*30),或则自定义大小方块矩阵中随机布置一定量的炸弹。
当我们选中一个格子时,如果是安全格则会显示周围一圈地雷的数量,通过获取地雷数量的信息进行逐一排查,最终找到所有安全格,从而排除所有雷格。
本篇博客将带领大家完成初级(9×9)扫雷游戏的实现
二、游戏功能分析及设计思路:
1 .游戏功能分析:
通过观察扫雷游戏,得到扫雷游戏的相关功能:
a.菜单(menu)模块:
我们需要设计一个菜单界面,供玩家进行选项选择,由于我们设计的是最基础的扫雷游戏所以我们可以设置两项功能:
1.进入游戏:当玩家输入1时进入游戏。
2.退出游戏:当玩家输入0时退出游戏。
b.游戏(game)模块:
进入游戏后,我们可以看到一个矩阵样的棋盘,那么我们需要思考,如何进行棋盘的设计和地雷的存储呢,不难想到我们可以使用二维数组,那么我们需要多大的二维数组呢,我们在下面进行详细分析。
首先,我们需要把雷和非雷区分开,雷用字符‘1’表示,非雷用字符‘0’表示,这样在后面我们排查雷的时候,这样容易计算格子周围一圈雷的个数。如下图所示,1则代表该格有雷,0则表示无雷
我们设计好了地雷存储棋盘用于记录地雷信息,我们需要设计另一个棋盘供玩家进行游戏,在这里我们使用字符’※’表示棋盘格。同时为了方便玩家进行行号 和列号的确定,我们可以在棋盘周围打印下行号与列号。
紧接着,我们思考一下,我们翻格子的时候,如果这个格子不是雷,那么就会排查这个格子周围八个格子存在雷的个数,假设我们翻开左上角的格子的时候,但是该格子上面和左边没有格子了怎么办?那就会出现越界访问的情况,为了避免这个情况出现,我们只需要把9*9的格子扩张成11*11的格子就可以了,如图所示,这样遍历的时候就不会出现越界访问的情况了。
2.所需文件:
由于扫雷需要实现的功能稍有复杂,所以我们将其拆分为不同的文件进行设计。
我们将代码拆分为三块,如下图所示,分别是:
⭐game.h–用于存放game模块相关函数声明。
⭐game.c–用于存放game模块相关函数实现。
⭐test.c –用于扫雷整体功能测试。
三、代码实现:
按照第二部分的分析,我们逐步完成代码的功能实现;
1.菜单(menu)模块代码:
void menu(){printf("*********************\n");printf("*****1.play******\n");printf("*****0.exit******\n");printf("*********************\n");}int main() {int input = 0;do{menu();srand((unsigned int)time(NULL));printf("请输入您的选择>");scanf_s("%d", &input);switch (input){case 1:game();break;case 0:printf("成功退出游戏");break;default:break;}} while (input);return 0;}
2.游戏(game)模块代码:
a.棋盘初始化(InitBoard):
我们在game.h文件里对棋盘的行列数进行宏定义,宏定义的好处是方便我们后续修改为其他大小的棋盘例如16×16等,由于我们实现9×9的棋盘所以将行(ROW)定义为9,列(COL)定义为9,为了防止上面提到的越界问题,将棋盘扩大到11×11,所以将扩大后的行(ROWS)定义为ROW+2,扩大后的列(COLS)定义为COL+2。
#define ROW 9#define COL 9#define ROWS ROW+2#define COLS COL+2
接下来我们实现初始化棋盘的函数:
对数组进行初始化操作,InitBoard函数使用了四个参数,分别是字符串类型的二维数组用于传入我们设计的扫雷二维数组,两个int类型的参数用于传入行号和列号,由于我们需要初始化两个棋盘,即地雷存储棋盘(全部初始化为字符’0‘),玩家游戏棋盘(全部初始化为字符’※’),所以我们设计了第四个参数,char类型的参数用于传入’0‘或者’※‘。这样我们就可以使用一个函数初始化两个数组。如图所示
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set){for(int i = 0;i<rows;i++){for (int j = 0; j <cols; j++){arr[i][j] = set;}}}
InitBoard(mine,ROWS,COLS,'0');//初始化地雷存储棋盘mineInitBoard(show,ROWS,COLS,'0');//初始化玩家游玩棋盘show
b.棋盘打印 (ShowBoard):
打印棋盘,我们设计三个参数,分别是字符串类型的二维数组用于传入我们设计的扫雷二维数组,两个int类型的参数用于传入行号和列号。代码如下
void ShowBoard(char arr[ROWS][COLS], int row, int col){printf("----------扫雷--------\n");for (int i = 0; i <= row; i++) {printf("%d ", i);//打印列号}printf("\n");for (int i = 1; i <=row; i++){printf("%d ", i);//打印行号for (int j = 1; j <=col; j++){printf("%c ", arr[i][j]);}printf("\n");}}
打印效果如下:
c.地雷设置(SetMine):
设置地雷,布置雷实际上还是把雷放在中间的9*9的数组中去,也就是说我们这里布置雷只需要操作mine数组。怎么实现呢,这里我们假设布置十个雷,那么我们就需要生成十个随机坐标,来放置雷。但是为了以后方便更改数据,所以这里我们可以把雷的数量在game.h头文件中。在放置雷的时候,我们需要判断该位置是否放置过地雷,具体代码和运行结果如下图示:
#define mine_count 10//设置10个地雷
void SetMine(char arr[ROWS][COLS], int row, int col){int count = mine_count;//记录生成地雷的数量while(count){int x = rand() % row + 1;//1-9int y = rand() % col + 1;//1-9if(arr[x][y]=='0')//防止重复设置地雷,进行一个判断,如果随机生成位置没有地雷则执行地雷生成。{arr[x][y] = '1';//地雷生成count--;//记录的地雷数量减去1,当count=0时地雷全部设置完毕,同时while循环结束;}}}
生成结果如下:
d.获取周围地雷数量 (GetMineNumbers):
获取周围地雷数量,我们排查雷是需要在mine数组里面查找,当我们排查一个单元格时,如果该单元格不是地雷格那么我们需要获取周围一圈格子地雷的数量,代码如下所示:
int GetMineNumbers(char mine[ROWS][COLS],int x,int y){return mine[x - 1][y] + mine[x - 1][y - 1] +mine[x][y - 1] + mine[x + 1][y - 1] +mine[x + 1][y] + mine[x + 1][y + 1] +mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0';//周围8个位置加起来-8*'0'即可得到有几个地雷}
这里是如何将字符数字和数字字符进行转换的,字符‘0’的ASCLL码值是48,地雷字符为’1’其ASCLL码值为49,我们直接将八个位置的ASCLL码相加并减去八个字符’0‘的ASCLL码就可以得到周围总共地雷的数量。
d.排查地雷(FindMine):
我们实现了获取周围地雷数量的函数后就可以进行地雷排查函数的设计,我们排查雷是需要在mine数组里面查找,然后将查到的数据放在show数组中展示。我们这个排查雷的函数需要将两个数组都传过去。具体怎么实现呢?代码如下:
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col){int x = 0;//坐标xint y = 0;//坐标yint win = 0;//排雷成功标志while (win ");scanf_s("%d %d", &x, &y);if ((x >= 1 && x = 1 && y <= col))//输入的坐标合法性判断{if (mine[x][y] == '0')//情况1.排查位置没有地雷{//获取周围地雷个数int n = GetMineNumbers(mine, x, y);show[x][y] = n + '0';//标记出周围地雷的个数ShowBoard(show, ROW, COL);win++;}elseif (mine[x][y] == '1')//情况2.排查位置有地雷{printf("对不起,您踩中地雷,游戏结束\n");break;}}else{printf("您输入的坐标不合法,请重新输入\n");}}}
对应9*9的棋盘来说,有10个雷,也就是我们需要排查71次才能将十个雷完全排查出来,使得游戏结束,所以在while循环里我们使用row*col-mine_count即计算出安全格的个数,每排查出一个安全格win++直到win=row*col-mine_count时排查完全部安全格,游戏获胜。
四、完整代码:
1.game.h文件代码:
#define ROW 9#define COL 9#define ROWS ROW+2#define COLS COL+2#define mine_count 10void ShowBoard(char arr[ROWS][COLS], int rows, int cols);void InitBoard(char arr[ROWS][COLS], int row, int col, char set);void SetMine(char arr[ROWS][COLS],int row,int col);void FindMine(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col);
1.game.c文件代码:
#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"#include#includevoid InitBoard(char arr[ROWS][COLS], int rows, int cols, char set){for(int i = 0;i<rows;i++){for (int j = 0; j <cols; j++){arr[i][j] = set;}}}void ShowBoard(char arr[ROWS][COLS], int row, int col){printf("----------扫雷--------\n");for (int i = 0; i <= row; i++) {printf("%d ", i);//打印列号}printf("\n");for (int i = 1; i <=row; i++){printf("%d ", i);//打印行号for (int j = 1; j <=col; j++){printf("%c ", arr[i][j]);}printf("\n");}}void SetMine(char arr[ROWS][COLS], int row, int col){int count = mine_count;//记录生成地雷的数量while(count){int x = rand() % row + 1;//1-9int y = rand() % col + 1;//1-9if(arr[x][y]=='0')//防止重复设置地雷,进行一个判断,如果随机生成位置没有地雷则执行地雷生成。{arr[x][y] = '1';//地雷生成count--;//记录的地雷数量减去1,当count=0时地雷全部设置完毕,同时while循环结束;}}}static int GetMineNumbers(char mine[ROWS][COLS],int x,int y){return mine[x - 1][y] + mine[x - 1][y - 1] +mine[x][y - 1] + mine[x + 1][y - 1] +mine[x + 1][y] + mine[x + 1][y + 1] +mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0';//周围8个位置加起来-8*'0'即可得到有几个地雷}void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col){int x = 0;//坐标xint y = 0;//坐标yint win = 0;//排雷成功标志while (win ");scanf_s("%d %d", &x, &y);if ((x >= 1 && x = 1 && y <= col))//输入的坐标合法性判断{if (mine[x][y] == '0')//情况1.排查位置没有地雷{//获取周围地雷个数int n = GetMineNumbers(mine, x, y);show[x][y] = n + '0';//标记出周围地雷的个数ShowBoard(show, ROW, COL);win++;}elseif (mine[x][y] == '1')//情况2.排查位置有地雷{printf("对不起,您踩中地雷,游戏结束\n");break;}}else{printf("您输入的坐标不合法,请重新输入\n");}}}
3.test.c文件代码:
#define _CRT_SECURE_NO_WARNINGS 1#include#include#include"game.h"void game(){char mine[ROWS][COLS];//地雷记录棋盘char show[ROWS][COLS];//玩家使用的扫雷棋盘//初始化棋盘InitBoard(mine,ROWS,COLS,'0');InitBoard(show, ROWS, COLS, '*');//打印棋盘ShowBoard(show,ROW,COL);//随机生成地雷SetMine(mine,ROW,COL);//展示地雷生成效果 //ShowBoard(mine, ROW, COL);//排查地雷FindMine(mine,show,ROW,COL);}void menu(){printf("*********************\n");printf("*****1.play******\n");printf("*****0.exit******\n");printf("*********************\n");}int main() {int input = 0;do{menu();srand((unsigned int)time(NULL));printf("请输入您的选择>");scanf_s("%d", &input);switch (input){case 1:game();break;case 0:printf("成功退出游戏");break;default:break;}} while (input);return 0;}
以上便是我为大家带来的扫雷小游戏的全部内容,若有不足,望各位大佬在评论区指出,谢谢大家!可以留下你们点赞、收藏和关注,这是对我极大的鼓励,我也会更加努力创作更优质的作品。再次感谢大家!