C | 简易版扫雷的实现
Posted Ersansui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C | 简易版扫雷的实现相关的知识,希望对你有一定的参考价值。
目录
前言
相信大家小时候都玩过扫雷小游戏吧?
在网络并不发达的时代,windows系统自动的扫雷小游戏便成为了不少人童年的回忆。
今天就让我们就用C语言来实现简易版的扫雷小游戏吧!
游戏实现
我们实现的思路如下:
1.程序开始时打印菜单,让玩家选择开始游戏还是退出游戏
2.玩家选择游戏后进入游戏
3.判断输赢后,重新回到菜单
同上一次三子棋小游戏的实现一样,我们先创建三个不同的文件,以便于代码的管理和维护。
test.c 用于游戏整体框架的实现
game.c 用于游戏相关函数的实现
game.h 用于游戏相关函数的声明
如果没有看过三子棋小游戏的同学们,可以点击下方链接跳转哦~
test.c
该文件为为main函数的实现,是程序的入口
我们通过菜单选项,可以选择开始游戏还是退出游戏
为了能够在switch语句的case中能够直观的看到不同的选项应该对应哪些函数,我们定义了一个枚举变量来一一对应选项
do-while语句,可以实现程序开始执行就打印一次菜单,让玩家可以选择
while中的条件判断,我们可以放入玩家选择的结果,如果为0就退出循环了,如果为非0就再打印一次菜单
srand函数的调用是用来设置随机数生成的起点,以便于后续调用rand函数来随机设置雷的位置
//test.c
//包含头文件,实现game.c中函数的调用
#include"game.h"
//定义枚举变量,对应菜单的选项
enum Choose
{
EXIT,
PLAY
};
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//利用时间戳,设置随机数生成起点
//游戏相关规则的说明
howtoplay();
//程序开始就执行一次,让玩家可以进行选择
do
{
menu();//调用菜单函数
scanf("%d", &input);
switch (input)//对应玩家的选择,并做出判断
{
case PLAY:
game();//选择了玩游戏后,调用game函数来进行游戏
break;
case EXIT:
printf("退出游戏\\n");
break;
default:
printf("选择有误,请重新选择\\n");
break;
}
} while (input);//当input为0时,退出循坏,结束程序;当input为非0时,可以重新让玩家选择
return 0;
}
game.c
该文件用来实现game函数中所调用的所有与游戏有关的函数
大致思路如下:
1.创建两个二维数组,一个(mine)用来记录雷的位置,一个(show)用于打印给玩家看
2.初始化两个二维数组
3.在mine数组中根据事先确定好的难度来设置雷
4.打印show数组与方便玩家看对应着看的坐标轴
5.玩家输入坐标来进行扫雷
6.判断玩家的选择,如果选中了雷就提示玩家:被炸死了;否则,在玩家所选的那一个位置中打印以那一个位置为中心的九宫格的雷的个数
game函数的实现
创建数组选择大小时,我们不要直接写大小,免得写死了,后续修改二维数组大小的时候不方便
我们可以在后面的game.h中通过define来定义二维数组行与列的大小
注意!!
这里我们创建的数组大小时11×11,而不是9×9的
这是因为,如果我们选择的是边上的位置,我们在遍历以该位置为中心的九宫格时,会因为数组越界而程序报错
所以我们在二维数组中在扩大一圈,并且全部初始化,避免后续遍历九宫格时候会造成越界
但是我们在打印数组时候,是不会打印外圈的
game函数主要是按照一定的顺序调用各个相关的函数来实现整个游戏过程
void game()
{
//创建两个二维数组
//mine数组用于记录雷的位置
//show数组用于打印显示
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化二维数组函数
//mine数组传参为‘0’
//show数组传参为‘*’
Initboard(mine, ROWS, COLS,'0');
Initboard(show, ROWS, COLS,'*');
//根据难度,在mine数组中随机设置雷的位置
Setmine1(mine,show,ROWS,COLS);
//Setmine(show, ROW, COL);
//打印show数组
//Printmine(mine, ROW, COL);
Printmine(show, ROW, COL);
//扫雷函数
Findmine(mine,show, ROW, COL);
}
游戏相关规则说明的函数
该函数用于在程序的最开始打印游戏相关规则
//游戏说明
void howtoplay()
{
printf("-------------------------------------------------------------------------\\n");
printf("1.玩家需用键盘输入进行选择 \\n");
printf("2.输入坐标时需要输入数字并按回车\\n");
printf("3.第一次选择行,第二次选择列\\n");
printf("4.左侧和上方的顺序数字是让玩家知道是哪一行那一列的\\n");
printf("5.如果选择的位置安全,则会在该位置打印出其周围八个格雷的数目\\n");
printf("6.当前版本并不能选择一次就展开一片,只能一个一个选择没有雷的位置\\n");
printf("7.当所有安全的位置被玩家找出,就赢得游戏\\n");
printf("8.当前难度为简单,一共有9个雷\\n");
printf("--------------------------------------------------------------------------\\n");
printf("\\n");
}
棋盘初始化函数的实现
为了能够初始化两个数组,我们就在函数内规定初始化的元素了,想要初始化成什么元素就直接传参给该函数即可
//初始化函数
//根据传参来初始化二位数组
void Initboard(char mine[ROWS][COLS], int rows ,int cols,char ch)
{
int i = 0;
for (i = 0;i < rows;i++)
{
int j = 0;
for (j = 0; j <cols; j++)
{
mine[i][j] = ch;
}
}
}
随机生成雷的函数的实现
我们把mine数组传给该函数,通过随机生成坐标的方式来实现雷的放置
注意!!
这里形参row和col是按照游戏中二维数组的大小来传参的
并不是按照大了一圈的大小来传参
因为我们在放置雷的时候,只需要把雷放在实际大小(该版本为9×9)的二维数组中即可
外围那一圈是不需要放置的
否则在后续遍历九宫格的时候就会出错
这里我设置字符1为雷,原来的字符0为安全
void Setmine1(char mine[ROWS][COLS],int row, int col)
{
int count = SIMPLE_MODE;
while (count)
{
int i = rand()%9 + 1;
int j = rand()%9 + 1;
if (mine[i][j] == '0')
{
mine[i][j] = '1';
count--;
}
}
}
打印数组函数的实现
//打印函数
//用于打印show数组,并打印行与列的坐标,方便玩家选择
void Printmine(char board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("\\n");
printf(" ");//让列的坐标数字能够与下面的*对齐
for (i = 1; i <= col; i++)
{
if (i <= 9)
printf("%d ", i);//当坐标数为个位数的时候,多一个空格占位置
else
printf("%d ", i);//当坐标数为两位数的时候,少一个空格占位置
}
printf("\\n");
printf(" ");//让列的坐标数下面的分割线与下面的*对齐
for (i = 1; i <= col; i++)
{
printf("---");//个位数+两个空格或者两位数+一个空格,所以这里用三个短横线来对齐
}
printf("\\n");
for (i = 1; i <= row; i++)
{
int j = 0;
if (i <= 9)
printf("%d |", i);//个位数的行坐标数用两个空格对齐
else
printf("%d |", i);//两位数的行坐标数用一个空格对齐
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);//用一个字符+两个短横线来对齐上面的三短横线
}
printf("\\n");
}
printf("\\n");
printf("\\n");
}
修改mine数组的函数的实现
void Setmine2(char show[ROWS][COLS], int x, int y, int ret)
{
show[x][y] = ret + '0';
}
扫雷过程函数的实现
//扫雷函数
void Findmine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;//用来记录九宫格雷的个数
int amount = row * col - SIMPLE_MODE;//用来记录没有放雷的安全位置的个数
while (1)
{
printf("请输入坐标:>\\n");
scanf("%d %d", &x, &y);
//if语句用于判断玩家输入的坐标是否正确
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("\\n");
printf("很遗憾,你被炸死了\\n");
printf("\\n");
return;//被炸死了就直接返回,退出该函数了
}
else
{
//else也要判断该位置是没有选过的‘0’的位置
//还是已经选过的并改为‘#’的位置
if (mine[x][y] == '0')
{
mine[x][y] = '#';//把字符0改为‘#’,方便后续判断该位置是否重复选择
amount--;//安全位置的个数减一,当减到零的时候,玩家还没有因为被炸死而退出
//则说明玩家已经排雷完成
//定义新坐标,为以玩家选择的坐标为中心的九宫格的左上角,
//用于遍历数组来统计九宫格雷的数量
int i = x - 1;
int j = y - 1;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (mine[i][j] == '1')
{
count++;//用来记录九宫格雷的个数
}
}
}
Setmine2(show, x, y, count);//将返回的九宫格的雷的个数来修改show数组
//让玩家选择的位置可以显示出周围有多少雷
count = 0;//每次修改成功后都要重置为0,否则数量会累加
Printmine(show, ROW, COL);//把修改过的show数组打印出来
if (!amount)//当amount为0时,说明玩家扫雷成功,返回退出函数
{
printf("恭喜你扫雷成功!\\n");
printf("\\n");
return;
}
}
else if (mine[x][y] == '#')
{
printf("该位置已排查过,请重新选择\\n");
}
}
}
else
{
printf("\\n");
printf("输入有误,请重新输入:>\\n");//如果玩家输入坐标有误,会让玩家重新选择
printf("\\n");
}
}
}
修改show数组的函数的实现
通过遍历九宫格后返回的数字,来把show函数中对应位置的字符0修改为对应数字的字符形式,以便玩家知道周围的雷的个数,因为打印函数里面用的是%c的字符形式,所以要把数字转变为字符的格式
void Setmine2(char show[ROWS][COLS], int x, int y, int ret)
{
show[x][y] = ret + '0';
}
game.c汇总
让我们对上述代码进行汇总吧,想要体验一下的小伙伴们可以直接拷贝下面的代码即可
#include"game.h"
//游戏说明
void howtoplay()
{
printf("-------------------------------------------------------------------------\\n");
printf("1.玩家需用键盘输入进行选择 \\n");
printf("2.输入坐标时需要输入数字并按回车\\n");
printf("3.第一次选择行,第二次选择列\\n");
printf("4.左侧和上方的顺序数字是让玩家知道是哪一行那一列的\\n");
printf("5.如果选择的位置安全,则会在该位置打印出其周围八个格雷的数目\\n");
printf("6.当前版本并不能选择一次就展开一片,只能一个一个选择没有雷的位置\\n");
printf("7.当所有安全的位置被玩家找出,就赢得游戏\\n");
printf("8.当前难度为简单,一共有9个雷\\n");
printf("--------------------------------------------------------------------------\\n");
printf("\\n");
}
//菜单函数
void menu()
{
printf("***************************\\n");
printf("******* 1. play *******\\n");
printf("******* 0. exit *******\\n");
printf("***************************\\n");
printf("\\n");
}
//初始化函数
//根据传参来初始化二位数组
void Initboard(char mine[ROWS][COLS], int rows ,int cols,char ch)
{
int i = 0;
for (i = 0;i < rows;i++)
{
int j = 0;
for (j = 0; j <cols; j++)
{
mine[i][j] = ch;
}
}
}
//设置雷的函数
//随机生成雷的坐标,并放置在mine数组中
void Setmine1(char mine[ROWS][COLS],int row, int col)
{
int count = SIMPLE_MODE;
while (count)
{
int i = rand()%9 + 1;
int j = rand()%9 + 1;
if (mine[i][j] == '0')
{
mine[i][j] = '1';
count--;
}
}
}
void Setmine2(char show[ROWS][COLS], int x, int y, int ret)
{
show[x][y] = ret + '0';
}
//打印函数
//用于打印show数组,并打印行与列的坐标,方便玩家选择
void Printmine(char board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("\\n");
printf(" ");//让列的坐标数字能够与下面的*对齐
for (i = 1; i <= col; i++)
{
if (i <= 9)
printf("%d ", i);//当坐标数为个位数的时候,多一个空格占位置
else
printf("%d ", i);//当坐标数为两位数的时候,少一个空格占位置
}
printf("\\n");
printf(" ");//让列的坐标数下面的分割线与下面的*对齐
for (i = 1; i <= col; i++)
{
printf("---");//个位数+两个空格或者两位数+一个空格,所以这里用三个短横线来对齐
}
printf("\\n");
for (i = 1; i <= row; i++)
{
int j = 0;
if (i <= 9)
printf("%d |", i);//个位数的行坐标数用两个空格对齐
else
printf("%d |", i);//两位数的行坐标数用一个空格对齐
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);//用一个字符+两个短横线来对齐上面的三短横线
}
printf("\\n");
}
printf("\\n");
printf("\\n");
}
//扫雷函数
void Findmine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0以上是关于C | 简易版扫雷的实现的主要内容,如果未能解决你的问题,请参考以下文章