路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)

知识提要(自主编写游戏所需要的知识):
1.函数的基本实现;
2.二维数组;
目录
扫雷
1.基本界面的实现
2.初始化棋盘(二维数组)
3.棋盘的打印
4.布置雷
5.安全保护
6.雷数显示
7.排查雷
8.标记雷
9.展开
10.难度设置
11.全局代码
扫雷 效果图:
路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)
文章图片

路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)
文章图片

从以上效果图中可见,我们需要实现的功能有:
1.随机埋雷
2.显示雷数
3.展开
4.标记
5.判定输赢
如果将雷,数字,和*同时放在一个数组里是不现实的,因为如果一个格子中已经放了雷,就不可能将其变为星号显示,所以我们得到一个大体思路,要用两个数组,一个埋雷,一个显示。
还是老规矩,创建3个文件
路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)
文章图片

game.h先引用和定义必要的数据

# define _CRT_SECURE_NO_WARNINGS #include #include #include #define ROW 9 #define COL 9#define ROWS ROW+2 #define COLS COL+2#define EASY_COUNT 10

这次我们用'*'当作未知量,'#'为标记,'1'为雷,'0'为非雷(此处为一个伏笔)

1.基本界面的实现 这一部分比较简单,所以就只简单提一句
void menu() { printf("*********************************\n"); printf("*********1. Play*********\n"); printf("*********0. Exit*********\n"); printf("*********************************\n"); }void game() { char mine[ROWS][COLS] = { 0 }; //存放雷的信息 char show[ROWS][COLS] = { 0 }; //展示给玩家的棋盘 intialize(mine,ROWS ,COLS,'0'); intialize(show,ROWS ,COLS,'*'); //展示棋盘 print(show, ROW, COL); //布置雷 setmine(mine, ROW, COL); //排查 search(mine, show, ROW, COL,0); }int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择>:"); scanf("%d", &input); switch (input) { case 1: printf("game start\n"); game(); break; case 0: printf("已退出游戏\n"); break; default: printf("选择错误,请重新选择\n"); break; } } while (input); return 0; }

这里可能有人要问,为什么要创建11*11的数组呢?
如果我们要在9*9的棋盘中找寻雷的个数,那么就得找寻周围8个元素,但是如果要找边边角角的格子附件雷的个数,就涉及到数组越界的问题,不太好办。所以我们将数组做大一圈,保证数组访问不会越界
路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)
文章图片


2.初始化棋盘(二维数组) 现在我们要考虑一个问题,这次我们有两个二维数组要初始化,而且其中内容也不同,那该怎么办呢?
其实也比较简单,只需要让初始化函数多接受一个需要初始化的量就可以了
void intialize(char board[ROWS][COLS], int row, int col, char target) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { board[i][j] = target; } }}

这样就可以完成不同的初始化了
3.棋盘的打印 由于扫雷需要的棋盘比较大,为了方便游玩,这次还需要打印行列号
void print(char board[ROWS][COLS], int row, int col) { int i = 0; for (i = 0; i <= row; i++)//打印列号 { printf("%d ", i); } printf("\n"); for (i = 1; i <= row; i++) { int j = 0; printf("%d ", i); //打印行号 for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } }

效果图:
路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)
文章图片

