[C语言小白]简易扫雷程序

从来好事天生俭,自古瓜儿苦后甜。这篇文章主要讲述[C语言小白]简易扫雷程序相关的知识,希望能为你提供帮助。
@TOC
本游戏程序和上一篇三子棋小程序的制作思路相仿,实现基础都是二维数组的运用
游戏主函数首先,我们设计三子棋时,要设计选择进入游戏,退出游戏的选项,以及输入错误内容时,重新选择的程序。
将游戏标题函数设置为
将游戏主题函数设置为
若在选择时,输入内容不在程序设定范围内,则要求使用者重新输入。所以程序此处应有一个循环。
因此主函数程序设置如下:

int main() { int input = 0; do { menu(); printf("请选择:"); scanf("%d", & input); switch (input) { case 1: game(); break; case 2: printf("退出游戏\\n"); input -= 2; break; default: printf("输入错误,请重新选择\\n"); break; } } while (input); return 0; }

当输入1时,进入case 1:运行game()函数;
当输入2时,进入case 2:打印“退出游戏”并跳出switch循环,在dowhile结尾进行检测时,检测结果为0,跳出循环,退出程序;
当输入其他字符时,进入default,打印‘“输入错误,请重新选择”。因为input非零,所以继续进行dowhile循环。
代码实现的初步工作首先我们创建游戏程序文件==game.c==,和头文件==game.h==
为了提高系统的可操作性,我们先将程序中的行与列定义为==ROW==和==COL==
所以头文件中预处理指令如下:
#define _CRT_SECURE_NO_WARNINGS 1//scanf函数防止报错 #include < stdio.h> //printf函数 #include < time.h> //time函数,产生随机值(后面讲) //例如9×9的棋盘,周边多一圈,这样便于进行周围雷数量的判断。周边一圈不进行打印,不设置雷 #define ROW 9//行 #define COL 9//列 #define ROWS ROW+2//棋盘外围拓展一圈,便于后续的程序制作,这里后面再讲 #define COLS COL+2 //设定雷的数量 #define NUM 10 //这里将游戏中用到的棋盘尺寸,雷的数量提前设置好,提高程序整体的可变性,便于后续修改

然后在==game.c==和主函数所在文件==TigerMinesweeper.c==中引用头文件:
接着设计主函数中的==menu()==函数。因为打印游戏菜单不需要返回值,所以函数类型void即可:
void menu() { printf("********扫雷游戏*********\\n"); printf("******** 1.play ********\\n"); printf("******** 2.exit ********\\n"); printf("************************\\n"); }

