友友们好,今天和大家一起做一个简单的C语言小游戏——扫雷小游戏。
游戏规则如下:
扫雷的规则很简单。盘面上有许多方格,方格中随机分布着一些雷。你的目标是避开雷,打开其他所有格子。一个非雷格中的数字表示其相邻8格中的雷数,你可以利用这个信息推导出安全格和雷的位置。打开所有安全格将被判定为胜利,打开雷将被判定为失败。
目录
实现思路
一、制作一个游戏菜单
二、构建游戏的基本逻辑结构
三、进入游戏的制作
1、定义两个一样的数组
编辑
2、初始化数组
3、打印盘面
4、布置雷
5、排查雷
·这个坐标不是雷,提示周围有几个雷
·这个坐标是雷,游戏结束
·所有非雷位置都找到了,游戏胜利
6、game函数的实现
四、扫雷游戏的实现
首先,制作一个游戏菜单,而后构建整个游戏的基本逻辑结构,然后进入游戏的制作。首先要在盘面上随机给出10个雷的位置; 然后玩家需要在盘面的合法位置排雷,如果在非法位置,应给出相应提示;在排雷的同时要判断游戏是否结束,如果结束需要判断胜负。
接下来我们就以这个基本思路来进行代码的实现。
首先,我们要制作一个游戏菜单。我们用一个简易的函数来实现他。
void menu()
{
printf("*********************************\n");
printf("******* 扫雷小游戏 *********\n");
printf("******* 1、play *********\n");
printf("******* 0、exit *********\n");
printf("*********************************\n");
}
我们在主函数中可以调用这个函数来实现打印菜单的目的。
制作完菜单后,我们需要构建这个游戏的基本逻辑结构。
首先需要明确我们的需求: 1、我们可以通过输入 1 / 0 来选择开始或结束游戏
2、如果一把玩完不过瘾,我们可以通过选择来再玩一把
· 我们运用分支语句的知识来实现第一个需求。
在这里我使用switch语句,定义一个整型来存放输入的数字,如果输入的数字是 1 ,则提示“开始游戏”;如果输入的数字是 0 ,则提示“结束游戏”;如果输入了 1/0 以外的数字,则我们提醒他输错了,重新输入。
· 我们通过循环来实现第二个需求。
在这里使用do... while() 循环,将定义的整型放在() 里作为判断条件。当我们输入 1 ,为非0,判断为真,游戏继续;当我们输入 0 ,判断为假,游戏结束;当我们输入 1/0 以外的数字,为非0,判断为真,可以继续循环让我们重新判断。
int main()
{
int input;
//先输入一个input判断要不要进入游戏,将其也设为循环的判断条件
do {
menu();
printf("请输入->");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game();
//如果输入1,说明要玩游戏,封装一个game函数来包含游戏内容
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输错啦,请重新输入\n");
break;
}
} while (input);
return 0;
}
从代码运行结果来看,满足了我们提出的两点需求。
两个数组,一个展示,一个放雷
所以我们需要定义两个 11*11的数组,一个用来存放雷的数据,一个用来显示。
为了后期调试的方便,我们可以将数组参数使用#define标识符替换列表中的参数。
#include
#include //srand函数的头文件
#include //time函数的头文件
#define ROW 9 //实际使用的行
#define COL 9 //实际使用的列
#define ROWS 11 //数组使用的行
#define COLS 11 //数组使用的列
#define COUNT_EASY 10
//简单版本有10个雷
首先我们封装一个game函数,将实现游戏的内容都放在game函数中。定义两个字符型的二维数组,将二者初始化。
//初始化数组
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
int x = 0;
int y = 0;
for (x = 0; x < rows; x++)
{
for (y = 0; y < cols; y++)
{
board[x][y] = ret;
}
}
}
void game()
{
//为了方便,把两个数组定义成完全一样的
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化两个数组,传对应的参数进去
//将雷盘先全都定义为0
//将显示盘定义为*
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
}
我们先清楚盘面的格式为:11 * 11 的正方形;其中只需打印中间的9*9,所以我们传ROW与COL进去即可;为了格式好看与查找方便,我们还可以添加一些表头与分隔。
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
printf("--------扫雷---------\n");
for (x = 0; x <= row; x++)
{
printf(" %d", x); //打印坐标提示行
}
printf("\n");
for (x = 1; x <= row; x++)
{
printf(" %d", x); //打印坐标提示列
for (y = 1; y <= col; y++)
{
printf(" %c", board[x][y]);
}
printf("\n");
}
printf("---------------------\n");
}
//打印的时候传过去的数组还是11*11的,数组是不会变的,不会因为你想打印的是9*9的就变成9*9的数组
//因为我们只想打印出9*9的格子,所以传过去的是ROW和COL
简易版的9*9盘面内有10个雷,我们可以用rand函数来生成随机值来作为雷生成的坐标。生成雷时需要注意,雷的坐标需要是一个合法坐标,我们可以将生成坐标的过程放进循环里,当雷的坐标为合法坐标时跳出循环。注意将坐标适当处理。我们封装一个函数,在game函数中调用来实现该功能。
//布置雷
void Setmine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = COUNT_EASY; //雷的数量
while (count)//当没布置完雷之前都继续循环
{
x = rand() % row + 1; //生成数%row后范围是0~8 我们需要的是1~9
y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
注意:
C语言中提供了一个rand函数可以帮我们生成随机数,返回值为int 整型,返回的值就是一个随机数。但rand函数生成的是伪随机数,返回的随机值并不完全随机。
rand函数在生成随机数之前,要使用srand函数设置随机数的生成器。srand()括号中放置类似于生成随机数的种子,种子固定了生成的随机数也是固定的。所以我们要使括号中的值为随机变化的,才能使产生的数值为随机值。
在我们的计算机中,时间是时刻在发生变化的,如果能将时间传入srand中,那么就可以实现真正的随机。这个时候我们可以使用time函数来解决这个问题。
time函数可以返回一个时间戳,时间戳是一串数字, 是随着时间在不断变化的 。在使用时我们需要调用二者的头文件。time函数的返回类型是time_t,在srand中要使用他需要强制类型转换为(unsigned int)
所以在主函数中:
//记得引用头文件
#include
#include //srand函数的头文件
#include //time函数的头文件
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do {
menu();
printf("请输入->");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输错了,请重新输入\n");
break;
}
} while (input);
return 0;
}
这样就能实现随机布置雷:
首先玩家排查雷需要在盘面中的合法位置,如果排查位置在盘外或者排查的位置已被占用,我们需要给出相应的提示。然后玩家给出的是盘面的坐标位置,因为我们盘面坐标刚好和数组位置对应,所以可以不用再进行操作。我们封装一个函数,在game函数中调用来实现该功能。
并且在排查的过程中,可能出现以下几种情况:1、这个坐标不是雷,提示周围有几个雷
2、这个坐标是雷,游戏结束
3、所有非雷位置都找到了,游戏胜利
如果找到的坐标位置为非雷,那么我们就需要继续排查,所以我们将排查过程放到循环中进行,踩到雷或者排查结束才跳出循环。
所以我们可以通过以下代码来实现功以上功能:
//数周围有几个雷
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return (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] +
mine[x - 1][y]) - (8 * '0');
}
然后在game函数中调用,实现函数功能。
当踩到雷时,我们给出相应提示后直接跳出循环结束游戏即可。
我们可以设置一个整型变量,其大小为非雷的位置个数。如果成功排除一个雷就将其减一,将他作为循环的判断条件,当他减为0时刚好也能跳出循环,并给出相应提示表示排雷成功。
//排查雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = row * col - COUNT_EASY;
while (win )
{
printf("请输入要排查的坐标->");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("踩到雷啦!爆炸!\n");
DisplayBoard(mine, row, col);
break;
}
else if (show[x][y] != '*')
{
printf("排查过该坐标,请重新输入\n");
}
else if (mine[x][y] == '0')
{
int ret = 0;
ret = GetMineCount(mine, x, y);
show[x][y] = ret + '0';
DisplayBoard(show, ROW, COL);
win--;
}
}
else
{
printf("输入坐标非法,请重新输入\n");
}
}
//跳出循环有两种可能,一个是踩雷退出,一个是排雷完成退出
//需要判断是不是排雷成功,然后给出提示
if(win==0)
printf("恭喜你,排雷成功! \n");
}
void game()
{
//为了方便,把两个数组定义成完全一样的
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化两个数组
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
//DisplayBoard(mine, ROW, COL);
//对应雷的数组不需要给玩家看
DisplayBoard(show, ROW, COL);
//布置雷
Setmine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//排查雷
Findmine(mine, show, ROW, COL);
}
将上面的代码汇总成一个完整的扫雷游戏:
#include
#include
#include
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
#define COUNT_EASY 10
//简单版本有10个雷
void menu()
{
printf("*********************************\n");
printf("******* 扫雷小游戏 *********\n");
printf("******* 1、play *********\n");
printf("******* 0、exit *********\n");
printf("*********************************\n");
}
//初始化数组
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
int x = 0;
int y = 0;
for (x = 0; x < rows; x++)
{
for (y = 0; y < cols; y++)
{
board[x][y] = ret;
}
}
}
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
printf("--------扫雷---------\n");
for (x = 0; x <= row; x++)
{
printf(" %d", x);
}
printf("\n");
for (x = 1; x <= row; x++)
{
printf(" %d", x);
for (y = 1; y <= col; y++)
{
printf(" %c", board[x][y]);
}
printf("\n");
}
printf("---------------------\n");
}
//布置雷
void Setmine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = COUNT_EASY;
while (count)
{
x = rand() % row + 1;
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 - 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] +
mine[x - 1][y]) - (8 * '0');
}
//排查雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = row * col - COUNT_EASY;
while (win )
{
printf("请输入要排查的坐标->");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("踩到雷啦!爆炸!\n");
DisplayBoard(mine, row, col);
break;
}
else if (show[x][y] != '*')
{
printf("排查过该坐标,请重新输入\n");
}
else if (mine[x][y] == '0')
{
int ret = 0;
ret = GetMineCount(mine, x, y);
show[x][y] = ret + '0';
DisplayBoard(show, ROW, COL);
win--;
}
}
else
{
printf("输入坐标非法,请重新输入\n");
}
}
if(win==0)
printf("恭喜你,排雷成功! \n");
}
void game()
{
//为了方便,把两个数组定义成完全一样的
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化两个数组
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
//DisplayBoard(mine, ROW, COL);
//对应雷的数组不需要给玩家看
DisplayBoard(show, ROW, COL);
//布置雷
Setmine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//排查雷
Findmine(mine, show, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do {
menu();
printf("请输入->");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输错了,请重新输入\n");
break;
}
} while (input);
return 0;
}
大家也可以将其封装为多个文件看上去更简洁明了,我这里为了表达方便将其放在一个文件里。
以上就是 C语言基础:扫雷游戏的C语言实现(超详图解+源码)的全部内容啦,希望能对你有所帮助!