> 文档中心 > 【C语言】扫雷游戏(递归实现展开一片)8000字详细教学

【C语言】扫雷游戏(递归实现展开一片)8000字详细教学

🧸🧸🧸各位巨佬大家好,我是猪皮兄弟
【C语言】扫雷游戏(递归实现展开一片)8000字详细教学

这里是下面要讲的知识内容🥳🥳🥳

文章目录

  • 🚒前言
  • 一、🚀头文件部分(头文件的包含和一些函数接口)
  • 二、🚀主函数部分(main)
  • 三、🚀自定义函数的实现
    • 一、​⛄初始化雷盘
    • 二、⛄随机埋雷
    • 三、⛄打印雷盘
    • 四、⛄获取周围雷的数目
    • 五、⛄自定义Boom函数递归实现炸开一片(重点!)
    • 六、⛄排雷和标记雷
  • 、🚀

🚒前言

    今天我们学习的内容是扫雷游戏(可炸开一片和可标记)。是不是发现现在电脑上没有系统自带的扫雷游戏,那有问题吗?没有问题,今天手把手得带大家来实现一下扫雷游戏🐷,废话不多说,我们直接开始


一、🚀头文件部分(头文件的包含和一些函数接口)

#define _CRT_SECURE_NO_WARNINGS#include #include #include #include #define ROW 9#define COL 9#define ROWS ROW+2#define COLS COL+2#define SET_NUM 10//初始化雷盘void InitBoard(char board[ROWS][COLS], int rows, int cols, char init);//随机埋雷操作void SetMine(char board[ROWS][COLS], int row, int col, int num);//打印雷盘void DisplayBoard(char board[ROWS][COLS], int row, int col);//排雷操作void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],char state[ROWS][COLS]);//数该雷块的周围八个雷块埋了多少个累int get_mine_count(char board[ROWS][COLS], int x, int y);//重点!!递归实现展开一片void Boom(char show[ROWS][COLS],char mine[ROWS][COLS],char state[ROWS][COL], int x, int y);

二、🚀主函数部分(main)

首先说下为什么使用9x9的雷盘要初始化化成11x11呢?
1.首先,找周围的八个雷会简单很多。因为只在需要的9x9的二维数组里进行埋雷,所以多出来的这两行两列(雷盘上下,左右各多一行)是没有雷的,所以不影响。
2.其次,方便打印棋盘的行号和列号,如图:
【C语言】扫雷游戏(递归实现展开一片)8000字详细教学

下面是主函数和菜单的实现

void menu(){printf("*\n");printf("*0.EXIT\n");printf("*1.PLAY\n");printf("*2.RULE\n");printf("*\n");}void Rule_Menu(){printf("1.输入坐标进行雷的排查\n");printf("2.输入b进行雷的标记\n");printf("3.显示数字表示包括自己在内的九宫格中雷的数目\n");system("pause");}void game(){char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };char state[ROWS][COLS] = { 0 };InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');InitBoard(state, ROWS, COLS, '0');SetMine(mine, ROW, COL, SET_NUM);DisplayBoard(show, ROW, COL);/*DisplayBoard(mine, ROW, COL);*/FindMine(mine, show,state);}int main(){int input;srand((unsigned int)time(NULL));do{menu();printf("\n");printf("请选择:> ");rewind(stdin);scanf("%d", &input);switch (input){case 1:printf("进入游戏......\n");game();break;case 0:printf("退出游戏......\n");exit(-1);break;case 2:printf("查看规则......\n");Rule_Menu();break;default:printf("输入错误,请重新输入......\n");break;}} while (1);return 0;}

三、🚀自定义函数的实现

声明一下
show是玩家可以看到的数组
mine是用于埋雷和排雷的数组
state是用于后面递归展开时定义是否递归的状态的数组

一、​⛄初始化雷盘

