(7)代码实现如下
//打印数组 void DisplayBoard(char board[ROWS][COLS], int row, int col) { printf("-------扫雷--------\n"); int i = 0; int j = 0; for (j = 0; j <= col; j++) { printf("%d ", j); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } printf("-------扫雷--------\n"); }
3.布置雷(SetMine)
(1)布置雷函数的定义和声明
我们布置雷都是往mine数组里面放的,这个数组的大小是11*11,需要操作的行是9,列是9。所以定义和声明为
void SetMine(char board[ROWS][COLS], int row, int col);
(2)雷的个数以及雷坐标的生成
我们开始生成雷的个数和坐标。雷的个数我们可以使用一个define来进行定义。雷的坐标则需要使用一个随机数的使用。代码实现如下
(3)具体的布置雷实现
(4)测试布雷
如下图所示,我们在布置好雷以后在后面打印一下数组
结果为下图所示,刚好符合我们的预期,就是10个雷
(5)布置雷的代码实现
//布置雷 void SetMine(char board[ROWS][COLS], int row, int col) { //雷的个数 int count = EASY_COUNT; while (count) { //生成随机下标 int x = rand() % row + 1; int y = rand() % col + 1; //布雷 if (board[x][y] == '0') { board[x][y] = '1'; count--; } } }
4.排查雷(FindMine)
(1)排查雷函数的声明和定义
我们在排查的时候,是在mine数组中进行查找,然后将结果反馈给show数组,所以需要两个数组都传过去。我们进行排查的时候,只需要使用行9列9即可
(2)排查雷的实现逻辑
我们在排查雷的过程中的逻辑是这样,让用户输入一个坐标,通过这个坐标先判断是否合法,如下图所示
现在我们可以确保我们的坐标是合法的了,在合法的基础上,如果这个坐标中的位置已经是字符1了,那玩家就被炸死了,游戏结束并打印出雷区的棋盘。如果不是字符1,那就开始统计他的一圈有多少个雷,为了方便统起见,我们使用一个函数来进行统计。这个函数我们不妨就定义为
int get_mine_count(char mine[ROWS][COLS], int x, int y);
这个函数返回一个整型数字,传一个数组和需要查询的坐标即可。我们最后只需要将返回的这个整型数字+字符0即可得到对应的字符,然后将这个字符赋值给show数组对应的位置,并打印出来
那么我们现在该实现get_mine_count这个函数了,这个难度也不大,我们把周围一圈的都加起来然后减去8个字符0就可以解决了
(3)测试
此时我们的test.c文件是这样的。前面打印出来的那些部分我们后期可以将其给删掉。但是现在我们是正在测试中,没有必要删除。
被炸死案例
坐标不合法案例
(4)排雷的结束条件
当我们一直排雷下去,我们会发现我们的代码有一点问题,那就是排雷无法结束。所以说我们要在循环加上限制条件,我们可以定义一个变量,每一次没有被炸死则这个变量++。对于我们9*9的棋盘而言只要有81-10=71次没有被炸死,就赢了。所以说我们的代码实现如下
为了方便测试,我们将雷的数量暂时改为80个,符合我们的预期。
(5)优化多次排查同一个位置的bug
在这里相信很多人也都发现了一个bug,那就是这个坐标已经被排查过了,还重复排查的话,那win依然会++,这就是一个漏洞了。所以我们要优化这个bug
我们在这个位置加上这样一段代码即可,只要不是'*',就代表这个位置已经被查过了,利用一个continue就可以解决问题了。
下面是运行测试
(6)排查雷代码实现如下
//排雷时候需要统计的雷个数 int get_mine_count(char mine[ROWS][COLS], int x, int y) { return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y - 1] + mine[x][y + 1] - 8 * '0'); } //排查雷 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-EASY_COUNT) { printf("请输入坐标>:\n"); scanf("%d %d", &x, &y); if (show[x][y] != '*') { printf("这个位置已经被排查过了,请重新输入坐标\n"); continue; } if (x >= 1 && x <= row && y >= 1 && y <= col) { if (mine[x][y] == '1') { printf("很遗憾,你被炸死了\n"); DisplayBoard(mine, ROW, COL); break; } else { int n = get_mine_count(mine, x, y); show[x][y] = n + '0'; DisplayBoard(show, ROW, COL); win++; } } else { printf("坐标不合法,请重新输入\n"); } } if (win == row * col - EASY_COUNT) { printf("恭喜你,你赢了\n"); DisplayBoard(mine, ROW, COL); } }
四、游戏完整代码(分文件)
test.c文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void meau() { printf("*************************\n"); printf("****** 1. 开始扫雷 ******\n"); printf("****** 0. 退出游戏 ******\n"); printf("*************************\n"); } void game() { printf("开始扫雷\n"); char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; //初始化数组 InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); //打印数组 //DisplayBoard(mine, ROW, COL);//这是用来测试时使用的 DisplayBoard(show, ROW, COL); //布置雷 SetMine(mine, ROW, COL); //DisplayBoard(mine, ROW, COL);//这是用来测试时使用的 //排查雷 FindMine(mine, show, ROW, COL); } void test() { srand((unsigned int)time(NULL)); int input = 0; do { meau(); printf("请输入选项>:\n"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("输入错误,请重新输入\n"); break; } } while (input); } int main() { test(); return 0; }
game.h文件
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<time.h> #include<stdlib.h> #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define EASY_COUNT 10 //初始化数组 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);
game.c文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" //初始化数组 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; } } } //打印数组 void DisplayBoard(char board[ROWS][COLS], int row, int col) { printf("-------扫雷--------\n"); int i = 0; int j = 0; for (j = 0; j <= col; j++) { printf("%d ", j); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } printf("-------扫雷--------\n"); } //布置雷 void SetMine(char board[ROWS][COLS], int row, int col) { //雷的个数 int count = EASY_COUNT; while (count) { //生成随机下标 int x = rand() % row + 1; int y = rand() % col + 1; //布雷 if (board[x][y] == '0') { board[x][y] = '1'; count--; } } } //排雷时候需要统计的雷个数 int get_mine_count(char mine[ROWS][COLS], int x, int y) { return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y - 1] + mine[x][y + 1] - 8 * '0'); } //排查雷 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-EASY_COUNT) { printf("请输入坐标>:\n"); scanf("%d %d", &x, &y); if (show[x][y] != '*') { printf("这个位置已经被排查过了,请重新输入坐标\n"); continue; } if (x >= 1 && x <= row && y >= 1 && y <= col) { if (mine[x][y] == '1') { printf("很遗憾,你被炸死了\n"); DisplayBoard(mine, ROW, COL); break; } else { int n = get_mine_count(mine, x, y); show[x][y] = n + '0'; DisplayBoard(show, ROW, COL); win++; } } else { printf("坐标不合法,请重新输入\n"); } } if (win == row * col - EASY_COUNT) { printf("恭喜你,你赢了\n"); DisplayBoard(mine, ROW, COL); } }
五、完整代码展示(合并为同一个文件)
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<time.h> #include<stdlib.h> #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define EASY_COUNT 10 //初始化数组 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); void meau() { printf("*************************\n"); printf("****** 1. 开始扫雷 ******\n"); printf("****** 0. 退出游戏 ******\n"); printf("*************************\n"); } void game() { printf("开始扫雷\n"); char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; //初始化数组 InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); //打印数组 //DisplayBoard(mine, ROW, COL);//这是用来测试时使用的 DisplayBoard(show, ROW, COL); //布置雷 SetMine(mine, ROW, COL); //DisplayBoard(mine, ROW, COL);//这是用来测试时使用的 //排查雷 FindMine(mine, show, ROW, COL); } void test() { srand((unsigned int)time(NULL)); int input = 0; do { meau(); printf("请输入选项>:\n"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("输入错误,请重新输入\n"); break; } } while (input); } int main() { test(); return 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; } } } //打印数组 void DisplayBoard(char board[ROWS][COLS], int row, int col) { printf("-------扫雷--------\n"); int i = 0; int j = 0; for (j = 0; j <= col; j++) { printf("%d ", j); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } printf("-------扫雷--------\n"); } //布置雷 void SetMine(char board[ROWS][COLS], int row, int col) { //雷的个数 int count = EASY_COUNT; while (count) { //生成随机下标 int x = rand() % row + 1; int y = rand() % col + 1; //布雷 if (board[x][y] == '0') { board[x][y] = '1'; count--; } } } //排雷时候需要统计的雷个数 int get_mine_count(char mine[ROWS][COLS], int x, int y) { return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y - 1] + mine[x][y + 1] - 8 * '0'); } //排查雷 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 - EASY_COUNT) { printf("请输入坐标>:\n"); scanf("%d %d", &x, &y); if (show[x][y] != '*') { printf("这个位置已经被排查过了,请重新输入坐标\n"); continue; } if (x >= 1 && x <= row && y >= 1 && y <= col) { if (mine[x][y] == '1') { printf("很遗憾,你被炸死了\n"); DisplayBoard(mine, ROW, COL); break; } else { int n = get_mine_count(mine, x, y); show[x][y] = n + '0'; DisplayBoard(show, ROW, COL); win++; } } else { printf("坐标不合法,请重新输入\n"); } } if (win == row * col - EASY_COUNT) { printf("恭喜你,你赢了\n"); DisplayBoard(mine, ROW, COL); } }
总结
本节主要讲解了扫雷游戏的实现。这是一个经典的游戏。其中的很多细节都在里面讲到了。当然还有一些不足之处,我们在网页上的扫雷他是可以进行展开的,可以展开一片的。这一点我们本节咱不讨论。我们会放在后面的文章中将扫雷进行升级,同样的三子棋也在后面的文章中进行升级。
写文章不易,如果对你有帮助的话,不要忘记点赞加收藏哦!!!