前言
❤️ 铁汁们大家好,欢迎大家来到出小月的博客里, 之前呢,我分享了C语言的函数篇。。。。今天呢,给大家分享一个童年回忆小游戏“扫雷游戏”,这个小游戏系统地把之前学的循环语句,还有函数都结合起来了,希望大家看完我这篇文章都能够“涨芝士”,感觉小月写的还不错的话,记得点赞加关注鼓励一下博主哦,不然下次可找不到我啦❗❗
作者简介
❤️ 作者的gitee:出小月;
❤️ 作者的主页:出小月的《程序员历险记》
❤️专栏:《C语言》,《数据结构初阶》
希望大家都能够:好好学习,天天编程❗❗❗
文章目录
- 前言
- 作者简介
- 一、扫雷游戏介绍
- 二、扫雷游戏最终页面
- 三、扫雷步骤分析
- 1、菜单
- 2、总体框架
- 3、游戏内容
- 4、初始化数组
- 5、打印棋盘
- 6、设置雷
- 7、排查雷
- 8、坐标周围雷的个数
- 9、递归展开周围的区域
- 总结
一、扫雷游戏介绍
《扫雷》这个游戏大家可能并不陌生,我们小的时候经常玩,记得高三的时候,早自习下课,有人就在白板上玩扫雷,哈哈哈,回忆一波。。。不会有小伙伴没有没有玩过吧❓❓没关系,小月这里再介绍一下下
游戏目标是根据点击格子出现的数字(如果这个格子上面的数字是3,就说明周围的八个位置其中有三个雷格子)找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。
来!咱们一起看这个图片这是一个9*9个格子的棋盘,中间的三代表黑方框圈起来的的格子里有三个是雷,是雷的,打咩,不能踩❗❗❗这大家应该都明白了吧!
二、扫雷游戏最终页面
首先,上来给一个菜单,输入一进入游戏,输入0退出游戏
我输入下标开始自动排查
我输入3 9,被炸死了
游戏基本就是这个,接下来就分析一下!!!
三、扫雷步骤分析
1、菜单
展示一个页面,提示用户,你选择1就进入游戏,你要是选择0就退出游戏,主要是为了更美观❗❗❗
void menu(){printf("******************************\n");printf("********* 1、play *******\n");printf("********* 0、exit *******\n");printf("******************************\n");}
2、总体框架
这个总体框架和三子棋的框架一模一样,我就不解释了。。。
可以看看这个三子棋游戏对框架的解释
void test(){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);}
3、游戏内容
我们要准备两个数组,数组一放置布置好的雷,数组二存放排查出的雷的信息。
刚开始我们要把第一个数组全部初始化为‘ 0 ’,把数组二全部初始为‘ * ’。
然后,我们要把数组一中是雷的位置置为‘ 1 ’,就要随机生成是个下标,把下标位置的字符设置成‘ 1 ’。
数组二上的数组呢?我们就在数组一中根据玩家输入的下标看周围有几个雷,有几个就把数字放到数组二中相应的位置。
思路大概就是这❗❗
这里定义ROW=9;ROWS=ROW+2;
void game(){//需要存放布置好的雷的信息,存放排查出的雷的信息,需要两个二维数组//排查坐标时为了防止数组坐标越界,我们把行增加2,列增加2char mine[ROWS][ROWS] = { 0 };//布置好的雷的数组char show[ROWS][ROWS] = { 0 };//排查出的雷的数组//默认mine数组都是字符零,默认show数组都是字符‘*’initboard(mine, ROWS, COLS, '0');initboard(show, ROWS, COLS, '*');printboard(show, ROW, COL);setmine(mine, ROW, COL);finemine(mine, show, ROW, COL);}
4、初始化数组
我们要把数组一全部置为‘ 0 ’,数组二全部置为‘ * ’。
1、那如果我们要把第一个数组置为‘ 0 ’,我们知道肯定要遍历二维数组然后把每一个元素置为‘ 0 ’,那我是不是得再写一个函数把数组二再遍历一下全部元素置为‘ * ’,
这麻烦不麻烦❓当然麻烦,我们可以直接把0或者‘ * ’直接当作一个参数传到函数就行啦!
void initboard(char board[ROWS][COLS], int rows, int cols, char ret){for (int i = 0; i < rows; i++){int j = 0;for ( j = 0; j < cols; j++){board[i][j] = ret;}}}
但是这里我们得先理解一个点,就是假如我们是99的棋盘,那我们要是排查到边的话,它周围就会越界,那我们就变成1111的棋盘,但是我们只用9*9的格子就行
5、打印棋盘
考虑到之后我们要排查某个位置的雷时需要玩家输入下标,此时如果有行的标号,有列的下标,看着就会更直观。
void printboard(char board[ROWS][COLS], int row, int col){for (int i = 0; i <= col; i++){printf("%d ",i);}printf("\n");for (int i = 1; i <= row; i++){int j = 0;printf("%d ", i);for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}}
6、设置雷
我们要设置几个雷,就循环几次,循环的内容就是:随机生成坐标,看这个坐标的位置是不是‘ 0 ’,如果是0,就把这个坐标置为1。
随机生成下标就要用rand函数,如果我们要生成0-9的下标,就是rand%ROW+1(这里ROW是9
rand函数可以随机生成一个数字,范围是0-32767,大家可以试一下,如果直接这样写,每次返回值都是一样的,因此我们要使用rand之前使用srand函数函数原型:
void srand (unsigned int seed);
这里的参数是unsigned int seed,我们经常使用time来做参数,只要每次播种的时间不同,生成的参数就不同,得到的随机数就不同
srand就是这样的srand((unsigned int)time(NULL));
它在函数中写一次就行,因此我们可以把它放在main函数中(函数参考百度);
void setmine(char board[ROWS][COLS], int row, int col){int x = 0;int y = 0;int count = easy_count;//这里的easy_count是10,就是生成是个雷x = rand() % row + 1;y = rand() % col + 1;for (int i = 0; i < count; i++)//循环生成雷{x = rand() % row + 1;//随机生成下标y = rand() % col + 1;if (board[x][y] == '0')//如果是0,就置为1{board[x][y] = '1';}}}
7、排查雷
mine数组是布置雷的数组,show数组是你输入下标展示的排查雷的数组,当玩家输入要排查的下标时,正常情况下就在mine数组的周围找找有几个雷,有几个雷,就把这个数字放到show数组中这个下标的位置上,那怎么统计这个位置的周围有几个雷呢❓❓❓下面分析;如果这个玩家输入的下标对应mine数组的位置发现刚好是‘ 1 ’,那就是被炸死了,炸死了,我就把mine数组打印出来,让他看看雷。
还有一个问题就是,那什么时候赢呢?我把所有不是雷的位置都排查完就赢了,那不是雷的位置是9*9-10=81个,因此设置一个循环,循环81次,用win计数每次成功排查一个下标,win就加一;如果我已经排查过的下标,你又输入了,就提示你“该坐标被排查过”,介绍本次,循环,进入下一次循环。
退出循环就意味着,赢了!
void finemine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col){printf("请输入要排除的下标");int x = 0;int y = 0;int win = 0;while (win<row*col-easy_count){scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (show[x][y]!='*'){printf("该坐标被排查过了");continue;}if (mine[x][y] == '1'){printf("很遗憾,你被炸死了\n");printboard(mine, row, col);}else{//OpenShow(mine, show, x, y);int ret = mine_count(mine,x,y);show[x][y] = ret + '0';printboard(show, row, col);win++;}}else{printf("坐标非法请重新输入");}}if (win == row * col - easy_count){printf("恭喜你,你赢了");printboard(mine, ROW, COL);}}
8、坐标周围雷的个数
我们设置雷的时候把雷设置的字符1,把不是雷的设置的字符0,字符零的ASC码值是48,那当然字符1-字符0=1,因此统计的时候让周围每个位置的都减去字符0,就是要减去8个字符零。
int mine_count(char mine[ROWS][COLS], int x, int y){return (mine[x][y - 1] + mine[x][y + 1] + mine[x - 1][y] + mine[x + 1][y]+ mine[x - 1][y - 1] + mine[x - 1][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0');}
9、递归展开周围的区域
我们上面最终页面是展开了一大片,但是现在我们是查找一个坐标就只展开了一个位置,因此我们要递归的展开周围区域,有三个条件
1、这个位置不是雷
2、它的周围没有雷
3、该坐标没有被排查过
void OpenShow(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)//展开周围的区域{if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1) {return;}if (show[x][y] != '*') {return;}int n = mine_count(mine, x, y);show[x][y] = n + '0';if (n > 0) {show[x][y] = n + '0';return;}if (n == 0) {OpenShow(mine, show, x - 1, y);OpenShow(mine, show, x - 1, y - 1);OpenShow(mine, show, x, y - 1);OpenShow(mine, show, x + 1, y - 1);OpenShow(mine, show, x + 1, y);OpenShow(mine, show, x + 1, y + 1);OpenShow(mine, show, x, y + 1);OpenShow(mine, show, x - 1, y + 1);}}
因此我们要修改上面查找雷的代码
else{OpenShow(mine, show, x, y);int ret = mine_count(mine,x,y);show[x][y] = ret + '0';printboard(show, row, col);win++;}
总结
好啦,今天的分享到此结束,看到这里大家应该都明白了吧,不明白没关系,直接私信小月,记得要,点赞、收藏加关注哦小月后面还会分享更多哦!!!