前言:经过了对数组、函数的认真学习以后学习以后,我们深刻的了解了数组和函数的底层逻辑,那么我们就开始一个新项目来巩固一下数组、函数内容。
使用工具:vs2019
首先:
带大家了解一些基本知识,在大型公司中,由于一个项目需要大量代码,所以一个项目不能由一个人单独完成,需要多人配合完成项目,为了更好的配合,不可能一群人在一个源文件(后缀.c的文件)里面完成一整个项目,大多都是分模块,每个人完成自己的目标模块,在自己创建的源文件中,最后汇总后进行执行。
一、 铺垫阶段:
铺垫 : 想必大家都玩过扫雷游戏,具体是有一个棋盘,这个棋盘也因人们选择的难度不同有不同的大小,今天我们来实现的也是相对来说比较容易的 9×9的棋盘。
第一步构想如何实现扫雷的棋盘。
如果我们要实现一个9 × 9 的棋盘最起码我们要定义一个 行为:9,列为:9 的二维数组。用来记录雷的信息。这里我们可以用0或者1,或者任意一个符号代表雷。
第二步构想如何表达雷并且记录对应九宫格内部有几个雷
如果用1代表雷,并且九宫格内部如果雷数为1,那么就会产生奇异,让人们误解到底是雷还是所对应的雷的信息。所以到目前为止我们应该创建两个二维数组,其中一个命名为mine ,用来存储雷的信息,另外一个命名为show,用来展示棋盘的信息。这样就不容易让人产生歧义。以上是用来表达雷的信息。那么我们怎么记录九宫格内有几个雷呢
对应来看其中内部的元素的好找,但当涉及到边角,在查找的时候就容易出现,下标访问越界的现象。为了避免这个现象,我们开辟的二维数组,不是9×9的,而是11×11。这样能防止边角元素在进行下标访问时越界。
第三步实现代码
二、具体实现:
第一步:打印一个菜单,让玩家自行选择游玩游戏。
知识点: do....while switch case语句 函数的调用
根据第一步我们可以使用一个do while循环让玩家在游玩游戏后不过瘾再玩一局,或者在选择错误的时候从新选择。具体代码块:
void menu()
{
printf("*******************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("*******************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请输入一个数字>:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
以上代码就可以实现打印菜单,并且让玩家自己选择。
第二步:创建两个二维数组分别记录雷的信息和展示为玩家的信息并且完成初始化
知识点:函数的设计
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
void InitBoard(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;
}
}
}
这里我们把布置雷的棋盘,初始化为字符0。把展示给玩家的棋盘初始化为*。
这里把布置雷的棋盘初始化为字符0的好处后面我们会提到。
第三步打印棋盘
知识点:自定义函数,循环打印
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= row; i++)
{
printf("%d", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d", i);
int j = 0;
for (j = 1; j <= col; j++)
{
printf("%c", board[i][j]);
}
printf("\n");
}
}
用这种方式打印可以打印出行数和列数,方便我们去找到对应的位置。
第四步:布置雷
在布置雷的阶段,我们把布置的雷放在mine函数中,把雷的位置改成字符1,这样方便找到雷。
在布置雷的时候我们先生成一个随机坐标,生成随机坐标这里我们使用的rand函数。
下面我详细的讲解一下rand函数:
rand函数可以生成随机数,但是在使用rand函数之前必须使用srand函数,srand函数的参数是一个随机值(变化的值),这里面变化的值可以为时间戳,time()函数。
在生成了随机值后,对坐标进行判断,合法后将字符0,变为字符1。
void setMine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int num = 10;
while (num)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
num--;
}
}
}
第五步:排查雷
在这一步中我们先让玩家输入一个坐标,我们先判断坐标的合法性,然后对坐标进行定位,如果坐标位置为字符1,那么这个位置对应的就是雷,玩家死亡。 如果玩家输入的坐标是字符0,那么我们会返回其对应的九宫格内雷的个数。
下面为具体代码:
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 rows, int cols)
{
int x = 0;
int y = 0;
int win = 0;
while (win< ROW * COL - EasyPlay)
{
printf("请输入坐标>:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= rows && y >= 1 && y <= cols)
{
if (mine[x][y] == '1')
{
printf("恭喜你被炸死了\n");
DisplayBoard(mine, ROW, COL);
}
else
{
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标不合法,请重新输入\n");
}
}
if (win == ROW * COL - EasyPlay)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
这里我们不得不挖出我们在之前埋下的伏笔,为什么用字符1代表雷,如果用其他的字符,我们在判断坐标位置是否为雷时,将特别的困难,如果我们用字符1,我们只需要将一圈的字符加到一起然后减去8个字符0,就是对应的雷的数字。
总结: 这个文章我们学习了如何实现扫雷游戏,其中对于11×11的棋盘的设定,以及为什么样设置2个二维数组,值得大家去思考,以及为什么雷要用字符1来表示都是好问题。