目录
游戏说明:
1、游戏可以通过菜单实现继续玩或者退出游戏
游戏设计:
(1)棋盘结构
首先我们先分析一下,不着急写代码。
我们想象中的扫雷的棋盘将类似上面的这种,这就是我们的棋盘结构。
我们需要建立两个棋盘,一个存放雷和空位置,一个全部存放星号或其它字符留给玩家进行游戏。(此处不用过多解释吧,玩过扫雷的都懂吧)。
(2)棋盘中放入内容
有了空棋盘后我们往棋盘里添加内容。
“0”表示空位置,此处没有雷;“1”表示雷。
(3)排雷方法
棋盘的内容算是已经完成了,非常的简单。
接下来我们要设计如何“排雷”。
看上图就是我们设计“排雷”的方法
它的原理是:排查(2,5)这个坐标时,我们访问周围的一圈8个黄色位置,统计周围雷的个数是1。
周围有几个雷中间绿色位置就显示几。
注意:
经过分析我们这样的排查方法有bug,当我们排查坐标(8,6)时会出现“越界”问题,如下:
我们再打印棋盘的时候只需要打印中间9*9的区域即可,雷也只布置在9*9的区域中。这样就完美解决了越界问题。
代码实现:
游戏设计环节我们已经结束了,接下来我们开始代码的实现。
首先我们先定义一下:
ROW表示行,COL表示列
ROWS 和COLS表示加两行两列后
#define ROW 9
#define COL 9 //9个棋盘格子
#define ROWS ROW+2
#define COLS COL+2 //加两行两列防止越界
(1)建立两个空棋盘
根据游戏的设计我们先建立两个空棋盘:
两个数组分别为mine和show
char mine[ROWS][COLS] = { 0 }; //不带星号的棋盘
char show[ROWS][COLS] = { 0 }; //带星号的棋盘
(2)棋盘赋值
有了这两个空棋盘我们要分别进行赋值:(这里用函数实现)
定义一个函数名为Initboard,对其进行传参:
Initboard(mine, ROWS, COLS, '0');//不带星号的棋盘
Initboard(show, ROWS, COLS, '*');//带星号的棋盘
Initboard函数内部实现: (此函数功能为对数组进行赋值,set 对应的是‘0’或者‘*’)
void Initboard(char arr[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
调用两次
(3)打印棋盘
赋值完毕后我们可以设计一个函数来专门进行打印棋盘名为Displayboard
代码如下:(代码中的细节就不带领读者细扣了,请读者仔细阅读一定可以看懂的,例如在棋盘周围加上坐标等)
void Displayboard(char arr[ROWS][COLS], int row, int col)
{
for (int i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
可实现如下两个棋盘:
(1)带星号的棋盘
(2)不带星号的棋盘
完成上述代码后棋盘的结构我们就已经解决了。
(4)布置雷
接下来我们需要对不带星号的棋盘进行雷的布置,我们默认随机布置10个雷。
首先定义EASY_COUNT 为10,表示雷的数量
#define EASY_COUNT 10 //雷的数量
随机布置雷需要用到函数srand()和time(),需要调用以下代码:
srand((unsigned int)time(NULL));
这两个库函数就不进行讲解了,读者可点开我的主页看我发的博客。
注意用这两个库函数需要引用相应的头文件
#include<stdlib.h>
#include<time.h>
此时我们创建一个函数用来布置雷名为Setmine
代码如下:(rand()%9的范围是0~8,再加1变为1~9)
void Setmine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = (rand() % row) + 1;
int y = (rand() % col) + 1;//随机生成x,y坐标
if (arr[x][y] == '0')//判断x,y坐标处的值,若为‘0’则可放入‘1’。
{
arr[x][y] = '1';
count--;
}
}
}
调用函数:
Setmine(mine, ROW, COL);
实现如下:
此棋盘中就有了10个‘1’,即10个雷,且每次重新生成的棋盘中雷的位置都不一样。
至此我们雷也随机布置到了不带星号的棋盘中。
(5)排查雷
现在我们要开始排雷了,用上述我们设计的排雷方法,来完成相应的代码。
首先创建一个函数名为Playboard
其代码:(此代码有点长,是此游戏的难点和核心所在,包含如果位置不是雷,就显示周围有几个雷以及如果位置是雷,就炸死游戏结束等条件。还请读者认真阅读,代码中有相应的注释,就不带读者细扣了)
void Playboard(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("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//在棋盘范围1~9内
{
if (show[x][y] == '*')//判断是否排查过
{
if (mine[x][y] == '1')
{
printf("很遗憾你被炸死了,游戏结束\n");
Displayboard(mine, ROW, COL);//打印棋盘让你明白雷在哪里
break;//跳出while循环
}
else
{
int count = Getcountboard(mine, x, y);//计算周围8个格子雷的个数
show[x][y] = count + '0';//注意此处是赋值给在x,y处的show
Displayboard(show, ROW, COL);//打印修改后的show棋盘
win++;
}
}
else
{
printf("此处已经排查过了,请重新输入\n");
}
}
else
{
printf("输入非法,请重新输入\n");
}
}
if (win == (row * col) - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
}
}
上述函数中还引用了一个名为Getcountboard的函数,此函数是用来计算的周围8个格子的雷的个数的,代码如下:
int Getcountboard(char mine[ROWS][COLS], int x, int y)
{
int count = 0;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)//周围8个格子,也包括自身x,y处。
{
count += mine[i][j] - '0';//减去0的ASII码值后再相加
}
}
return count;
}
上述所有代码就已经完成了扫雷游戏中的游戏实现过程,这个游戏过程我们给它放入一个名为game的函数中去:(把上述所有函数放入此函数中)
void game()
{
char mine[ROWS][COLS] = { 0 }; //不带星号的棋盘
char show[ROWS][COLS] = { 0 }; //带星号的棋盘
Initboard(mine, ROWS, COLS, '0');
Initboard(show, ROWS, COLS, '*');//给棋盘赋值
Setmine(mine, ROW, COL);//布置雷
//Displayboard(mine, ROW, COL);
Displayboard(show, ROW, COL); //展示棋盘
Playboard(mine, show, ROW, COL);//排雷
}
这个game函数就是扫雷游戏的实现部分
(7)游戏菜单
接下来我们给这个游戏弄一个游戏菜单,相当于游戏的初始页面
编写一个名为menu的函数:
void menu()
{
printf("*****************\n");
printf("***** 1.play ****\n");
printf("***** 0.quit ****\n");
printf("*****************\n");
}
实现如下效果:
(8)游戏流程
有了menu()和game()这两个函数此扫雷游戏已经完成90%了,剩下10%是将这两个函数在主函数中引用即可,主函数将这两个函数串在一起,用于实现游戏的流程,主函数代码如下:
int main()
{
srand((unsigned int)time(NULL));//调用srand库函数
int input = 0;
do {
menu();
printf("请输入:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("game over\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
return 0;
}
最终游戏效果演示:
代码排版:
整个游戏代码如下所示:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10 //雷的数量
void Initboard(char arr[ROWS][COLS], int rows, int cols, char set);//棋盘赋值
void Displayboard(char arr[ROWS][COLS], int row, int col);//打印棋盘
void Setmine(char arr[ROWS][COLS], int row, int col);//布置雷
void Playboard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//排雷
int Getcountboard(char mine[ROWS][COLS], int x, int y);//计算周围8个格子雷的个数
void Initboard(char arr[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
void Displayboard(char arr[ROWS][COLS], int row, int col)
{
printf("----扫雷开始----\n");
for (int i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
void Setmine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = (rand() % row) + 1;
int y = (rand() % col) + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
int Getcountboard(char mine[ROWS][COLS], int x, int y)
{
int count = 0;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)//周围8个格子,也包括自身x,y处。
{
count += mine[i][j] - '0';//减去0的ASII码值后再相加
}
}
return count;
}
void Playboard(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("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//在棋盘范围1~9内
{
if (show[x][y] == '*')//判断是否排查过
{
if (mine[x][y] == '1')
{
printf("很遗憾你被炸死了,游戏结束\n");
Displayboard(mine, ROW, COL);
break;//跳出while循环
}
else
{
int count = Getcountboard(mine, x, y);
show[x][y] = count + '0';//注意此处是赋值给在x,y处的show
Displayboard(show, ROW, COL);
win++;
}
}
else
{
printf("此处已经排查过了,请重新输入\n");
}
}
else
{
printf("输入非法,请重新输入\n");
}
}
if (win == (row * col) - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
}
}
void menu()
{
printf("*****************\n");
printf("***** 1.play ****\n");
printf("***** 0.quit ****\n");
printf("*****************\n");
}
void game()
{
char mine[ROWS][COLS] = { 0 }; //不带星号的棋盘
char show[ROWS][COLS] = { 0 }; //带星号的棋盘
Initboard(mine, ROWS, COLS, '0');
Initboard(show, ROWS, COLS, '*');//给棋盘赋值
Setmine(mine, ROW, COL);//布置雷
//Displayboard(mine, ROW, COL);
Displayboard(show, ROW, COL); //展示棋盘
Playboard(mine, show, ROW, COL);//排雷
}
int main()
{
srand((unsigned int)time(NULL));//调用srand库函数
int input = 0;
do {
menu();
printf("请输入:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("game over\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
return 0;
}
建议读者做此类型的需要较长代码的题目尽量分开文件夹去做,不要都放一个文件夹中
我是用vs2022做的
我用了三个文件夹,头文件是game.h,源文件是game.c和text.c
头文件用来放引用库函数和函数声明;
源文件中game.c专门来写函数的实现;
text.c用来写主函数;
结束语:
感谢看此文章的大佬们,若此文章哪有不好的地方,还请大佬们评论区留言,感谢。
互关~~
帮忙点个赞~~