前言
本篇文章要实现的是扫雷游戏,其代码实现与上一篇的三子棋游戏类同,都是在棋盘的基础上,与电脑进行对抗,不同的是,扫雷游戏一开始电脑就已经随机布置好了所有“雷”。
请戳 --->
三子棋
扫雷游戏
- 1. 扫雷游戏玩法
- 2. 设计思路
- 2.1 准备工作
- 2.2 主函数设计
- 2.3 设计棋盘
- 2.3.1 初始化棋盘
- 2.3.2 打印棋盘
- 2.4 布置雷
- 2.5 排除雷
- 2.5.1 代码实现
- 3. 总结
- 3.1 game.h文件所有内容
- 3.2 game()游戏函数整体
- 结束语
1. 扫雷游戏玩法
经典玩法:
扫雷就是要把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。
游戏主区域由很多个方格组成。选择一个方格,方格即被打开并显示出方格中的数字,
而方格中数字则表示其周围的8个方格隐藏了几颗雷;如果点开的格子为空白格,即其周围有0颗雷,则其周围格子会自动打开。
本机玩法:
游戏开始,玩家在棋盘格上输入正确的行列坐标选择位置,若选择到的是非地雷,就会显示出周围8个格子存在雷的数量,直到把所有非雷的格子都选出来,游戏胜利;若“踩雷”了,则游戏失败。
看似简单的扫雷游戏,想要胜利,走的每一步都需要推算
2. 设计思路
游戏都需要一个开关去控制它,所以一个菜单界面是必不可少的,通过菜单去选择play还是exit。
而对于游戏的实现:
1.首先需要创建一个n*n的棋盘格,可以用二维数组实现,自定义它的大小
2.在玩家选择位置前,就要布置好雷的数量,随机埋下雷的位置,并用一个二维数组来存放布置好的雷
3.玩家通过提示,输入正确的坐标选择位置,如果选择的是非雷坐标,就显示出周围雷的数量,用一个二维数组来存放排查出的雷的信息(数量)
坐标选择后的状态有两种:
- 选择的坐标是非雷的,显示周围雷的数量,一直到排查完所有的雷,即所有的坐标都选择完了且没有踩雷,游戏胜利
- 选择的坐标是有雷的,游戏失败
2.1 准备工作
🍥 建立 test.c
源文件 – 测试游戏代码
🍥 建立 game.c
源文件 – 游戏的实现
🍥 建立 game.h
头文件 – 游戏函数声明
2.2 主函数设计
为了控制游戏的进行,我们设置一个菜单选项,选1时玩游戏,选择0,则退出游戏。
🍤 代码实现:
//test.cint main()
{//菜单printf("----1. play----\n");printf("----0. exit----\n");//进行选择int input;printf("请选择:");scanf("%d", &input);switch (input){case 1:game();//游戏函数break;case 0:printf("退出游戏\n");break;default:printf("选择错误,请重新选择\n");break;}return 0;
}
当玩家想要一直玩游戏,该怎么办呢? 加入循环
同时,为了使主函数简洁明了,我们将菜单放在主函数外面,使用menu函数来实现
//test.cvoid menu()
{printf("----1. play----\n");printf("----0. exit----\n");
}
int main()
{int input;srand((unsigned int)time(NULL));//设置随机种子do{menu();printf("请选择:");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}
🍤 菜单显示:
2.3 设计棋盘
想打印一个9x9的棋盘格实现游戏,我们就需要先创建两个二维数组(11x11),一个存放布置好的雷,一个存放排查出的雷的信息。
为什么是11x11?
考虑到棋盘边缘的位置,周围并不能的格子不能都满足8个,所以为了防止在统计坐标周围的雷的个数的时候越界,所以让数组设计为11x11,这里的11x11并不会全部打印出来
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息
仔细观察就会发现,这里的数组大小为什么是ROWSxCOLS,而不是11x11呢?
在下面设计棋盘时,我们的大小与这里是相同的,而为了后期可以方便的调整大小,我们就在game.h文件中就定义这两个全局变量的大小
🍤 代码实现:
#define ROW 9//显示的棋盘大小
#define COL 9#define ROWS ROW+2//棋盘真正大小
#define COLS COL+2
2.3.1 初始化棋盘
//game.cvoid InitBoard(char board[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++){board[i][j] = set;}}
}
🍤 调用:
//test.cvoid game()
{char mine[ROWS][COLS];//存放布置好的雷char show[ROWS][COLS];//存放排查出的雷的信息//初始化棋盘//1.mine数组最开始全‘0’、//2.show数组最开始全‘*’InitBoard(mine,ROWS,COLS,'0');InitBoard(show,ROWS,COLS,'*');
}
2.3.2 打印棋盘
用DisplayBoard
函数实现棋盘打印,为了玩家有更好的游戏体验,我们在棋盘格的最顶端和最左边提示坐标信息,方便玩家快速的锁定行列数。
//game.cvoid DisplayBoard(char board[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++){printf("%d ", i);//最左边打印行数int j = 0;for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}
}
打印棋盘时,只用打印出9x9大小的棋盘格
//打印棋盘
DisplayBoard(show, ROW, COL);//打印棋盘函数调用
🍤运行结果:
2.4 布置雷
在game.h文件中先定义全局变量EASY_COUNT
,控制雷的数量
#define EASY_COUNT 10
在布置雷时,要先生成随机坐标,然后判断该坐标是否可以放雷
- 用rand函数产生随机值
- 每一个格子只能存放一个雷,前面初始化棋盘时,已经将所有的格子(11x11)全初始化为’0’,所以在布置雷,只能在为’0’的格子中存放
//game.cvoid SetMine(char board[ROWS][COLS], int row, int col)
{//布置雷//生成随机的坐标,布置雷int count = 10;while (count){int x = rand() % row + 1;//为了控制随机值大小,防止越界,范围:1-9int y = rand() % col + 1;if (board[x][y] == '0'){board[x][y] = '1';count--;}}
}
🍤 调用头文件:
//game.h#include<stdlib.h>
#include<time.h>
2.5 排除雷
玩游戏选择坐标时,会有三种结果:
1. 选择存放了雷的坐标,游戏结束
玩家先输入坐标,该坐标行列大小在定义的范围内,然后判断是否是存放了雷的坐标。
在之前我们已经初始化了所有位置都是‘0’,只有随机存放了雷的位置,会变为‘1’,而当输入的坐标的内容为‘1’时,即玩家踩雷了,游戏结束。
2. 选择了安全的坐标,且显示周围8个坐标的雷的数量
如果输入的坐标的内容为‘0’,则计算出周围8个位置的雷的数量,并打印在此坐标上。
在这里,我们用GetMineCount
函数单独计算,返回雷的数量
假设已知坐标x,y,其他周围的坐标就可以表示为:
🍤 代码实现:
//game.cint GetMineCount(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');
}
🍩游戏胜利的实现
定义一个变量win
,在每次选择非雷的坐标后累加1,当win=棋盘总个数(9x9)-存放了雷的个数,即win==row* col - EASY_COUNT
,也就排除了所有的雷,游戏胜利。
3. 坐标选择错误
当我们选择的行列坐标超出设定的范围,就提示玩家输入错误,重新输入。
printf("坐标非法,重新输入!\n");
2.5.1 代码实现
//game.cvoid FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x = 0, y = 0;int win = 0;while (win<row*col-EASY_COUNT){printf("请输入要排查的坐标,如:1 2:>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了");DisplayBoard(mine, ROW, COL);break;}else{int count=GetMineCount(mine, x, y);//统计周围8个位置的雷的数量show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else{printf("坐标非法,重新输入!\n");}}if(win == row* col - EASY_COUNT){printf("恭喜你,排雷成功…^-^…");DisplayBoard(mine, ROW, COL);}
}
3. 总结
3.1 game.h文件所有内容
#include<stdlib.h>
#include<time.h>
#define EASY_COUNT 10
#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘
void InitBoard(char board[ROWS][COLS],int rows,int cols,char set);
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
3.2 game()游戏函数整体
//test.cvoid game()
{char mine[ROWS][COLS];//存放布置好的雷char show[ROWS][COLS];//存放排查出的雷的信息//初始化棋盘//1.mine数组最开始全‘0’、//show数组最开始全‘*’InitBoard(mine,ROWS,COLS,'0');InitBoard(show,ROWS,COLS,'*');//打印棋盘DisplayBoard(show, ROW, COL);//1.布置雷SetMine(mine,ROW,COL);//2.排查雷FindMine(mine, show, ROW, COL);
}
🍩注: 每一个.c文件最前面,需要用 #include "game.h"
进行声明
结束语
扫雷的实现就到这里了,感觉这篇文章有帮到你的话,点赞支持一下哟。
我们下一篇文章再见。