在学了数组、函数和分支循环语句后,这次我们来写一个简易的扫雷游戏
1.扫雷游戏的功能
- 使用简易的菜单实现经典的扫雷游戏
- 游戏可以通过菜单实现继续玩或者退出游戏
- 扫雷的棋盘是9*9的格子
- 默认随机布置10个雷
- 可以排查雷
- 如果位置不是雷,就显示周围有几个雷
- 如果位置是雷,就炸死游戏结束
- 把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束
2.简易菜单
- 这个菜单的代码可以参考上一篇的菜单,这里就略过了(链接在这里)
- 这里有为了让代码看起来能更结构化,
- 把文件中写游戏的测试逻辑放在test.c中,
- 把文件中写游戏需要的数据类型和函数声明等放在game.h头文件中,
- 把文件中的游戏函数等放在game.c中
- 这样所有的申明都可以放在game.h中,
- 在test.c中只要引入game.h这个头文件就可以使用所有需要的函数了
- 下面是菜单的代码
- 因为这里需要在三个文件中编辑,所以我在每段代码的第一行会表明在哪个文件
#include "game.h" //test.c文件
int main()
{
int flag = 0;
srand((unsigned int)time(NULL)); //设置随机数的种子
do
{
printf("**************************\n");
printf("*********开始游戏:1*******\n");
printf("*********退出游戏:0*******\n");
printf("**************************\n");
printf("是否开始游戏(0/1):");
scanf("%d", &flag);
switch (flag)
{
case 1:
game();
break;
case 0:
printf("您已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (flag);
return 0;
}
3.游戏的实现
3.1 游戏的分析和设计
- 扫雷的过程中,布置的雷和排查出的雷的信息都需要存储,所以我们需要⼀定的数据结构来存储这些信息,
- 因为我们需要在9 * 9的棋盘上布置雷的信息和排查雷,我们首先想到的就是创建⼀个9 * 9的数组来存放信息,
- 然后把有雷的地方储存记为1,没有雷的地方记为0,如下图:
- 但当我们写排雷代码的时候发现,排雷需要计算周围8个格子的信息,
- 当我们在9*9边界排雷的时候发现就会越界了,所以我们打算把数组的范围再往外扩大一格,这样就解决了越界的问题,如下图:
- 我们接着分析,如果我们输入坐标为(3,6)的位置进行排雷,
- 此时周围有一个雷,那么我们该怎么把这个雷的个数 1 储存起来呢,直接打印在这个棋盘上吗?
- 如果这样的话,那么这个 1 到底是原来随机生成的呢,还是我们排雷后代表周围雷的个数呢,就会产生歧义了,
- 此时我们可以再定义一个数组,让一个数组来存储随机生成的雷,另外一个显示周围雷的个数,
- 并且为了保持神秘性,显示周围雷的那个数组一开始全都为“ * ”,
- 此时就可以定义两个字符数组开始敲代码了
3.2 初始化数组
#pragma once //game.c文件
#include <stdio.h>
#define ROW 9
#define COL 9 //9*9的棋盘
#define ROWS ROW+2
#define COLS COL+2 //定义11*11的数组
#define NUM 10 //定义雷的个数
//game.c文件
void chushihua(char arr[ROWS][COLS], int row, int col, char s)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
arr[i][j] = s;
}
}
}
- 这里用了宏定义是为了方便之后改参数,比如你想玩20 * 20的棋盘了,你就直接把#define后的参数改了就行
3.3 布雷
- 要布雷就要用到能生成随机数的函数,这里我们用rand(具体语法请点击此处)
void bulei(char arr[ROWS][COLS], int row, int col) //game.c文件
{
int n = NUM;
while (n != 0)
{
int a1 = rand() % row + 1;
int a2 = rand() % row + 1;
if (arr[a1][a2] == '0')
{
arr[a1][a2] = '1';
n--;
}
}
}
- 这里如果赋值随机数的时候发现之前赋值过了,就要重新赋值,所以这个循环的执行次数大于等于10
3.4 计算周围雷的个数
void jisuan(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int a, int b) //game.c文件
{
int sum = 0;
for (int i = a - 1; i <= a + 1; i++)
{
for (int j = b - 1; j <= b + 1; j++)
{
sum += arr2[i][j] - '0';
}
}
arr1[a][b] = (char)(sum + '0');
}
3.5 打印排雷后的数组
void print(char arr[ROWS][COLS], int row, int col) //game.c文件
{
for (int i = 0; i <= col; i++)
{
printf("%2d ", i);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%2d ", i);
for (int j = 1; j <= col; j++)
{
printf("%2c ", arr[i][j]);
}
printf("\n");
}
printf("\n");
}
- 这里在printf函数中规定了打印2个字符
- 是为了防止当这不是9 * 9,而是20 * 20的棋盘的时候
- 保证整个棋盘是对齐的
- 加了 2 之后的是这样的
3.6 标记功能
- 通过输入坐标后再输入一个数(0,1,-1)实现对坐标处的探雷,标记,解除标记
int biaoji(char arr1[ROWS][COLS], int a, int b, int c) //game.c文件
{
if (c == 0)
{
return 1;
}
else if (c == 1)
{
if (arr1[a][b] == '*')
{
arr1[a][b] = '$';
print(arr1, ROW, COL);
return 0;
}
else
{
printf("这个位置已经排过雷了,请重新输入\n");
return 0;
}
}
else if (c == -1)
{
if (arr1[a][b] == '$')
{
arr1[a][b] = '*';
print(arr1, ROW, COL);
return 0;
}
else
{
printf("此处未被标记\n");
return 0;
}
}
else
{
printf("请选择是否要标记,标记则在坐标后加1,否则加0\n");
return 0;
}
}
3.7 排雷
最核心的还是排雷的代码,可以调用之前的函数来实现功能
void pailei(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col)//game.c文件
{
int n = row * row - NUM;
while (n > 0)
{
int a, b;
int c;
printf("请输入排雷的坐标以及是否要标记(标记为1,否则为0, 撤回标记为-1,输入的三个数用空格隔开):");
scanf("%d %d %d", &a, &b, &c);
if (biaoji(arr1, a, b, c) == 1)
{
if (a >= 1 && a <= ROW && b >= 1 && b <= COL)
{
if (arr1[a][b] == '*')
{
if (arr2[a][b] == '1')
{
printf("您被炸死了,雷的分布图为:\n");
print(arr2, ROW, COL);
break;
}
else
{
jisuan(arr1, arr2, a, b); //计算坐标周围八格的雷数
n--;
print(arr1, row, col); //打印数组
//print(arr2, row, col); //排雷后打印雷的位置
}
}
else
{
printf("您已探测过此处了,请重新输入\n");
}
}
else
{
printf("输入坐标超出范围,请重新输入\n");
}
}
}
if (n == 0)
{
printf("恭喜你,排掉了所有的雷\n");
print(arr2, ROW, COL);
}
}
3.8 整合代码
void game() //game.c文件
{
printf("<————开始游戏————>\n");
printf("共有%d个雷\n", NUM);
char arr1[ROWS][COLS];
char arr2[ROWS][COLS];
chushihua(arr1, ROWS, COLS, '*');
chushihua(arr2, ROWS, COLS, '0'); //初始化数组
print(arr1, ROW, COL);
bulei(arr2, ROW, COL); //11*11的范围布NUM个9*9的随机雷
pailei(arr1, arr2, ROW, COL);
}
- 最后将这些函数整合起来实现扫雷的功能
- 别忘了在game.h文件里把所有的函数都申明了
void dayin(char arr[ROWS][COLS], int row, int col); //game.h文件
void chushihua(char arr[ROWS][COLS], int row, int col, char s);
void print(char arr[ROWS][COLS], int row, int col);
void bulei(char arr[ROWS][COLS], int row, int col);
void jisuan(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int a, int b);
void pailei(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col);
int biaoji(char arr1[ROWS][COLS], int a, int b, int c);
void game();
- 后续对扫雷游戏的改进想要源代码同学的请自行领取(git)
最后,
如果上述代码或表述有问题,
欢迎一起讨论