扫雷的目录
- 扫雷
- 游戏选择
- 初始化棋盘
- 布置雷
- 打印棋盘
- 排查雷
- 完整代码呈现
- 结尾
扫雷
整个游戏的实现分为五个部分:
- 游戏选择
- 初始化棋盘
- 布置雷
- 打印棋盘
- 排查雷
在文章的最后会有完整的代码呈现
游戏选择
首先是游戏选择部分,你可以在此选择是否开始游戏
且每当结束一把对局,也会回到该界面,再次进行选择
void menu()
{printf(" \n");printf(" 1.paly \n");printf(" 0.exit \n");printf(" \n");}int main()
{int input = 0;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;
}
这里我们用do…while语句配合switch…case语句,实现游戏选择的基本功能
如果对方输入“1”,那么我们将开始游戏,但在此之前会初始化棋盘、并将其打印的
初始化棋盘
我们以一个9×9的棋盘为例,这对应的就是一个9行9列的二维数组
我们都知道扫雷游戏的玩法:点开一个格子,会显示其周围一圈八个格子存在雷的数量。
但倘若我们点的格子恰好在边缘上,这时候再判断周围八个格子是否是雷时会有几个坐标在棋盘外部,这时再通过遍历这八个坐标判断时,会发生数组越界
为了避免这种麻烦,我们再定义一个11×11的二维数组,专门用于判断,并且在超过9×9的地方都赋值0,这样在判断时也不会将其判定为雷
综上:
我们需要设计两个二维数组,一个数组(show)9×9(尽管初始化时我将show初始化成11×11的数组,但实际上只用到了中间的9×9),专门用于存放被排查出的雷的信息,并呈现给玩家;另一个数组(mine)11×11,专门用于判断周围是否有雷,并将排查出来的信息传递给show数组
对于初始化:
mine数组初始化为全’0’,被埋雷的地方则改为’1’;show数组初始化为’*‘,被排查的地方则显示器周围相应的雷的数量,如’2’
代码实现:
#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2void init_board(char board[ROWS][COLS], int rows, int cols, char set)
{int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = set;}}
}void game()
{//定义两个数组char mine[ROWS][COLS];char show[ROWS][COLS];//初始化数组init_board(mine, ROWS, COLS, '0');init_board(show, ROWS, COLS, '*');
}
尽管我们设计了两个数组,但在打印时只会打印show数组,mine数组是不打印的,其存在目的只是为了使show数组能够显示每个格子周围雷的信息
打印结果展示:
看到上面的打印结果或许有人要问:这个行和列旁边的0~9是什么意思啊?
不急,这就涉及到后面内容-棋盘打印了,在文章后续会讲
下面我们先看雷的布置
布置雷
在初始化棋盘完成后,就需要布置雷了
雷的布置要满足随机的要求,所以就要用到随机数rand和srand(注意头文件的引用)
我们提前在main函数中初始化一个随机数发生器srand((unsigned int)time(NULL));
,便于生成随机数
因为雷的布置玩家是不知道的,所以只需要在mine数组中布置即可,即将mine数组中的’0’变成’1’
代码实现:
//设置雷的个数
#define easy_count 10void set_mine(char board[ROWS][COLS], int row, int col)
{int count = easy_count;//布置easy_count个雷,每布置一个就减少1while (count){int x = rand() % row + 1;int y = rand() % col + 1;//该坐标要确定没被布置过雷if (board[x][y] == '0'){board[x][y] = '1';count--;}}
}
这里的int x = rand() % row + 1和int y = rand() % col + 1
是保证布置的雷不会超出9×9的范围
打印棋盘
在布置完雷后,就可以进行打印棋盘供玩家开始排查雷了
所打印的棋盘是不能让玩家知道雷是怎么布置的所以,mine数组不能打印,只需打印show数组即可
代码实现:
void dispaly_board(char board[ROWS][COLS], int row, int col)
{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");}
}
为了使玩家在排查雷时方便输入坐标,我们在棋盘的上侧和左侧标上列号和行号,即在初始化棋盘时见到的那样
排查雷
棋盘被成功打印后就要开始真正的“扫雷”了
玩家在输入一个坐标后,我们需要在mine数组上的该坐标周围8个坐标判断有没有雷,有几颗雷,并将这个数据传给show数组进行显示
同时我们也要给出游戏结束的条件:踩雷了或者非雷的坐标都排查完毕
代码实现:
int get_mine_count(char board[ROWS][COLS],int x,int y)
{return (board[x - 1][y - 1] +board[x - 1][y] +board[x - 1][y + 1] +board[x][y - 1] +board[x][y + 1] +board[x + 1][y - 1] +board[x + 1][y] +board[x + 1][y + 1] - 8 * '0');
}void find_mine(char board1[ROWS][COLS], char board2[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int win = 0;while (win< row * col - easy_count){printf("请输入坐标:");scanf("%d%d", &x, &y);//首先判断输入的坐标是否符合棋盘大小规定if (x >= 1 && x <= row && y >= 1 && y <= col){//再判断这个坐标是否已经排查过了if (board2[x][y] == '*'){if (board1[x][y] == '1'){printf("很遗憾,你被炸死了!\n");dispaly_board(board1, ROW, COL);break;}else{//用来接收该坐标周围的雷数int count = get_mine_count(board1, x, y);//因为我们在show数组中都是字符数字,所以也要让count变成字符数字,所以这里+上了'0'board2[x][y] = count + '0';//进行屏幕清空system("cls");dispaly_board(board2, ROW, COL);//每成功扫一个雷就win++win++;}}else{printf("坐标已被排查,请重新输入:");}}else{printf("坐标非法,请重新输入:");}}if (win == row * col - easy_count){printf("恭喜你,扫雷成功\n");dispaly_board(board1, ROW, COL);}
}
具体排查过程各位可以看代码,是比较好理解的
值得一提的是,在提取坐标周围雷的信息时,我们是将这八个坐标遍历,将这8个字符加起来-8*‘0’,这样就可以得到雷的个数
因为’0’对应的ASCII码值为48,'1’对应49,倘若周围没有雷,则8个48相加减去8乘48等于0,即没有雷,符合要求
完整代码呈现
我写这个游戏时是多文件工程,所以我也就分文件给大家呈现了
main.c
#include"game.h"
void menu()
{printf(" \n");printf(" 1.paly \n");printf(" 0.exit \n");printf(" \n");}void game()
{//定义两个数组char mine[ROWS][COLS];char show[ROWS][COLS];//初始化数组init_board(mine, ROWS, COLS, '0');init_board(show, ROWS, COLS, '*');//布置雷set_mine(mine, ROW, COL);//打印最初的棋盘dispaly_board(show, ROW, COL);//排查雷find_mine(mine, show, ROW, COL);}int main()
{int input = 0;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;
}
game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2//设置雷的个数
#define easy_count 10//初始化数组
void init_board(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盘
void dispaly_board(char board[ROWS][COLS], int row, int col);//布置雷
void set_mine(char board[ROWS][COLS], int row, int col);//排查雷
void find_mine(char board[ROWS][COLS], int rows, int cols);
game.c
#include"game.h"//初始化数组
void init_board(char board[ROWS][COLS], int rows, int cols, char set)
{int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = set;}}
}//打印棋盘
//这里只需要打印中间9*9的棋盘就可以了
void dispaly_board(char board[ROWS][COLS], int row, int col)
{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");}
}//布置雷
//这里只需要在中间9*9的棋盘布置即可,将mine数组中'0'变成'1'
//因为要在棋盘中随机布置雷,所以要用到随机数
void set_mine(char board[ROWS][COLS], int row, int col)
{int count = easy_count;//布置easy_count个雷,每布置一个就减少1while (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 board[ROWS][COLS],int x,int y)
{return (board[x - 1][y - 1] +board[x - 1][y] +board[x - 1][y + 1] +board[x][y - 1] +board[x][y + 1] +board[x + 1][y - 1] +board[x + 1][y] +board[x + 1][y + 1] - 8 * '0');
}//排查雷
//玩家在选定一个坐标后,我们需要在mine数组上的该坐标周围8个坐标判断有没有雷,有几颗雷,并将这个数据传给show数组进行显示
void find_mine(char board1[ROWS][COLS], char board2[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int win = 0;while (win< row * col - easy_count){printf("请输入坐标:");scanf("%d%d", &x, &y);//首先判断输入的坐标是否符合棋盘大小规定if (x >= 1 && x <= row && y >= 1 && y <= col){//再判断这个坐标是否已经排查过了if (board2[x][y] == '*'){if (board1[x][y] == '1'){printf("很遗憾,你被炸死了!\n");dispaly_board(board1, ROW, COL);break;}else{//用来接收该坐标周围的雷数int count = get_mine_count(board1, x, y);//因为我们在show数组中都是字符数字,所以也要让count变成字符数字,所以这里+上了'0'board2[x][y] = count + '0';//进行屏幕清空system("cls");dispaly_board(board2, ROW, COL);//每成功扫一个雷就win++win++;}}else{printf("坐标已被排查,请重新输入:");}}else{printf("坐标非法,请重新输入:");}}if (win == row * col - easy_count){printf("恭喜你,扫雷成功\n");dispaly_board(board1, ROW, COL);}
}
结尾
到这里,扫雷游戏就算是实现了,不过这里的游戏也存在缺陷
我写的代码在排查雷时只能一次排查一个,无法做到像网上游戏一样,有时候可以一次排查一片
其他若有写的不对、不好、不严谨的地方欢迎各位指正
感谢各位的阅读观看,谢谢大家!