4.布置雷 布置雷就牵扯到随机数的问题,要保证雷不会重复布置且只在9*9的棋盘中布置
void setmine(char board[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = 0; while (1)//未布置满就一直循环 { x = rand() % row + 1; //使x,y在1~9间,保证数组不越界布置 y = rand() % col + 1; if (board[x][y] != '1')//保证布置的雷不重复 { board[x][y] = '1'; count++; } if (count == EASY_COUNT)//布置满所有不重复的雷后才可跳出循环 break; }}

5.安全保护 为了防止第一次排查就猝死,提高游戏体验所以我们需要设计一下,让玩家如果第一次就踩雷,棋盘会重置,直到此处没有雷
first_die++; if (first_die == 1 && mine[x][y] == '1')//first_die在test中创建,默认传递0进入 { while (mine[x][y] == '1') { intialize(mine, ROWS, COLS, '0'); //必须先初始化棋盘,不然会导致原本的雷依然在 setmine(mine, ROW, COL); }}

6.雷数显示
int search_show(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'); }

'0'的ASCII值为48,我们将雷设计为'1'就是为了方便相加以后减去8个'0',直接就可以得到雷的数量
7.排查雷 下面就是本文章的重点之一,雷的排查,其实实现思路也比较简单,如果踩到雷,游戏结束;如果没有,继续游戏,同时显示附近雷的个数
int x = 0; int y = 0; while (1) { printf("请输入需要排查的坐标,如:1 1\n"); scanf("%d%d", &x, &y); first_die++; if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的行列号是否在规定范围 { if (mine[x][y] == '1') { printf("你死了,请再接再厉\n"); print(mine, ROW, COL); break; } else { show[x][y] = search_show(mine, ROW, COL)+'0'; //显示周围的雷数 open(mine,show, x, y,row,col); print(show, ROW, COL); } } else { printf("输入错误,请重新输入\n"); }

8.标记雷 我们可以在排查以后加入一个标记功能,我们规定用'#'标记,同时只能标记未知量
//标记地雷 int input1 = 0; int input2 = 0; if (x >= 1 && x <= row && y >= 1 && y <= col) {do//至少要运行一次 { printf("请输入标记坐标,输入0 0退出标记\n"); scanf("%d%d", &input1, &input2); if (input1 >= 1 && input1 <= row && input2 >= 1 && input2 <= col) { if (show[input1][input2] == '*')//只标记未知量 { show[input1][input2] = '#'; print(show, ROW, COL); } else { printf("标记失败,请重新标记\n"); } } else if (input1 == 0 && input2 == 0)//输入0 0退出标记 break; else { printf("标记错误,请重新标记\n"); }} while (input1&&input2); printf("已退出标记\n"); }

9.展开 这应该是最难实现的一部分,这里我们用到递归的思想
void open(char mine[ROWS][COLS],char show[ROWS][COLS], int x, int y,int row ,int col) { int ret = 0; ret =search_show(mine,x,y); if (ret == 0)//如果周围无雷,判断展开 { show[x][y] = ' '; //防止死递归,如果不将show[x][y]变为' ',则下一次检测可能又会是*,再次进入递归,直至卡死。 if (x - 1 > 0 && y > 0 && show[x - 1][y] == '*'|| show[x - 1][y] == '#') open(mine, show, x - 1, y, row, col); if (x - 1 > 0 && y + 1 <= col && show[x - 1][y + 1] == '*'|| show[x - 1][y + 1] == '#') open(mine, show, x - 1, y + 1, row, col); if (x > 0 && y + 1 <= col && show[x][y + 1] == '*'|| show[x][y + 1] == '#') open(mine, show, x, y + 1, row, col); if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*'|| show[x + 1][y + 1] == '#') open(mine, show, x + 1, y + 1, row, col); if (x + 1 <= row && y > 0 && show[x + 1][y] == '*'|| show[x + 1][y] == '#') open(mine, show, x + 1, y, row, col); if (x + 1 <= row && y - 1 > 0 && show[x + 1][y - 1] == '*'|| show[x + 1][y - 1] == '#') open(mine, show, x + 1, y - 1, row, col); if (x > 0 && y - 1 > 0 && show[x][y - 1] == '*'|| show[x][y - 1] == '#') open(mine, show, x, y - 1, row, col); if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*'|| show[x - 1][y - 1] == '#') open(mine, show, x - 1, y - 1, row, col); } else//有雷则返回雷数 { return show[x][y]=search_show(mine, x, y)+'0'; }}

10.难度设置 其实实现思路比较简单,可以再设置MIDDLE_COUNT和HARD_COUNT。
传参时,将难度数字也传进去即可
这里交给大家去自行实现,不算难
11.全局代码
game.h# define _CRT_SECURE_NO_WARNINGS #include #include #include #define ROW 9 #define COL 9#define ROWS ROW+2 #define COLS COL+2#define EASY_COUNT 10//初始化 void intialize(char board[ROWS][COLS], int row, int col, char target); //打印棋盘 void print(char board[ROWS][COLS], int row, int col); //布置雷 void setmine(char board[ROWS][COLS], int row, int col); //排查雷 void search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,intgame.c# define _CRT_SECURE_NO_WARNINGS # include "game.h"void intialize(char board[ROWS][COLS], int row, int col, char target) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { board[i][j] = target; } }}void print(char board[ROWS][COLS], int row, int col) { int i = 0; for (i = 0; i <= row; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i <= row; i++) { int j = 0; printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } }void setmine(char board[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = 0; while (1) { x = rand() % row + 1; y = rand() % col + 1; if (board[x][y] != '1') { board[x][y] = '1'; count++; } if (count == EASY_COUNT) break; }}int search_show(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'); }void open(char mine[ROWS][COLS],char show[ROWS][COLS], int x, int y,int row ,int col) { int ret = 0; ret =search_show(mine,x,y); if (ret == 0)//如果周围无雷,判断展开 { show[x][y] = ' '; //防止死递归,如果不将show[x][y]变为' ',则下一次检测可能又会是*,再次进入递归,直至卡死。 if (x - 1 > 0 && y > 0 && show[x - 1][y] == '*'|| show[x - 1][y] == '#') open(mine, show, x - 1, y, row, col); if (x - 1 > 0 && y + 1 <= col && show[x - 1][y + 1] == '*'|| show[x - 1][y + 1] == '#') open(mine, show, x - 1, y + 1, row, col); if (x > 0 && y + 1 <= col && show[x][y + 1] == '*'|| show[x][y + 1] == '#') open(mine, show, x, y + 1, row, col); if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*'|| show[x + 1][y + 1] == '#') open(mine, show, x + 1, y + 1, row, col); if (x + 1 <= row && y > 0 && show[x + 1][y] == '*'|| show[x + 1][y] == '#') open(mine, show, x + 1, y, row, col); if (x + 1 <= row && y - 1 > 0 && show[x + 1][y - 1] == '*'|| show[x + 1][y - 1] == '#') open(mine, show, x + 1, y - 1, row, col); if (x > 0 && y - 1 > 0 && show[x][y - 1] == '*'|| show[x][y - 1] == '#') open(mine, show, x, y - 1, row, col); if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*'|| show[x - 1][y - 1] == '#') open(mine, show, x - 1, y - 1, row, col); } else { return show[x][y]=search_show(mine, x, y)+'0'; }}int win(char show[ROWS][COLS], int row, int col) { int i = 0; int j = 0; int count = 0; for (i = 1; i <= row; i++) { for (j = 1; j <= col; j++) { if (show[i][j] == '*'||show[i][j]=='#') count++; } } if (count == EASY_COUNT) return 1; else return 0; }void search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int first_die) { int x = 0; int y = 0; while (1) { printf("请输入需要排查的坐标,如:1 1\n"); scanf("%d%d", &x, &y); first_die++; //防止第一次暴毙 if (first_die == 1 && mine[x][y] == '1') { while (mine[x][y] == '1') { intialize(mine, ROWS, COLS, '0'); setmine(mine, ROW, COL); }}if (x >= 1 && x <= row && y >= 1 && y <= col) { if (mine[x][y] == '1') { printf("你死了,请再接再厉\n"); print(mine, ROW, COL); break; } else { show[x][y] = search_show(mine, ROW, COL)+'0'; //显示周围的雷数 open(mine,show, x, y,row,col); print(show, ROW, COL); } } else { printf("输入错误,请重新输入\n"); }//判断输赢 int Win = win(show, row, col); if (Win == 1) { printf("恭喜您,胜利了\n"); break; }//标记地雷 int input1 = 0; int input2 = 0; if (x >= 1 && x <= row && y >= 1 && y <= col) {do { printf("请输入标记坐标,输入0 0退出标记\n"); scanf("%d%d", &input1, &input2); if (input1 >= 1 && input1 <= row && input2 >= 1 && input2 <= col) { if (show[input1][input2] == '*') { show[input1][input2] = '#'; print(show, ROW, COL); } else { printf("标记失败,请重新标记\n"); } } else if (input1 == 0 && input2 == 0) break; else { printf("标记错误,请重新标记\n"); }} while (input1&&input2); printf("已退出标记\n"); } } }test.c# define _CRT_SECURE_NO_WARNINGS # include "game.h"void menu() { printf("*********************************\n"); printf("*********1. Play*********\n"); printf("*********0. Exit*********\n"); printf("*********************************\n"); }void game() { char mine[ROWS][COLS] = { 0 }; //存放雷的信息 char show[ROWS][COLS] = { 0 }; //存放排查出的雷的信息 intialize(mine,ROWS ,COLS,'0'); intialize(show,ROWS ,COLS,'*'); //展示棋盘 print(show, ROW, COL); //布置雷 setmine(mine, ROW, COL); //排查 search(mine, show, ROW, COL,0); }int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择>:"); scanf("%d", &input); switch (input) { case 1: printf("game start\n"); game(); break; case 0: printf("已退出游戏\n"); break; default: printf("选择错误,请重新选择\n"); break; } } while (input); return 0; }


以上就是本次的分享内容了,喜欢我的分享的话,别忘了点赞加关注哟!
如果你对我的文章有任何看法,欢迎在下方评论留言或者私信我鸭!
【路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)】我是白晨,我们下次分享见!!

    推荐阅读