一:扫雷游戏原理分析
如何利用C语言中函数和数组的关系,写一个9x9阶的扫雷游戏呢?首先我们要清楚其原理。
在编译器中,我们只能利用控制台输入输出数据,因此,游戏的运行实在控制台实现的。
功能如下:
1>. 玩家可以通过菜单选择游戏继续进行或者退出,
2>. 棋盘为9x9的格子,
3>. 默认布置十个雷,
4>. 可以排查雷的数量:如果所排查的位置不是雷,就标记周围一圈类的数量;如果是雷,就被炸死了,游戏结束,退出游戏;如果把十个都是雷之外的所有位置都找出来了,则排雷成功,游戏结束。
游戏界面如图所示:
1. 游戏的分析
首先我们需要创建一个二维9*9数组用于储存雷并且排查雷
没雷的位置放1,有雷的位置放0
由于我们需要在排查过每个坐标过后标记它位置上的雷的数量;因此若打印雷的个数的信息,将其存放在排查雷的数组中时,会和原本有没有雷的信息相混解决这个问题,我们可以将雷和非雷的信息用字符表示,
为了增加神秘感,我们可以先初始化为show数组为'*'
mine数组初始化字符为'0',布置雷之后存放'1'
char mine[11][11] = {0};
char show[11][11] = {0};
为了使程序结构清晰,我们可以将实现不同功能的代码放到不同的文件中,比如:将函数的声明放到game.h文件中,将函数的实现放到game.c文件中,将游戏的底层运行逻辑放到test.c文件中。
-
test.c文件
void menu()//先用menu函数打印一个菜单,作用是接下来让玩家选择进行游戏还是退出游戏
{
printf("----------扫雷游戏----------\n");
printf("****************************\n");
printf("******** 1. play ********\n");
printf("******** 0. exit ********\n");
printf("****************************\n");
}
-
int main()
{
int count = 10;//存放雷的数量
int input = 0;
do {
menu();//先打印菜单
printf("请输入:");
scanf("%d", &input);//再输入值判断是否进行游戏
//我们可以用switch语句输入值判断游戏是进行还是退出
switch (input)
{
case 1: //若输入1,则进行游戏
game();//调用自己编写的game()函数实现游戏
break;
//每结束一把游戏,玩家可自行选择是否进行下一把游戏,break跳出循环后再输入input选择
case 0: //若输出入0,则退出游戏
printf("退出游戏\n");
break;
default: printf("输入错误,请重新输入:\n");//若输入的既不是1,也不是0,则重新输入
break;
}
} while (input);
return 0;
}
前面我们提到用两个二维数组分别用来存放和展示雷的信息
void game()
{
printf("游戏开始:\n");
调用game.c文件中的函数实现游戏
char mine[ROWS][COLS];//二维数组存放雷
char show[ROWS][COLS];//二维数组存放排查出的雷的信息
Initboard(mine, ROWS, COLS, '0');//初始化存放雷的棋盘为' 0 '
Initboard(show, ROWS, COLS, '*');//初始化展示棋盘 ' * '
Displayboard(show, ROW, COL);//展示棋盘
SetMine(mine, ROW, COL);//布置雷
FindMine(mine, show, ROW, COL);//排查雷
- 将函数的声明放到 game.h 文件中去:
#include<stdio.h>//在其头文件中将所需的头文件都放在一起,后面test.c和game.c函数要使用时,只需引用自定义头文件#include"game.h"就行(用户自定义头文件用" "引用)
//随机数的生成需要包含
#include<time.h>
#include<stdlib.h>
//两个头文件
//雷的排列为9乘9,初始化行和列都为9
#define ROW 9
#define COL 9
//可以任意改变雷的数量,
#define EASY_COUNT 10
//棋盘排列为11乘11,比雷多两行两,方便计算边缘位置的雷的数量
#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘
void Initboard(char board[ROWS][COLS], int rows, int cols, int set);
//打印棋盘
void Displayboard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char mine[ROWS][COLS], int row,int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
- 将游戏的实现放到 game.c 文件中去:
void Initboard(char board[ROWS][COLS], int rows, int cols, int set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set; //对棋盘进行初始化,放入字符 '0';
}
}
}
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= col; i++)//第一行给列进行标号
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);//每行开头对行进行标号
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)
{
//rand()函数随机生成一个坐标
int x = rand() % row + 1;//1-9
int y = rand() % col + 1;//1-9
if (board[x][y] == '0')//初始化为字符'0',都没有雷
{
board[x][y] = '1';//在此坐标位置布置雷
count--; //每布置一个雷,雷的总数减一,当count为0时,判断循环的条件
//不成立,退出循环
}
}
}
//我们需要统计所输入坐标外一层的雷的个数,可以用mine数组中的字符提取出来('0'或'1'),然后进行字符型数字与十进制数字之间的转换就行了,方法如下:
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)
{
//给定x,y坐标用于确定二维数组中某一点的位置
int x = 0;
int y = 0;
int win = 0;
while (win < row * col - EASY_COUNT)
//当棋盘大小9x9行共81个时,布置有x个雷,若查找了81-x个坐标仍未排查到雷,那么说明剩余的位置全为雷
//因此就可以判定游戏成功了,可以跳出循环了
{
printf("请输入的坐标:");
scanf("%d%d", &x, &y); //输入坐标信息
if (x >= 1 && x <= row && y >= 1 && y <= col)//在9x9棋盘中查找雷
{
if (mine[x][y] == '1')//如果排查到了雷,那么肯定被炸死了,就跳出循环
{
printf("很遗憾,你被炸死了\n游戏结束\n");
Displayboard(mine, ROW, COL);//但是要死的明明白白,就要让玩家看到所有雷的信息
break;
}
else
{
int m = GetMinecount(mine, x, y);
//如果还未排查到雷,那么通过排查他周围的雷的数量就可以排查其他位置的雷了,但棋盘中存放
//的是字符类型的数据,因此排查出的值(0 - 9)就要通过转化成字符( '0 '-- '9' )进行储存
show[x][y] = m + '0';//将值转化为字符型储存
Displayboard(show, ROW, COL);//然后再打印排查后的棋盘信息,进行下一次雷的排查
win++;//每排查到一次到非的值,就说明离成功更进一步,非雷的数量加一
}
}
else
{
printf("非法坐标,请重新输入\n");//若输出的坐标不在9x9的棋盘中,那么就需要重新输入坐标值再次判断
}
}
//当所有非雷的位置排查完之后,剩下的位置都是雷,说明游戏成功,因此就可以退出游戏了,
// 最后打印出所有雷所在位置的信息
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
Displayboard(mine, ROW, COL);
}
}
代码的完整版在函数和数组实践:扫雷游戏/函数和数组实践:扫雷游戏 · fanyunxi/范云熙的C仓库 - 码云 - 开源中国 (gitee.com)