大一C语言必做项目扫雷超详解
文章目录
- 扫雷游戏的功能说明
- 1. 游戏的分析与设计
- 数据存储
- 多文件格式
- 2. 菜单打印与基本程序框架
- 菜单
- 基本框架
- 3. game函数实现
- 布雷
- 排雷
- 胜利判定
- 4. 拓展
扫雷游戏的功能说明
在线扫雷游戏
使用控制台实现经典的扫雷游戏 游戏可以通过菜单实现继续玩或者退出游戏 扫雷的棋盘是9*9的格子 默认随机布置10个雷 可以排查雷 · 如果位置不是雷,就显示周围有几个雷。 · 如果位置是雷,就炸死游戏结束 · 把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束
你可以在c语言扫雷中获得源代码,喜欢的顺手点个star吧!!
1. 游戏的分析与设计
数据存储
我们以 9*9 的棋盘举例进行分析:
首先,我们需要一个二维数组来存储哪些地方有雷,但这个二位数组应该是多大的?不妨先初始化一个9行9列的二维数组进行尝试。
int arr[9][9] = { 0 };我们先跳过埋雷这一步骤,先思考 Print 这个函数该如何实现。
在埋雷时,我们将有雷的地方在数组中赋值为1,这样在打印棋盘的时候就只需要统计被点开位置周围 9*9 位置中1的个数就可以了。
那么这其中有两个问题:
1. 棋盘边缘位置的数字该如何统计?
2. 打印棋盘时不能将哪里有雷告诉玩家,应该如何实现?
我们逐一来解决:
- 我们确实可以通过一些复杂的判断来使这些边缘部位的数字统计时不会越界访问,但我想提供一种更简单的办法:无论棋盘大小为多少,都在棋盘的上下左右加上一行(列)0,这样,在数字计算时就不会发生越界访问,且不会影响数组的准确性。
- 这里我们肯定有办法解决,比如雷的息不要使用数字,使用某些字符就行,这样就避免冲突了,但是这样做棋盘上有雷和非雷的信息,还有排查出的雷的个数信息,就比较混杂,不够方便。
这里我们采用另外一种方案,我们专门给一个棋盘(对应一个数组mine)存放布置好的雷的信息,再给另外一个棋盘(对应另外一个数组show)存放排查出的雷的信息。这样就互不干扰了,把雷布置到mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且打印show数组的信息给后期排查参考。
同时为了保持神秘,show数组开始时初始化为字符*,为了保持两个数组的类型一致,可以使用同一套函数处理,mine数组最开始也初始化为字符 0 ,布置雷改成 1 。如:
char mine[11][11] = { 0 }; char show[11][11];//先省略其初始化为'*'的步骤多文件格式
扫雷是一个项目,我们可以使用多文件存储代码来使代码逻辑性更强
test.c //⽂件中写游戏的测试逻辑 game.c //⽂件中写游戏中函数的实现等 game.h //⽂件中写游戏需要的数据类型和函数声明等
2. 菜单打印与基本程序框架
菜单
由于本程序采用控制台终端进行输出,因此在游戏最开始打印一个菜单对玩家进行提示是非常有必要的!
我们可以将其封装在 *menu()*函数中以方便调用。
注:menu函数声明再 game.h 中,实现在 game.c 中,调用在 test.c 中。
可以简单地做一个这样的菜单对玩家进行提醒。
基本框架
我们可以通过一个 input 变量存储玩家的输入,以此进行游戏是否进行的判断。
另外,游戏显然应该可以进行多轮,且第一次输入input一定会进行,因此,我们可以采用 do…while循环来控制整个程序。
在循环内部,我们还可以用switch对input进行分类讨论,样板如下:
//test.c,main函数中 int input = 0; do { menu(); scanf("%d", &input); switch (input) { case 1: game();//此处进行游戏(此时尚未实现game函数) break; case 0: printf("游戏退出\n"); // input 为 0,循环退出,即游戏结束 break; default: printf("输入错误,请重新输入\n"); // input != 0,本次循环结束,但循环继续进行 break; } } while (input);3. game函数实现
布雷
接下来我们实现 game 函数:
//test.c(game函数可以放在test.c中,但其他函数应该定义再其他文件中) char mine[11][11] = { 0 }; char show[11][11] = { 0 };//先省略其初始化为'*'的步骤 inititshow(show);//初始化 show inititmine(mine);//埋雷接下来实现 initishow和initimine函数
//game.h void initishow(char* show[COLS],int row,int col); void initimine(char* mine[COLS],int row,int col,int num_mine);
注:这里char* show[COLS]是对二维数组传参的一种写法,如果你对此并不了解,可以使用
char show[ROWS][COLS],我会在将来的指针博客中详细解释这种写法!
那么在实现这两个函数之前,我们不妨先定义两个宏。
为了在之后更方便对游戏进行修改,不妨将一些数值设置为宏,如:
//game.h(以9*9棋盘为例) #define EASY_COUNT 10//雷的数量 #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2
initishow的实现较为简单,先实现:
//game.c void initishow(char* show[COLS], int row, int col) { for (int i = 0; i接下来是initimine,这个要复杂一些,为了保证每次生成的雷的位置不相同,我们需要使用随机数,如果你不了解随机数,你可以在猜数字详解的开篇部分了解,这里不再赘述。
//game.c void initimine(char(*mine)[COLS], int row, int col, int num_mine) { for (int i = 0; i






