提示:此扫雷只是简易版,完善了基本的功能,需要什么拓展功能请留言,我以后会出。源码我放在我主页我分享的文件里,需要自取。
C语言小游戏-扫雷详解
扫雷的基本逻辑
提示:首先编写扫列游戏前我们必须弄懂这个游戏怎么玩,怎么判断输赢以及一些运行逻辑:
如图所示,我们从中可以得到信息:
1,扫雷界面是由一个 长 * 宽得到的格子的集合
2,点击方块,方块会得到一个数字,这个数字表示在此坐标的周围8个坐标中有一个雷。
3,输赢条件:踩到雷输,假设这个棋盘埋了10个雷,那么只要棋盘上只存在10个坐标的时候就赢
注意:但是在c语言中我们现在不采用这种界面,我们输出棋盘的样式主要是由‘*’代表没排雷前的坐标样式用Printf输出。
一、创建项目以及文件
1,创建项目Saolei
2,在头文件中创建 game.h文件,主要用来进行符号的定义,以及函数的声明
3,在源文件中创建text.c文件,主要用来编写main函数进行游戏测试运行。
4,在源文件中创建game.h文件,主要用于函数的封装,函数的主体部分的编写。
二、编写程序
main函数及菜单打印函数
main函数主体代码:
int main() {
int input = 0;
do {
menu(); //游戏菜单打印函数
printf("请选择:--->\n");
scanf("%d",&input);
switch (input) {
case 1:
game(); //游戏的运行逻辑函数
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
讲解:
1,menu,函数是游戏菜单函数,用来打印游戏界面
2,scanf输入的值好让玩家进行选择所以用循环控制,当玩家选择为非0时条件为真,执行循环;当玩家选择为0时条件为假,退出循环。
3,因为游戏菜单至少要打印一次,所以这里选择的是do…while…语句
menu函数:(注意menu函数和main函数在同一个文件里)
void menu() {
printf("******************************************\n");
printf("************ 1. PLAY ***********\n");
printf("************ 0. EXIT ***********\n");
printf("******************************************\n");
}
1.游戏逻辑部分编写
在上面,我们虽然实现了游戏菜单的功能,但是游戏的逻辑部分我们还没完成,接下来我们看游戏逻辑应该怎么设置:
void game() {
//初始化棋盘
//显示打印棋盘
//布置雷
//排查雷
}
以上就是我们要实现的4个游戏逻辑
初始化棋盘函数
注意:接下来的函数我们都在game.c文件里进行函数主体部分的编写,并且要在头文件game.进行声明
棋盘的逻辑及InitBoard(初始化棋盘函数)
我们要初始化棋盘,就必须得现有棋盘,为了减小代码的工作量,我们这里就用设置两个二维数组,设置两个棋盘,
一个是mine棋盘,用来存放埋雷的信息
一个是show棋盘用来存放玩家排雷的信息
void game() {
char mine[ROWS][COLS] = {0};
char show[ROWS][COLS] = {0};
//初始化棋盘
InitBoard(mine,ROWS,COLS,'0');//初始化字符为‘0’;
InitBoard(show,ROWS,COLS,'*');//初始化字符为‘*’;
//显示打印棋盘
//布置雷
;
//排查雷
}
这里为什么要初始化字符为字符0和字符*
1,初始化mine 数字为字符 0 ,是因为我们用字符 0 代表这个坐标没有雷,用字符1在mine数组代表有雷,方便我们后面进行排查雷之后显示该位置周围有几个雷的判断。
2,初始化show数组为字符*,是因为在这里我们把棋盘看成是用组成的棋盘所以这里用。
棋盘这里定义的是符号,如图下在头文件声明:
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EAY_COUNT 10(这里下一个函数会用到这个符号)
InitBoard函数体:
void InitBoard(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;
}
}
}
显示打印棋盘函数Displayboard()
//打印棋盘
void Displayboard(char board[ROWS][COLS], int row, int col) {
int i = 0;
int j = 0;
printf("=======扫雷========\n");
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"); //打印完换行
}
这里需要注意的就是:
1,要打印行数来观察坐标,使游戏更容易上手
2,列数坐标也需要打印
布置雷函数SetMine()
void SetMine(char mine[ROWS][COLS], int row, int col) {
int count = EAY_COUNT; //埋雷的数量为10个,也就是EAY_COUNT符号定义所代表的数字
//每次埋雷减少一个知道count为假
while (count) {
int x = rand() % row + 1;
int y = rand() % col + 1; //相当于膜上9,余数的取值范围为0-8,在加上1取值范围就变成了1-9
if (mine[x][y] == '0') {
mine[x][y] = '1';
count--;
}
}
}
1,时间戳库函数的调用要引用头文件,不然会报错
2,rand()函数调用之后,要设置srand函数
3,之后给x,y设置随机的数,然后在棋盘随机位置埋下10个雷也就是我们定义的外部符号EAY_COUNT = 10 =count变量
排查雷函数FindMine()
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 - EAY_COUNT) {
printf("请输入要排查的坐标:--->");
scanf("%d %d",&x,&y);
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col) {
if (show[x][y] == '*') { //判断坐标是否已经被排查
if (mine[x][y] == '1'){ //坐标是雷,被炸死
printf("很遗憾,你被炸死了!!!!!\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("该位置已经被排查!\n");
}
}
else {
printf("排查的坐标非法,请重新输入:--->\n");
}
}
//成功之后提示
if (win == row * col - EAY_COUNT) {
printf("恭喜你,排雷成功了!!\n");
}
}
这里需要注意的是:
1,判断条件和循环嵌套容易出错
统计坐标周围雷的数量函数 GetMineCount
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][y + 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0');
}
//因为之前定义埋雷数组的值为字符1和字符0.1表示有雷,0表示没雷,所以想要得到一个坐标周围8个坐标雷的数量
//就应该把所有字符相加在减去8个字符0,就可以得到数据了,因为字符0-数字0等于数字0,所以得到的就全是有雷的数量的数据
//坐标一定要输对,,这里容易写漏或者写错
总结(编写项目时的注意事项,以及容易发生的错误)
1,写项目时在Text.c文件中,text函数里调用的函数要在头文件game.h中进行声明。
2,在game.h声明的函数要在game.c中进行创建
3,注意函数的返回值类型,以及实参和形参的类型定义是否相同
4,一定要写注释,增强代码的可读性,方便调试,不易出错。
5,注意scanf()里绑定变量前面要加取地址符号&