目录
一,游戏原理
看到这幅图,相必大家都不会陌生,这正是陪伴我们整个童年的游戏--扫雷,那既然提到扫雷,我们都知道它的运作原理,就是简单的点一下图上的白方块,然后就会炸开,遇到雷时,就会停止炸裂,然后显示周围有几颗雷的数字(数字代表自己周围一圈雷的数量),让你猜雷的位置在哪 ,然后对有雷的位置插上小红旗,排除所有的雷就可以通关了。但是,一旦点到雷了,就会导致游戏结束。
二,扫雷游戏背后代码的创作与讲解
1、打印游戏目录
那既然我们已经知道了扫雷游戏的运行原理,那我们便可以通过c语言来将这款游戏进行还原。
首先,我们先创建1个项目,并再其添加2个源文件和1个头文件,就像这样:
首先test.c(源文件)是整个游戏的逻辑运行,game.h(头文件)是游戏相关的函数声明,game.c(源文件)是游戏相关的函数的实现。
那创作好我们的文件之后,我们就可以开始创建目录,这是每个游戏都必不可少的一个环节,图:
图中的#include "game.h",是我们待会要用到的头文件,所以在此引用,图中的game()函数的主体,我放入game.c中,待会就可以看见。好的,我们以这样的形式搭建好我们的游戏目录,其中do-while循环是至关重要的,它可是整个代码逻辑的主体,务必请大家熟练掌握。
2、定义game函数
在搭建好游戏目录之后,我们就开始思考下一个步骤,通过观察,我们不难发现,扫雷这款游戏跟我们所学的二维数组非常相似,可以说是一模一样,都是由行和列所组成,那既然这样,那我们便可以创造一个二维数组,但我们首先要想一个真的够吗?当我们用'0'和'1'来分别表示”没雷“和”有雷“,那我们有没有想过,当我们所猜的地方正好周围有一颗雷时,那这个数字“1”到底表示的是“有雷”还是“周围雷的数量了”。所以为了方便使用,我们可以创造两个二维数组,一个用于“专门存放布置好雷的信息”(这里我们就用数组mine代替),另一个“专门存放排查雷的信息”(这里我们就用数组show来表示),我们就可以把雷布置到mine数组,在数组mine中排查雷,将排查出的数据存放于show数组中,并打印show数组的信息给后期排查参考。
mine数组
show数组
这两张图只是个例子,仅供参考,不必研究!!!
3、创建棋盘
通过对扫雷页面的观察,我们可知,在不同的的模式下,扫雷游戏的棋盘大小会发生变化,但其中最为基础的还是9*9的棋盘,于是我们便可以在game.h(头文件)中定义"row"和"cow",如图:
那就会有人问了,那个rows为啥后面跟着row+2(cols也是同理)了?这是因为当我们扫雷时,我们有时候点的位置可能会在边边角角的位置,但我们有没有想过?我们明明设置的是9*9的棋盘,但当我们统计所点地方周围雷的数量时,在9*9的范围内的好统计,但一旦超出这个范围,不就形成了越界访问这种现象嘛!所以为了防止这种现象,我们就在其周围扩大1圈(让纵行和横行各加一个2),所扩大的范围什么的不用加,就是为了防止越界访问这种现象出现,还有以后为了方便改变棋盘的大小,我们可以随时将row后面跟的9改成任意数字,但我们这里还是以最基本的棋盘来讲解。
搞清楚我们要创建的棋盘之后,我们就可以开始创建一个关于棋盘的函数“Initborad”,这里我们将show数组开始初始化为字符'*',为了保持两个数组的类型一致,可以使用同一套函数处理时,mine数组最开始也初始化为字符'0',布置雷改成'1'。
注意:这里需使用包含game.h的头文件,才能实现棋盘的初始化,这里用Rows和Cols是为了区分实参和形参,便于理解。
4、打印棋盘
初始化棋盘之后就需打印出来,我们便可以创建DisplayBoard 函数实现,如图
这里打印行号和列号,是为了方便观察,填写相对应的坐标,就像这样:
5、布置雷
我们棋盘创建好之后,我们便可以开始放置雷了,既然要放置雷,我们肯定希望雷的位置是完全随机的,所以我们可以创建一个SetMine函数来实现这一原理
注意: 在用rand函数时,需要用到srand函数、time.h和stdlib.h这两个头文件!!!
6、排查雷
布置完雷之后,我们就要开始排雷了,那该怎么排雷了?
首先,我们讲过在排雷的时候,我们所点的位置会显示周围有几颗雷,那根据这个原理,我们就可以统计它周围有多少个以'1'这样字符的雷,因为我们前面用这个'1'来表雷,用'0'表示“没有雷”,而且'1'的ASCLL对应的值为“49”,'0'对应的ASCLL对应的值为“48”,所以我们就可以得到用'1'-'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';
}
这样我们的扫雷程序就基本完成了,以下便是完整代码:
test.c
#include<stdio.h>
#include "game.h"
void menu()
{
printf("****************\n");
printf("*** 1.play ***\n");
printf("*** 2.exit ***\n");
printf("****************\n");
}
//完成扫雷游戏的整个过程
void game()
{
char mine[rows][cols] = { 0 };//存放布置好雷的信息
char show[rows][cols] = { 0 };//存放排查出的雷的信息用于显示
//初始化棋盘
Initborad(mine, rows, cols,'0');//初始化"0"
Initborad(show, rows, cols,'*');//初始化"*"
DisplayBoard(show, row, col);
/*DisplayBoard(mine, row, col);*/
//布置雷
SetMine(mine, row, col);
/*DisplayBoard(mine, row, col);*/
//排查雷
FindMine(mine,show,row,col);
}
int main()
{
int a = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入数字:");
scanf_s("%d", &a);
switch (a)
{
case 1:
game();
break;
case 2:
printf("已退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (a);
return 0;
}
game.c
#include "game.h"
void Initborad(char board[rows][cols], int Rows, int Cols,char set)
{
int i = 0;
for (i = 0; i < Rows; i++)
{
int j = 0;
for (j = 0; j < Cols; j++)
{
board[i][j] = set;
}
}
}
void DisplayBoard(char board[rows][cols], int Row, int Col)
{
int i = 0;
printf("----- 扫雷 -----\n");
for (i = 0; i <= Row; 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;//用EASY_COUNT代表几个雷,方便以后随时更改雷的数量
while (count)
{
int x = rand()%Row + 1;//生成的随机数范围为1~Row
int y = rand()%Col + 1;//生成的随机数范围为1~Col
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] +
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)
{
int x = 0;
int y = 0;
int win = 0;
while (win<row*col-EASY_COUNT)
{
printf("请输入要排查的坐标:");
scanf_s("%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
{
//统计mine数组的x,y坐标周围8个坐标中有几个雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, row, col);
}
}
}
else
{
printf("输入的坐标非法,请重新输入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, row, col);
}
}
game.h
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define EASY_COUNT 10
#define row 9
#define col 9
#define rows row+2
#define cols col+2
//棋盘的初始化
void Initborad(char board[rows][cols], int Rows, int Cols, char set);
//打印棋盘
void DisplayBoard(char board[rows][cols], int Rows, int Cols);
//布置雷
void SetMine(char board[rows][cols], int Row, int Col);
//排查雷
void FindMine(char mine[rows][cols], char show[rows][cols], int Row, int Col);
三,总结
以上就是扫雷的全部过程了,小编我也是第一次编写这么多的程序,虽然可能在某些地方讲的不太好,但希望大家多多包容,有错误的地方,希望大家可以指出来,我们可以一起研究学习。