void  InitBoard(char board[ROWS][COLS], int rows, int cols, char init){//char init说明你想把数组里面定义成什么内容for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){board[i][j] = init;}}}

二、⛄随机埋雷

注意:要使用rand函数,要在主函数中加入
srand(unsigned int)time(NULL);

     注意srand写的位置,你比如说要写一个才随机数字大小的游戏,那么久只能写在主函数里,不然每次猜数字都会生成一个随机值,这不是拿阳寿猜答案嘛。

void SetMine(char board[ROWS][COLS], int row, int col, int num){while (num){int x = (rand() % 9) + 1;int y = (rand() % 9) + 1;if (board[x][y] != 1){board[x][y] = '1';num--;}}}

三、⛄打印雷盘

void DisplayBoard(char board[ROWS][COLS], int row, int col){printf("------扫雷游戏------\n");for (int i = 0; i <= col; 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 ",board[i][j]);}printf("\n");}}

效果展示
【C语言】扫雷游戏(递归实现展开一片)8000字详细教学


四、⛄获取周围雷的数目

这里需要说一下字符和数字之间的相互转换
【C语言】扫雷游戏(递归实现展开一片)8000字详细教学

int get_mine_count(char board[ROWS][COLS], int x, int y){return(board[x - 1][y] +board[x - 1][y - 1] +board[x][y - 1] +board[x + 1][y - 1] +board[x + 1][y] +board[x + 1][y + 1] +board[x][y + 1] +board[x - 1][y + 1] -8 * '0');}

五、⛄自定义Boom函数递归实现炸开一片(重点!)

注意!!!
如果不进行任何条件的约束,只是往周围进行递归的话,就会死循环

这是哇网页版的扫雷,我们来看卡看它的边界条件,是不是遇到数字就停止这一块雷块的递归,好,我们下面来模仿实现一下【C语言】扫雷游戏(递归实现展开一片)8000字详细教学

蓝色圈代表排雷点,黑色线代表向周围八个展开,如下图,演示了展开方向【C语言】扫雷游戏(递归实现展开一片)8000字详细教学

     大家想象一下,约束条件也就当某一个雷块周围有雷时,会调用get_mine_count函数数周围的雷,然后在show数组中会显示出来,当遇到这一块显示数字了的,就停止递归,而且不能超过边界,也就是说x>=1&&x=1&&y<=COL

下面是对Boom的实现

void Boom(char show[ROWS][COLS], char mine[ROWS][COLS], char state[ROWS][COLS],int x, int y){state[x][y] = '1';if (x<1 || x>ROW || y<1 || y>COL)return;if (show[x][y] != ' ')return;else{/*if (get_mine_count(mine, x, y) == 0)show[x][y] = ' ';elseshow[x][y] = get_mine_count(mine, x, y) + '0';*///将周围8个先show出来,然后递归boomif (get_mine_count(mine, x - 1, y) == 0)show[x - 1][y] = ' ';elseshow[x - 1][y] = get_mine_count(mine, x - 1, y) + '0';if (get_mine_count(mine, x - 1, y - 1) == 0)show[x - 1][y - 1] = ' ';elseshow[x - 1][y - 1] = get_mine_count(mine, x - 1, y - 1) + '0';if (get_mine_count(mine, x, y - 1) == 0)show[x][y - 1] = ' ';elseshow[x][y - 1] = get_mine_count(mine, x, y - 1) + '0';if (get_mine_count(mine, x + 1, y - 1) == 0)show[x + 1][y - 1] = ' ';elseshow[x + 1][y - 1] = get_mine_count(mine, x + 1, y - 1) + '0';if (get_mine_count(mine, x + 1, y) == 0)show[x + 1][y] = ' ';elseshow[x + 1][y] = get_mine_count(mine, x + 1, y) + '0';if (get_mine_count(mine, x + 1, y + 1) == 0)show[x + 1][y + 1] = ' ';elseshow[x + 1][y + 1] = get_mine_count(mine, x + 1, y + 1) + '0';if (get_mine_count(mine, x, y + 1) == 0)show[x][y + 1] = ' ';elseshow[x][y + 1] = get_mine_count(mine, x, y + 1) + '0';if (get_mine_count(mine, x - 1, y + 1) == 0)show[x - 1][y + 1] = ' ';elseshow[x - 1][y + 1] = get_mine_count(mine, x - 1, y + 1) + '0';if(show[x-1][y]==' '&& state[x - 1][y] != '1')Boom(show, mine,state, x - 1, y);if (show[x - 1][y-1] == ' ' && state[x - 1][y-1] != '1')Boom(show, mine,state, x - 1, y - 1);if (show[x][y-1] == ' ' && state[x ][y-1] != '1')Boom(show, mine, state,x, y - 1);if (show[x + 1][y-1] == ' ' && state[x + 1][y-1] != '1')Boom(show, mine,state, x + 1, y - 1);if (show[x + 1][y] == ' '&& state[x + 1][y] != '1')Boom(show, mine,state, x + 1, y);if (show[x + 1][y+1] == ' '&& state[x + 1][y+1] != '1')Boom(show, mine,state, x + 1, y + 1);if (show[x][y+1] == ' '&& state[x][y+1] != '1')Boom(show, mine, state,x, y + 1);if (show[x - 1][y+1] == ' '&& state[x - 1][y+1] != '1')Boom(show, mine,state ,x - 1, y + 1);}}

特别注意,不能够去递归 递归过的雷块,因为我弟归你,你递归我,我再递归你,是不是就死循环了啊,所以我们重新定义了一个state数组表示这一块是否被递归过。


六、⛄排雷和标记雷

     这里用到的排雷的思想是,有雷的雷块在mine数组上是1.遇到1则炸死了,打印mine数组(让玩家死得瞑目),这里会用到Boom函数进行递归,可以先看看上面讲得递归

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],char state[ROWS][COLS]){int x, y;int input;while (1){printf("1.排雷\n");printf("2.标记雷\n");printf("3.取消标记\n");printf("请输入操作选项:>");scanf("%d",&input);switch (input){case 1:{printf("请输入排雷坐标:>");rewind(stdin);scanf("%d", &x);scanf("%d", &y);if (x >= 1 && x <= ROW && y >= 1 && y <= COL){if (show[x][y] != '*'){printf("该坐标已查找过,请重新输入.....\n");}else{if (mine[x][y] == '1'){printf("你被炸死了,loser\n");DisplayBoard(mine, ROW, COL);system("pause");exit(-1);}else{int count = get_mine_count(mine, x, y);if (count == 0){show[x][y] = ' ';Boom(show, mine, state, x, y);DisplayBoard(show, ROW, COL);}else{show[x][y] = count + '0';DisplayBoard(show, ROW, COL);}}}}else{printf("error position\n");}break;}case 2:{printf("请输入标记雷坐标;>");rewind(stdin);scanf("%d", &x);scanf("%d", &y);show[x][y] = '#';DisplayBoard(show, ROW, COL);break;}case 3:{printf("请输入取消标记坐标;>");rewind(stdin);scanf("%d", &x);scanf("%d", &y);show[x][y] = '*';DisplayBoard(show, ROW, COL);break;}default:printf("输入错误,请重新输入.....\n");break;}}}

好了,今天的扫雷游戏就到这里,感谢大家对猪皮的支持!!!


、🚀

        当你看到这里,相信上面的内容已经倒背如流了吧😶‍🌫️😶‍🌫️😶‍🌫️。各位巨佬如果觉得有帮助的话,还望各位父老乡亲动动小手指👈👇👉点点点。一键三连有问题吗?没有问题,这都是什么?人情世故
在这里插入图片描述

户口查询网