也许屏幕前面的你玩过windows系统附带的那个游戏。清除地雷。
回想当时,我完全不明白这个游戏是怎么玩的
相比扫雷,三维弹球对我更有吸引力
跑题了
这个博客让我们一起通过C语言代码制作“扫雷游戏se”的方法吧。
1.游戏程序主要功能
在编写这种游戏代码时,我们要使用的主要函数基本一致
扫雷游戏的主要函数和数字猜测游戏的主要函数差别很小
Void menu()//简单目录
{
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * n '
printf(' * * * * 1 . play 0 . exit * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * n '
}
Int main()
{
int input=0;
道
{
菜单();
Printf(选择“:”);
扫描(“%d”,输入);
开关(input)
{
Case 1:
game();//实现游戏功能
布雷克;
Case 0:
Printf('游戏结束\ n ');
布雷克;
Default:
Printf('输入错误\ n ');
布雷克;
}
} while(input);
return 0;
} 2 .游戏实现原理
要想写好代码,首先要知道如何玩扫雷游戏
我们需要9x9棋盘来生成我们的雷霆和玩家的游戏
当然,在C语言中,不能自己制作这样的画。
但是,可以使用*或#符号代替栅格,1和0表示是否有雷声。
只要制作一个棋盘,1和0就会直接出现,无法达到隐藏的效果
所以我们要用二维排列制作两个棋盘。一个是存放雷声,一个是玩玩家的游戏。
char mine[ROWS][COLS];//雷区布局
char show[ROWS][COLS];//使用玩家看到的界面扫雷游戏头文件源文件编写代码
这样写代码的话,以后。优点是可以通过直接更改h文件的数组来更改晶格大小。
例如,将:更改为12x12游戏界面,更改雷区雷场的数量等。
所以我们必须在game.h中定义这些符号
# include
# include
# include
#define ROW 9
#define COL 9
#define ROWS ROW 2
#define COLS COL 2同时,必须在主函数的顶部引用自己创建的头文件
如果将库函数头文件放在game.h文件中,则只需在其他源文件中引用game.h即可。
不用再引用了。像这样的
# include“game . h”主板大小为什么需要11x11?
如你所见,在创建数组的时候,我用了ROWS,它的值是ROW 2。
最终只显示9x9游戏界面,但生成的棋盘实际上是11x11
这是因为需要在mine阵列中扫描雷区
玩过扫雷游戏的人肯定知道:当你点击格子的时候,如果这个格子不是雷的话。
显示周围8个格子中有几个打雷的数字
如图所示:
gnature=70ODEXtflyiMtDObt89095Kej8Y%3D&index=2" width="498" height="620"/>在C语言中,我们可以用函数统计周围8个格子中雷’1’的个数
但是如果你来到边缘,那就出现问题了
如果我们想统计边缘的格子周边有几颗雷,就会遇到这种溢出数组的情况
此时代码会报错
为了避免这个问题,我们可以在原来9x9的基础上在周围加一圈空白的格子
也就是代码所示的ROW(行)COL(列)都要+2的情况
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
游戏过程
这里简单梳理一下我们的游戏过程
(1)玩家选择开始游戏
(2)生成两个棋盘,一个放置雷\扫描雷,一个向玩家展示游戏界面
(3)玩家输入坐标,选择排雷位置
(4)有雷–>玩家被炸死,游戏结束;无雷–>显示周边有几颗雷,游戏继续
(5)所有雷被排出,游戏胜利
3.游戏代码实现
接下来就进入我们的游戏代码部分
3-1.初始化和打印
//初始化扫雷
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印扫雷
DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
我们需要初始化两个棋盘,其中雷区初始化为0(0代表无雷),展示区初始化为’*’,用✳代替界面
同时我们打印这两个棋盘,查看初始化效果
因为这是我们的自定义函数,所以需要在.h文件中定义函数,在另外一个.c文件中包含函数的实现
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//打印
void DisplayBoard(char board[ROWS][COLS], int row, int col);
初始化函数和打印函数比较简单,使用for语句达成我们的需求
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("------扫雷游戏------\n");
//打印列号
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)//只打印中心的99方格
{
printf("%d ", i);//打印行号
for (j = 1; j <= col; j++)//只打印中心的99方格
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("--------------------\n");
}
需要注意的是我们的最后打印棋盘的时候是从i=1开始的,这样就能避开添加的空白边缘区域,只打印中心的99方格
同时我们添加了列号和行号,这样能让玩家清除的知道自己应该输入什么坐标
3-2.布置雷区
//布置雷
SetMine(mine, ROW, COL);
同样的,我们需要在game.h中定义这个函数
//布置地雷
void SetMine(char mine[ROWS][COLS], int row, int col);
在game.c中写入自定义函数的实现
//放置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] =='0')
{
mine[x][y] = '1';
count--;
}
}
}
这里面出现了一个前面没有提到的变量,EASY_COUNT
本来这个位置只是个10
但如果我们想更改布雷个数,那每次都需要更改这里的10,后面的代码中也需要更改,非常麻烦
所以我们改为使用一个自定义变量,在game.h中定义这个变量的值
#define EASY_COUNT 10
这个值就代表我们布置雷的个数了
3-3.玩家排查雷
//在主函数中引用这个函数
FindMine(mine,show, ROW, COL);//需要把mine数组中排查的雷放入show
//在game.h中定义这个函数
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);
因为我们需要把mine数组中排查出的雷的个数放入show数组中打印出来
所以这里我们需要把两个数组都传送过去
1.输入排查的坐标
2.检查坐标处是不是雷
·是雷 -boom!炸死 -游戏结束
·不是雷 -统计坐标周围有几个雷-存储排雷的信息到show数组,游戏继续
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
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
{
//不是雷的情况下,统计坐标周围有几个雷
int count = get_mine_count(mine, x, y);
show[x][y] = count + '0';
}
}
else
{
printf("坐标错误,请重新输入 \n");
}
}
}
注意,这里面我们需要添加一个代码来判断坐标合法性
我们的棋盘是9x9,玩家要是输入一个(99,99)的坐标,那肯定不在数组中的,是无效的
我们需要提醒玩家他输错了
‘0’的作用
show[x][y] = count + '0';
你可能会对这行代码感到疑惑
为什么要在count后面+上一个‘0’?
这里就和我们ascii码表有关了
因为我们初始化数组和布置雷的时候,我们给数组传入的都是1和0这两个符号,并不是数字!
但是在show数组中我们需要给玩家显示一个数字的字符
这里面我们提供的是1的字符,并不是1它本身
而我们在计算周边雷的个数的时候,传回来的是一个具体的数字
观察表格,你会发现数字和对应的字符中间,都差了48
而48恰好是字符’0’对应的ASCII码值
所以我们需要用count加上字符’0’,以此在界面中向玩家展示周边8格有几颗雷
3-4. 系统扫描雷
如何把玩家选择的格子周边的雷扫描出来呢?
设玩家的选择的坐标为x和y
我们只需要把这些坐标全部在二维数组中键入,就能逐个扫描出雷的个数
//统计雷的个数
static int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x][y - 1] +
mine[x][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] - 8 * '0';
}
这里因为我们扫描出来的也是‘1’的字符,系统中是字符1的ascii码值49
所以我们需要减去8个字符‘0’,这样就能得到雷的个数的数字
(然后在之前的那个函数中接受,count+‘0’,在show数组中显示)
这个函数是在玩家排查雷的函数之前的
因为在主函数中我们不需要使用这个自定义函数,所以不需要在game.h中定义
我们想让它只在game.c中生效,所以用static修饰它
static的作用
1.修饰局部变量
2.修饰全局变量
3.修饰函数
上面的代码其实还少了一个东西
我们需要判断玩家什么时候胜利——雷区的0(无雷方块)全部被玩家找出,玩家就胜利了
int win = 0;
while (win< row * col - EASY_COUNT)
这里我们需要更改的是whlie函数
其中 row * col - EASY_COUNT 指方格总数减去雷的个数,得到的是无雷方块的个数
玩家每成功排除一个无雷方块,win就会加一个数字
else
{
//不是雷的情况下,统计坐标周围有几个雷
int count = get_mine_count(mine, x, y);
show[x][y] = count + '0';
//显示排查出来的信息
DisplayBoard(show, ROW, COL);
win++;
}
当win达到无雷方块个数的时候,whlie循环就会停止
随后我们判断玩家是否胜利,如果胜利,就打印棋盘,让玩家知道雷的位置
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,游戏胜利!\n");
DisplayBoard(mine, ROW, COL);
}
这里必须要判断,因为你失败了也是会跳出循环的!
到此,我们的扫雷代码就是完成了
4.查看结果
这里我作弊,将雷的个数设置为80并打印出布置雷之后的棋盘
输入最后一个雷的位置,系统提示我们游戏胜利
输入雷的坐标后,也会提示你被炸死了
到这里我们可以确认代码是编写成功了!
对啦对啦!另外的话为了帮助大家,轻松,高效学习C语言/C++,我给大家分享我收集的资源,从最零基础开始的教程到C语言项目案例,帮助大家在学习C语言的道路上披荆斩棘!可以来我粉丝群领取哦~
编程学习书籍分享:
编程学习视频分享:
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在群里面交流提问编程问题哦!
对于C/C++感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C++的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!