1.主函数(玩家选择流程)
之前博客有说明,因此这里直接给出
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
//玩游戏
game();
break;
case 0:
//退出
break;
default:
printf("输入错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
2.游戏部分(game函数)
左图为扫雷的初始界面,可以看到,游戏界面是一个 9×9 的棋盘,因此我们可以使用二维数组,而上图的10为雷的数量。而右图是扫雷中的界面,若用数组存储,那么在这个数组中应有十个元素存储的是代表雷的字符,而存储雷的位置不应被玩家所看到,因此我们事实上需要两个数组,一个用来存储雷,一个如右图,打印出来雷的信息。
char mine[ROWS][COLS] = { 0 }; //存储雷(不显示)
char show[ROWS][COLS] = { 0 }; //打印雷的信息(给玩家看)
#define ROWS 11
#define COLS 11
数组定义如上,依旧采用了符号常量,但如上图数组是9×9,我却将常量设为11,这是因为检查雷的数量时,需要将所指定下标元素一周的元素都访问并检查是不是雷,如下图:
这样,当我们输入的下标是边缘时,程序实际上需要访问并检查的元素应不仅是我们可视的棋盘界面,因此我们在定义棋盘时应比我们看到的大一圈,这样的实现方式其实就是将行数,列数比玩家能看到的多2
否则,有可能造成严重后果,若我们不定义为11而定义为9,那么当输入下标为边缘时,就会造成数组越界访问
Initboard函数
首先,我们将两个棋盘都初始化,建议将mine数组全部初始化为字符 '0' (原因在下面会说明),将show数组全部初始化为字符 '*',代码实现如下:
void Initboard(char arr[ROWS][COLS], int rows, int cols, char ch)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
arr[i][j] = ch;
}
}
}
这里的参数不仅有字符指针,数组的行数,列数,第四个参数是我们在传参时自己希望初始化的字符,因为此函数需要为两个数组初始化,因此需要不同的字符
Setmine函数
数组被初始化后,就需要向数组中布置雷了,此时我们需要用到的是mine数组,因为需要电脑以下标的方式随机产生雷,因此和前两个游戏一样,需要用到 rand( ),srand( ),time( )函数
在定义数组大小时,为了防止越界定义的数组行列都比玩家可以看到的多2,但布置雷时,其实使用玩家可以看到的9×9数组即可,因此定义两个符号常量如下,为了方便修改,雷的数量也同样定义为符号常量:
#define ROW 9
#define COL 9
#define COUNT 10
函数代码实现如下:
void Setmine(char mine[ROWS][COLS], int row, int col)
{
//雷的数量
int count = COUNT;
int x = 0;
int y = 0;
while (count)
{
//随机产生的数为1到row
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] == '0')
{
//布置雷的下标元素被赋值为'1'
mine[x][y] = '1';
//每次布置一个雷后,雷的数量减1
count--;
}
}
}
Printboard函数
此函数用于将数组打印到屏幕上让玩家可以看到,只需要打印show数组,根据打印出的雷的信息来判断下一步选择的下标位置,代码实现如下:
void Printboard(char arr[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 ", arr[i][j]);
}
printf("\n");
}
}
为了方便玩家输入坐标,在编写打印函数时,在最上和最左侧分别打印了行号和列号
Finemine函数
最后玩家需要排查雷,当玩家输入的坐标刚好存放了雷时,就提示被炸死了并结束本次游戏,否则就继续,直到所剩下标位置都为雷时,就提示排雷成功并结束本次游戏
首先,将代码给出如下:
void Finemine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
//已经排过的位置的数量
int ground = 0;
//除了存放雷的位置,还有其它位置没排时,循环继续
while (ground<row*col-COUNT)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
//判断坐标非法性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//坐标位置为雷
if (mine[x][y] == '1')
{
printf("被炸死了\n");
Printboard(mine, ROW, COL);
break;
}
else
{
int count = Numbermine(mine, x, y);
show[x][y] = count + '0';
Printboard(show, ROW, COL);
ground++;
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
//除了雷的位置以外的下标都排过了,游戏胜利
if (ground == row * col - COUNT)
{
printf("排雷成功\n");
Printboard(mine, ROW, COL);
}
}
此函数需要检查下标周围雷的数量信息并把这些信息存放并打印给玩家,因此所给参数应同时包括show,mine数组的地址,如上代码中有一函数Numbermine用于给出输入下标周围雷的数量
Numbermine函数
mine数组初始化时,我们将里面的元素都初始化为字符 '0',而在Setmine函数中电脑将随机设置雷的位置赋值为字符 '1',根据ASCII表,字符'0'和字符‘1’相差为1,因此我们只需要将玩家输入的坐标周围一圈8个数组元素的值相加,相加后的和再除以8个字符'0'的和即可得到周围雷的数量,这也是初始化为'0'的原因,代码实现如下:
static int Numbermine(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x - 1][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x][y - 1] -
8 * '0';
}
static关键字将此函数改为只能在本源文件被使用
至此,游戏实现所需要的函数已经定义完毕,game函数代码实现如下:
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
Initboard(mine, ROWS, COLS, '0');
Initboard(show, ROWS, COLS, '*');
//布置雷
Setmine(mine, ROW, COL);
//打印
Printboard(show, ROW, COL);
//排查
Finemine(mine, show, ROW, COL);
}
game.h头文件如下:
#define ROWS 11
#define COLS 11
#define ROW 9
#define COL 9
#define COUNT 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//初始化
void Initboard(char arr[ROWS][COLS], int rows, int cols, char ch);
//打印
void Printboard(char arr[ROWS][COLS], int row, int col);
//布置雷
void Setmine(char arr[ROWS][COLS], int row, int col);
//排查雷
void Finemine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
运行结果如下:
失败:
成功:
为了方便测试,我将雷的数量修改为80,并且将雷的位置提前打印出来