根据主函数的设计,我们继续设计game()函数:
同理不需要返回值,所以函数类型为void:
void game() { char mine[ROWS][COLS] = { 0 }; //创建雷的位置的 数组 char show[ROWS][COLS] = { 0 }; //创建展示给玩家的页面 的数组 //初始化棋盘 InitBoard(mine, ROWS, COLS, \'0\'); InitBoard(show, ROWS, COLS, \'*\'); //布置雷 SetMine(mine, ROW, COL); //打印棋盘 DisplayBoard(show, ROW, COL); //开始逐步排查雷 FindMine(mine, show, ROW, COL); }

如上文所示,我们先整理出了一个大致的代码设计方向。
游戏实现原理与程序优化 初始化棋盘首先我们需要将数组初始化
mine数组为雷组,“1”为有雷,“0”为无雷
show数组展示给玩家,“*”为初始展示界面,数字代表周围八个格子中雷的数量,0则说明无雷
void 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; //set对应传进来的参数,这样两个数组可以共用一个函数 } } }

然后再在头文件==game.h==中声明,并做好注释:
//初始化棋盘 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);

打印棋盘因为我们周围的一圈不算入游戏,只是为了程序进行时便于判断,故打印棋盘时,只打印1~9,0和10不打印(在行列都为9时)
void DisplayBoard(char board[ROWS][COLS], int row, int col) { printf("-----扫雷 游戏-----\\n"); int i = 0; for (i = 0; i < = row; 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"); } }

然后我们同样在头文件==game.h==中声明此函数,并做好注释:
//打印棋盘 void DisplayBoard(char board[ROWS][COLS], int row, int col);

这样此函数既可用于打印显示给玩家的棋盘,也可以打印雷的分布图,便于后续程序的调试
布置雷此处依然采用time函数,讲随机值取模后再+1后获得1~9的随机数。
依此方法获取雷的随机坐标,将二维数组中的0赋值为1(0为无雷,1为有雷)
void SetMine(char mine[ROWS][COLS], int row, int col) { int count = NUM; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (mine[x][y] != \'1\') { mine[x][y] = \'1\'; count--; } } }

同样,在头文件==game.h==中声明此函数,并做好注释:
//布置雷 void SetMine(char board[ROWS][COLS], int row, int col);

排查雷排查雷的时候,是游戏的最重要部分,即玩家的操作部分。
所以我们要先理清游戏流程,以此着手制作
所以我们可以这样制作出一串代码:
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; while (1) { printf("请输入排查雷的坐标:\\n"); scanf("%d %d", & x, & y); if (x > = 1 & & x < = row & & y > = 1 & & y < = col) { if (mine[x][y] == \'1\')//是雷,GG { printf("你被炸死了,GG\\n"); DisplayBoard(mine, ROW, COL); break; } else { //不是雷,获取坐标周边的累个数 } } else { printf("坐标不存在,请重新输入"); } } }

然后我们再思考如何获取玩家输入坐标周围的雷个数,这里设定一个函数来获取周围雷的数量:
//获取周边雷数量 int GetMineCount(char mine[ROWS][COLS], int x, int y) {}

此处我有两种思路:
①因为ASCII表的0~9的是连续排列的,所以:
//获取周边雷数量 int 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\'); }

②既然要获取周边的雷数量,那么我们首先知道的是,玩家所选坐标是没有雷的。
这么说,我们可以统计玩家所选坐标周围,总共九格中雷的数量。所以我们采用两重嵌套的for循环:
//获取周边雷数量 int GetMineCount(char mine[ROWS][COLS], int x, int y) { int i = 0; int j = 0; int count = 0; for (i = x - 1; i < = x + 1; i++) { for (j = y - 1; j < = y + 1; j++) { if (mine[i][j] == \'1\') { count++; } } } return count; }

然后我们就可以完善先前的==排查雷==的函数了。
当游戏中所有雷被排除,记所有非雷的位置被玩家选择后,剩下未选择的都是雷,那么玩家胜利。
以此我们可以设置变量win,当玩家正确输入次数达到要求时,游戏结束,玩家胜利
如下:
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int win = 0; while (win < row*col - NUM) { printf("请输入排查雷的坐标:\\n"); scanf("%d %d", & x, & y); if (x > = 1 & & x < = row & & y > = 1 & & y < = col) { if (mine[x][y] == \'1\')//是雷,GG { printf("你被炸死了,GG\\n"); DisplayBoard(mine, ROW, COL); break; } else//不是雷,获取坐标周边的累个数 { int count = GetMineCount(mine, x, y); show[x][y] = count + \'0\'; DisplayBoard(show, ROW, COL); win++; } } else { printf("坐标不存在,请重新输入"); } } if (win == row * col - NUM) { printf("恭喜你,排雷成功\\n"); DisplayBoard(mine, ROW, COL); } }

但是你以为结束了吗?并没有
我发现,如果玩家输入同一坐标多次,那win会不停地增长,在win达到目标后玩家胜利。而事实上,玩家并没有将所有非雷的空选择(并没有把雷排除完)
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { //1输入坐标 //2检查是否为雷 //2.1若是雷,GG //2.2若不是雷,统计坐标周围有几个雷,存储数据到二维数组show中,游戏继续 int x = 0; int y = 0; int win = 0; while (win < row*col - NUM) { printf("请输入排查雷的坐标:\\n"); scanf("%d %d", & x, & y); if (x > = 1 & & x < = row & & y > = 1 & & y < = col) { if (mine[x][y] == \'1\')//是雷,GG { printf("你被炸死了,GG\\n"); DisplayBoard(mine, ROW, COL); break; } else//不是雷,获取坐标周边的累个数 { int count = GetMineCount(mine, x, y); if (show[x][y] == \'*\')//这里增加一次判断,若玩家已经排过雷,则不计入总次数 { win++; } show[x][y] = count + \'0\'; DisplayBoard(show, ROW, COL); } } else { printf("坐标不存在,请重新输入"); } } if (win == row * col - NUM) { printf("恭喜你,排雷成功\\n"); DisplayBoard(mine, ROW, COL); } }

【[C语言小白]简易扫雷程序】下面是传统艺能,挖坑。
以上程序,如果执行,可以很明显地发现,和以前玩电脑时的扫雷有很大区别。
至少两个坑吧
1.在周围都没有雷的时候,自动将周围的空白摊开,直到数字不为0(优化玩家体验)
2.不是简单的输入坐标,而是能使用鼠标光标进行游戏

    推荐阅读