目录
1.了解扫雷游戏的规则:
2.在编译器上设计扫雷游戏:
(1)写入主函数:
(2)写入菜单及菜单选择的函数:
(3)写入完成扫雷游戏的函数game()
3.完整代码
4.代码测试
扫雷游戏是我们这一代人小时候都会玩的游戏,那如何用C语言来实现一个简单的扫雷游戏呢?
让我们一起来逐步学习吧~
1.了解扫雷游戏的规则:
(1)游戏可以通过菜单实现继续玩或者退出游戏
(2)扫雷游戏的棋盘是9*9的格子
(3)默认随机布置10个雷
(4)可以排查雷
a.如果位置不是雷,就显示周围有几个雷
b.如果位置是雷,就炸死游戏结束
c.把除10个类之外的所有非雷都找出来,排雷成功,游戏结束
棋盘示例:
2.在编译器上设计扫雷游戏:
在进行扫雷游戏的设计时,应在同一项目下加入三个文件(如图):
首先,在test.c文件中完成游戏的测试逻辑。
为避免所有的指令全部位于主函数之内,可以采用函数调用,来使程序的内容整体更加清晰、明确。
确定头文件:
#include
(1)写入主函数:
int main(){test();//测试逻辑return 0;}
(2)写入菜单及菜单选择的函数:
一般游戏的开始总会有菜单界面进行选择。
例如:“开始游戏”和“结束游戏”。用户通过选择“1”,“0”来开始或结束游戏。
该选择的实现可以通过switch循环语句实现
想多次进行游戏则可以通过do……while循环语句来实现:
void test{do{menu();//menu为菜单界面} while ();}
此时进行修整后的菜单及选择界面的代码及运行结果如下:
#includevoid menu()//仅用于打印菜单{printf("***************************\n");printf("******* 1. play *******\n");printf("******* 0. exit *******\n");printf("***************************\n");}void test()//用于菜单选择的实现{int input = 0;do{menu();printf("请选择:>");scanf_s("%d", &input);//下一步识别1、0、其他数switch(input){case 1:printf("扫雷\n");//输入值为 1 开始游戏break;case 0:printf("游戏结束,退出游戏\n");//输入值为 0 结束游戏break;default:printf("选择错误,重新选择\n");//输入其他数,重新进行选择}} while (input);//只有当输入值为 0 时才停止循环,否则将一直进行循环}int main(){test();return 0;
这样游戏的菜单界面就设计好啦~
那我们开始游戏的时候可就不能只打印“扫雷”两个字喽!要将它换成我们的游戏函数game()了
(3)写入完成扫雷游戏的函数game()
假设,对棋盘进行排查,则会发现
在排查(2,5)这个坐标时,我们访问周围的一圈八个黄色位置,统计周围雷的个数是1
在排查(8,6)这个坐标时,我们访问周围的一圈八个黄色位置,统计周围雷的个数时,最下面的三个坐标就会越界,为了避免越界的情况,我们在设计时应该给数组扩大一圈,而我们的雷仍应该布置在9*9的坐标上,即创建成11*11的区域。
(起始棋盘)
(优化后的棋盘)
a.规定雷的标记
从上面的棋盘中我们设定了:‘1’为雷 ‘0’为非雷但当我们将雷排出时,原本‘0’所在的位置见会被改写成‘1’代表被排除,但此时将会与用‘1’代表的雷混淆。那么此时~聪明的我们肯定会想到解决的办法,那就是–设置两个数组,一组用来设置雷,一组用来排雷。如图:
b.在设计棋盘
时要对棋盘进行初始化,为了方便之后对游戏的拓展,我们还需要在game.h的头文件中设计:
#pragma once#define ROW 9//行#define COL 9//列#define ROWS ROW+2#define COLS COL+2
此时要记得在文件test.c中声明我们自己的头文件,即:
#include “game.h”
要注意声明自己的头文件时不能使用要使用””
c.初始化棋盘
时利用文件game.c执行棋盘的初始化,此时,文件test.c中的game函数中应该如下
void game(){char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'//初始化棋盘InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');}
此时的game.c文件中的InitBoard函数应该如下:
#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;}}}
d. 打印棋盘
打印棋盘时主要是打印show函数中的棋盘,则在game.h文件中声明打印棋盘的函数,并在game.c文件中写入初步打印棋盘的函数。
void DispiayBoard(char board[ROWS][COLS], int row, int col);//因为棋盘只用打印9*9棋盘,所以只用传输9行9列
void DispiayBoard(char board[ROWS][COLS], int row, int col){int i = 0;printf("---------扫雷游戏---------\n");//美化棋盘for (i = 0; i <= col; 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");}}
此时的运行结果如图:
e.布置雷
布置雷是在数组mine中布置的,这些雷在我们的游戏条件下是10个,而且是随机的,所以在test.c文件中的game函数中需要添加一个布置雷的函数SetMine并在game.c文件中确定函数。
因为要使用随机数所以在game.h文件中需要包含库函数:
#include
#include
#define EASY_COUNT 10//确定雷的个数
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--;}}}
d.排除雷需要同时借助mine和show数组,构建函数FindMine进行排查。
如图 即为此处的排除雷的函数代码:
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');}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 ");scanf("%d %d", &x, &y);if (x >= 1 && x = 1 && y <= col)//判断坐标是否有效{if (mine[x][y] == '1')//判断是否是雷{printf("很遗憾,你被炸死了\n");DispiayBoard(mine, ROW, COL);break;}else{int count = GetMineCount(mine, x, y);//增加一个函数,用来计算输入的坐标周围八个位置中总共的雷的个数show[x][y] = count + '0';DispiayBoard(show, ROW, COL);//每排除一个便,打印一次此时的棋盘win++;//每排除一个便加一}}else{printf("坐标非法,重新输入\n");}}if (win == row * col - EASY_COUNT)//所有不是雷的坐标全部找到,结束游戏{printf("恭喜你,排雷成功\n");DispiayBoard(mine, ROW, COL);}}
此时所有的代码都已准备就绪:
3.完整代码
game.h
#pragma once#include#include#include#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 DispiayBoard(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
#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 DispiayBoard(char board[ROWS][COLS], int row, int col){int i = 0;printf("-------扫雷游戏-------\n");//美化棋盘for (i = 0; i <= col; 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");}}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 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');}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 ");scanf("%d %d", &x, &y);if (x >= 1 && x = 1 && y <= col)//判断坐标是否有效{if (mine[x][y] == '1')//判断是否是雷{printf("很遗憾,你被炸死了\n");DispiayBoard(mine, ROW, COL);break;}else{int count = GetMineCount(mine, x, y);//增加一个函数,用来计算输入的坐标周围八个位置中总共的雷的个数show[x][y] = count + '0';DispiayBoard(show, ROW, COL);//每排除一个便,打印一次此时的棋盘win++;//每排除一个便加一}}else{printf("坐标非法,重新输入\n");}}if (win == row * col - EASY_COUNT)//所有不是雷的坐标全部找到,结束游戏{printf("恭喜你,排雷成功\n");DispiayBoard(mine, ROW, COL);}}
test.c
#include"game.h"void menu()//仅用于打印菜单{printf("***************************\n");printf("******* 1. play *******\n");printf("******* 0. exit *******\n");printf("***************************\n");}void game()//完成扫雷游戏{char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'//初始化棋盘InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//布置雷SetMine(mine, ROW, COL);//先布置雷,再打印雷更符合逻辑//打印棋盘DispiayBoard(show, ROW, COL);//排除雷FindMine(mine, show, ROW, COL);}void test(){int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);//下一步识别1、0、其他数switch(input){case 1:printf("一共有十个雷,请找出");game();//输入值为 1 开始游戏break;case 0:printf("游戏结束,退出游戏\n");//输入值为 0 结束游戏break;default:printf("选择错误,重新选择\n");//输入其他数,重新进行选择}} while (input);//只有当输入值为 0 时才停止循环,否则将一直进行循环}int main(){test();return 0;}
4.代码测试
此时一共有八十一个坐标,而实际上的雷只有十个,如果想要测试代码是否能正常运行到结束,需要,耗费很长时间,若中途游戏失败,还需要重新进行,所以我们要选用更便捷的方式来测试。即:
设置雷的个数为80个,此时只有一个位置不是雷,在进行排雷之前直接显示出雷的位置,即可测试是否可以顺利结束。
如图中的运行结果:
以上便是简易的扫雷游戏的代码设计过程,这只是最简易的,欢迎大家继续拓展呦~
如果代码有用,记得一键三连呦~
在线扫雷游戏:http://www.minesweeper.cn/