大家好呀!👋这个是付青云同学的博客,是一名大一在校生哦!😁😁
目前一直在学习C语言。🐸
写博客是为了来记录我的学习过程,同时也希望通过博客能够帮助到需要帮助的人。
如果我的博客可以帮助到你,不妨给我一个关注哦😁
首先看动图演示
文章目录
扫雷
这里使用的编译环境是VS2022
写在前面
相信大家都对扫雷这个游戏不陌生吧?
记得在我很小的时候我家就有电脑了,小孩子嘛,对这些新事物总是好奇的🤓,就天天左点点右看看,在鼓捣的时候就发现了扫雷这个游戏。
说实话,对于那时候的我来说,况且还不知道规则,这个游戏的初级我都没通关过几次😂,所以每次都把棋盘设置到最大,把雷设置到最少,靠找规律才勉勉强强通关(我是真的菜)。即使这样,我还是天天偷偷躲着我老爸玩这个游戏(这也是我童年为数不多的乐趣之一了),所以这个游戏也算是我的启蒙游戏了吧。(真怀念童年那无忧无虑的年纪呀🥲~~)
现在,我来说一下扫雷的游戏规则😎:
在一个
9
∗
9
9*9
9∗9的棋盘中,随机分布着10个雷💣,当我们输入坐标时,如果那个坐标下没有雷,那么就检查八方雷的数量并显示出来,当所有的空都被扫描出来,意味着扫雷成功,游戏胜利;反之,当输入的坐标下有雷的话,游戏失败*_*。
那么现在,我们就使用C语言,来重温一下当年那个游戏吧!😁
思路
想要编写一个程序,思路肯定是少不了的,更何况还是一个小游戏。
这个游戏的思路并不复杂:
首先,老规矩,我们先要初始化棋盘,但这个棋盘要怎么初始化呢?
- 仔细想想,我们可以这样:定义两个数组,一个是面向玩家的,当玩家输入坐标时,给出八方的雷的数量;另一个就是隐藏的,用来设置雷。
然后,我们就要打印面向玩家的棋盘,这个并不难解决;
再然后,我们就要开始设置雷了,关于设置雷,我们可以依旧可以使用rand函数和srand函数来随机摆放雷;
最后,我们就要开始排查雷,关于排查雷,我前面也提到了,可以自定义一个函数,将我们输入坐标的八方检查一遍,来计算这八方的雷的数量并显示出来。
基本思路出来了,更多的细节,我们在遇到困难的时候再解决。那,我们就开整吧🥳🥳🥳!
代码实现
制作一个菜单
这次的菜单,我们依旧自定义一个菜单函数,利用switch来选择游戏状态。
game()函数用来实现游戏逻辑
如下:
void menu()//菜单
{
printf("扫雷游戏\n");
printf("****************************\n");
printf("******** 1、开始 *********\n");
printf("******** 0、结束 *********\n");
printf("****************************\n");
}
void game()
{
;
}
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;
}
设置棋盘大小
这里设置两种大小,设置(ROWS/COLS)的目的是,便于后面自定义排查雷的函数:
因为在排查雷的时候,我们排查的是输入坐标的八方’1’的个数,而当我们输入最外围的坐标时,就会越界访问内存,因为它们在我们设置的数组之外,所以,我们就需要在上、下、左、右的边界各加一行,因此我们就各位多定义两行两列,防止越界。
如下:
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
初始化棋盘
我们可以用一个函数来初始化两个数组:
将面向玩家的棋盘全部赋为’*‘,将隐藏的棋盘全部赋为’0’
到时候我们可以将雷赋为’1’,便于计算。
如下:
void IntBoard(char board[ROWS][COLS], int rows, int cols, char sat)//初始化棋盘
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = sat;
}
}
}
int main()
{
char my_board[ROWS][COLS] = { 0 };
char show_board[ROWS][COLS] = { 0 };
//初始化棋盘
IntBoard(my_board, ROWS, COLS, '0');
IntBoard(show_board, ROWS, COLS, '*');
return 0;
}
打印棋盘
如下图:
怎么实现直接看代码吧
如下:
void CBoard(char board[ROWS][COLS], int row, int col)//打印棋盘
{
printf("------扫雷游戏------\n");
int i = 0;
int j = 0;
for (i = 0; i <= col; i++)//打印第一排的数字
{
printf("%d|", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d|", i);//打印第一列的数字
for (j = 1; j <= col; j++)
{
printf("%c", board[i][j]);
if (j < col)
{
printf(" ");
}
if (j == col)
{
printf("|");
}
}
printf("\n");
}
printf("------扫雷游戏------\n");
}
设置雷
首先我们需要设定一个雷的数量
如下:
#define DiLei 10
然后关于rand函数和srand函数我之前的文章也提到过了:
因为rand函数所输出的并不是一个真正的随机数,所以我们需要srand函数来辅助,让它输出一个真正的随机数。
直接看代码吧!:
void SetBoard(char board[ROWS][COLS], int row, int col)//设置雷
{
int count = DiLei;
while(count)//当count=0时停止循环
{
int x = rand() % ROW + 1;//生成1~9的随机数,注意要+1
int y = rand() % COL + 1;
if (board[x][y] == '0')//防止把雷放在同一个地方
{
board[x][y] = '1';
count--;
}
}
}
排查雷
关于排查雷,按照我之前的思路:
计算输入坐标八面的雷的个数
注意:数组里面都是字符,所以输出要转换为数字。
如下:
int get_mine_count(char mine[ROWS][COLS],int x,int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
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';
}
判断游戏状态
如下:
void FindBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
printf("请输入坐标:>");
int x = 0;
int y = 0;
int n = 0;//n是计算排查的空地的数目
while (n != row * col - DiLei)//代表雷还没扫完
{
scanf("%d%d", &x, &y);
system("cls");
if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
{
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';
DisPlayBoard(show, ROW, COL);
n++;
}
}
else
{
printf("坐标输入错误,请重新输入:>\n");
}
}
if (n == row * col - DiLei)//当格子总数减去雷个数就是空地数
{
printf("恭喜你!扫雷成功!");
}
}
更多的细节
到这里,我们的扫雷就已经写完了
加一点细节,将所有的代码整理一下如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>//Sleep函数和system函数
#define DiLei 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void menu()
{
printf("扫雷游戏\n");
printf("****************************\n");
printf("******** 1、开始 *********\n");
printf("******** 0、结束 *********\n");
printf("****************************\n");
}
void InitBoard(char board[ROWS][COLS], int rows, int cols, char sat)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = sat;
}
}
}
void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("-----扫雷游戏----\n");
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("-----扫雷游戏----\n");
}
void SetBoard(char mine[ROWS][COLS], int row, int col)
{
int count = DiLei;
while (count)
{
int x = rand()%row+1;
int y = rand()%col+1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
int get_mine_count(char mine[ROWS][COLS],int x,int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
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';
}
void FindBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int n = 0;
while (n != row * col - DiLei)
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了*_*\n");
DisPlayBoard(mine, ROW, COL);
break;
}
else
{
system("cls");
int count = get_mine_count(mine, x, y);
show[x][y] = count + '0';
DisPlayBoard(show, ROW, COL);
n++;
}
}
else
{
printf("坐标输入错误,请重新输入:>\n");
}
}
if (n == row * col - DiLei)
{
printf("恭喜你!扫雷成功!");
}
}
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
system("cls");
//打印棋盘
DisPlayBoard(show, ROW, COL);
//设置雷
SetBoard(mine, ROW, COL);
//排查雷
FindBoard(mine, show, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
{
game();
break;
}
case 0:
{
printf("结束\n");
break;
}
default:
{
printf("选择错误,请重新输入\n");
break;
}
}
} while (input);
return 0;
}
运行结果
更多的问题
我们看到上面的运行结果,虽然基本的扫雷可以实现,但是感觉就没那味:需要真的一个一个把所有的空地找出来,就显得不够方便。
所有,能不能设计一个函数,可以将没有雷的地方全部展开呢?
废话不多说,开搞✊✊!
解决问题
排查雷的函数还是这个
int get_mine_count(char board[ROWS][COLS], int x, int y)//计算坐标八方的雷数
{
return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + //第一行
board[x][y - 1] + board[x][y + 1] + //第二行
board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - (8 * '0');//第三行
//注意board里面的是字符
}
关于展开的问题
思路:我们可以利用排查雷的函数,如果它没有排到雷的话(输出为0),就检查它的八方,递归循环下去,直到排到雷为止(输出不为0)。
如下:
void OpenBoard(char my_board[ROWS][COLS], char show_board[ROWS][COLS], int x, int y)
{
int n = get_mine_count(my_board, x, y);
int i = 0;
int j = 0;
if (n != 0)//排查到雷
{
show_board[x][y] = n + '0';
}
else if (show_board[x][y] != ' ')
{
show_board[x][y] = ' ';//将没有雷的位置设置为空格
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
OpenBoard(my_board, show_board, i, j);
}
}
}
else
{
return;
}
}
判断游戏状态的优化
既然上面的展开函数将没有雷的地方设为空格,我们也就可以优化一下判断游戏状态的函数:
可以直接寻找展示给玩家的棋盘中雷(*)的个数,如果正好等于10(DiLei)个,说明游戏胜利,反之游戏继续。
如下:
void FindBoard(char my_board[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)//排查雷
{
int x = 0;
int y = 0;
while (1)//判断是否扫完了雷
{
printf("请输入坐标:>");
scanf("%d %d", &x, &y);
if (x <= 9 && x >= 1 && y <= 9 && y >= 1)
{
if (my_board[x][y] == '1')
{
printf("*_*游戏结束,你被炸死了*_*\n");
CBoard(my_board, ROW, COL);
break;
}
else
{
OpenBoard(my_board, show_board, x, y);
CBoard(show_board, ROW, COL);
}
}
else
{
CBoard(show_board, ROW, COL);
printf("坐标输入错误,重新输入\n");
}
}
int i = 0;
int j = 0;
int t = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show_board[i][j] == '*')
{
x++;
}
}
if (t == DiLei)//表示扫完所有空地
{
CBoard(show_board, ROW, COL);
printf("扫雷成功!!,你获胜啦!!!\n");
break;
}
}
}
优化后的代码
加一点细节
代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>//Sleep函数和system函数
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define DiLei 10//地雷数量
void menu()
{
printf("扫雷游戏\n");
printf("****************************\n");
printf("******** 1、开始 *********\n");
printf("******** 0、结束 *********\n");
printf("****************************\n");
}
void IntBoard(char board[ROWS][COLS], int rows, int cols, char sat)//初始化棋盘
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = sat;
}
}
}
void CBoard(char board[ROWS][COLS], int row, int col)//打印棋盘
{
printf("------扫雷游戏------\n");
int i = 0;
int j = 0;
for (i = 0; i <= col; i++)//打印第一排的数字
{
printf("%d|", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d|", i);//打印第一列的数字
for (j = 1; j <= col; j++)
{
printf("%c", board[i][j]);
if (j < col)
{
printf(" ");
}
if (j == col)
{
printf("|");
}
}
printf("\n");
}
printf("------扫雷游戏------\n");
}
void SetBoard(char board[ROWS][COLS], int row, int col)//设置雷
{
int count = DiLei;
while(count)//当count=0时停止循环
{
int x = rand() % ROW + 1;//生成1~9的随机数,注意要+1
int y = rand() % COL + 1;
if (board[x][y] == '0')//防止把雷放在同一个地方
{
board[x][y] = '1';
count--;
}
}
}
int get_mine_count(char board[ROWS][COLS], int x, int y)//计算坐标八方的雷数
{
return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + //第一行
board[x][y - 1] + board[x][y + 1] + //第二行
board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - (8 * '0');//第三行
//注意board里面的是字符
}
void OpenBoard(char my_board[ROWS][COLS], char show_board[ROWS][COLS], int x, int y)
{
int n = get_mine_count(my_board, x, y);
int i = 0;
int j = 0;
if (n != 0)
{
show_board[x][y] = '0' + n;
}
else if (show_board[x][y] != ' ')
{
show_board[x][y] = ' ';
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
OpenBoard(my_board, show_board, i, j);
}
}
}
else
{
return;
}
}
void FindBoard(char my_board[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)//排查雷
{
int x = 0;
int y = 0;
while (1)//判断是否扫完了雷
{
printf("请输入坐标:>");
scanf("%d %d", &x, &y);
system("cls");//清屏
Sleep(200);//此函数可以起到延时的功能,提高用户体验。单位ms
if (x <= 9 && x >= 1 && y <= 9 && y >= 1)
{
if (my_board[x][y] == '1')
{
printf("*_*游戏结束,你被炸死了*_*\n");
CBoard(my_board, ROW, COL);
printf("刚刚的坐标是%d %d\n", x, y);
break;
}
else
{
OpenBoard(my_board, show_board, x, y);
CBoard(show_board, ROW, COL);
}
}
else
{
CBoard(show_board, ROW, COL);
printf("坐标输入错误,重新输入\n");
}
}
int i = 0;
int j = 0;
int t = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show_board[i][j] == '*')
{
x++;
}
}
if (t == DiLei)//表示扫完所有空地
{
CBoard(show_board, ROW, COL);
printf("扫雷成功!!,你获胜啦!!!\n");
break;
}
}
}
void game()
{
char my_board[ROWS][COLS] = { 0 };
char show_board[ROWS][COLS] = { 0 };
//初始化棋盘
IntBoard(my_board, ROWS, COLS, '0');
IntBoard(show_board, ROWS, COLS, '*');
//打印棋盘
CBoard(show_board, ROW, COL);
//CBoard(my_board, ROW, COL);
//设置雷
SetBoard(my_board, ROW, COL);
//排查雷
FindBoard(my_board,show_board, ROWS, COL);
}
int main()
{
//扫雷项目
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
system("cls");
switch (input)
{
case 1:
{
game();
break;
}
case 0:
{
printf("退出游戏\n");
break;
}
default:
{
printf("选择错误,重新选择\n");
break;
}
}
} while (input);
return 0;
}
运行结果
如图:
这样看是不是舒服多了呀哈哈😁
结语
到这里,扫雷小游戏的代码就真的写完了🎉🎉🎉🎉!
若发现文章中有什么不足之处,敬请大佬指出。
希望这篇文章对大家有帮助🙂。
最后,创作不易,给个三连再走吧(❁´◡`❁)😘!