C语言之扫雷游戏(功能扩展+代码解析!)

发布时间:2026/10/31 1:35:22
C语言之扫雷游戏(功能扩展+代码解析!) 首先声明此博客不照搬抄袭存在自己的见解我所使用的编译器是VS2022一、项目介绍分析与设计1扫雷游戏的玩法介绍玩家通过输入坐标翻开对应格子依靠数字提示判断周围地雷数量合理排查安全区域。若点开地雷则游戏失败成功找出所有无雷格子即可获胜。2扫雷游戏的分析与设计分析程序需要实现的功能- 给玩家一个菜单玩家可通过菜单选择是否进入游戏。- 雷每一把都是随机布置的。- 玩家可输入坐标进行排查若所选位置无雷则显示该位置周围的地雷总数。- 若踩中地雷则游戏失败。- 排查出所有的无雷格子后排查的无雷的格子总数大于等于或者就等于格子总数包括雷减去雷的数量时则判断游戏胜利。或者判断未翻出的格子如果小于等于或者就等于雷的个数而且没被炸死则说明游戏胜利。- 简易版本为9*9的扫雷棋盘10个雷。中等版本为16*16的棋盘40个雷。困难版本为30*16的棋盘99个雷。设计扫雷功能模块的架构首先我们需要9*9的格子数来存放我们的雷和无雷区域很容易联想到二维数组无雷则存0有雷则存1其次因为我们要计算的是排查的每一格该格周围一圈雷的总数当我们计算上图8,6坐标时会出现下图情况数组越界计算因为我们只有9*9的方格所以我们要将数组扩展一圈变成11*11的数组以便于计算排查格子周围雷的数量但是真正存放雷和排查雷还是在里面的9*9方格里去实现如上图所示扩展为11*11的格子数此时我们注意一个巧妙的点虽然我们扩展为11*11的数组但我们展示存放和排查的还是里面9*9的数组此时看9*9数组对应的下标行和列刚好都是从1开始这更便于真实用户进行游戏时找到自己想排查格子的对应下标我们采用两个数组分别用于存储和展示数据- mine用于存放雷的操作1表示雷0表示无雷- show用于将排查雷的信息展现给游玩者*表示未排查格子数字表示该格周围雷的总数我们需要几个函数实现上述功能 首先需要两个源文件test.c)(game.c和一个头文件(game.h)- test.c 用于存放主函数实现游戏逻辑的整体运行- game.c用于实现各个函数的定义- game.h用于对各个函数的声明其次需要两个数组 - mine用于存放雷的操作1表示雷0表示无雷- show用于将排查雷的信息展现给游玩者*表示未排查格子数字表示该格周围雷的总数其次函数模块的划分 - InitBoard 用于初始化棋盘- PrintBoard 用于打印棋牌- SetMine 用于布置雷- GetGround 用于统计坐标周围雷的个数- FindMine 用于实现排查雷的操作二、代码详细解析未扩展功能版头文件的声明和宏定义game.h文件中#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h #define Row 9 #define Col 9 #define Rows 11 #define Cols 11 #define Low 10 void menu(); void game(); void InitBoard(char arr[Rows][Cols], int rows, int cols, char set); void PrintBoard(char arr[Rows][Cols], int row, int col); void SetMine(char mine[Rows][Cols], int row, int col, char set); void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col); #include time.h #include stdlib.h因为我们需要对二维数组进行操作我们即需要对内层9*9的方格进行操作也需要对外层11*11的方格进行操作所以在此我们设计四个宏定义分别表示行和列主函数游戏总体逻辑time.c文件中首先当我们想要游玩这个游戏之前我们先要给玩家添加一个游戏菜单供玩家选择是否游玩//test.c文件中 #include stdio.h void menu() { printf(*******************\n); printf(******1.enter******\n); printf(******0.exit*******\n); printf(*******************\n); } int main() { int k 0; //srand((unsigned int)time(NULL)); do { menu(); scanf(%d, k); switch (k) { case 1: { printf(进入游戏\n); //printf(-------------------\n);//每次进入游戏后用这个隔开再打印棋盘能让画面更清白明了 //game();进入game函数 break; } case 0: { printf(退出游戏\n); break; } default: { printf(输入错误请重新输入\n); break; } } } while (k); return 0; }运行截图如上图所示输入1进入游戏输入0退出游戏因为无论怎么我们都要先打印菜单供玩家选择是否进入游戏所以我们采用do_while循环,上来就先打印菜单告诉玩家要做什么对于菜单这种可选固定几个整型常量表达式的我们采用switch语句来实现功能会比if更好更快输入1我们就进入game函数开始游戏//在test.c文件中 void game() { char mine[Rows][Cols] { 0 }; char show[Rows][Cols] { 0 }; char ch1 0; char ch2 *; char ch3 1; InitBoard(mine, Rows, Cols, ch1);//初始化棋盘 InitBoard(show, Rows, Cols, ch2);//初始化棋盘 //PrintBoard(mine, Row, Col); //mine棋盘是给设计者看的 PrintBoard(show, Row, Col); //show棋盘是给玩家看的 SetMine(mine, Row, Col, ch3); //设置棋盘 // PrintBoard(mine, Row, Col);//观察是否设置雷成功 FindMine(mine, show, Row, Col); }我们创造了两个数组分别为mine和show首先对他们分别进行初始化初始化好后打印show棋盘给玩家看供玩家进行操作当然这步操作也可以放在将棋盘的雷设置好之后就是打印show数组的指令PrintBoard(show, Row, Col)放在SetMine(mine, Row, Col, ch3)之后也是可以的但要在FindMine函数之前不然玩家看不到棋盘没法排查游戏逻辑具体函数的定义game.c文件中1InitBoard函数初始化棋盘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; } } }用于初始化数组我们传入了mine和show数组传这两个数组函数只能用char arr[Rows][Cols]接收因为数组的大小为11*11的格子我们要全部初始化这里不是只对里面的9*9进行操作而是全部都要操作2PrintBoard函数打印棋盘的函数void PrintBoard(char arr[Rows][Cols], int row, int col) { // 打印顶部列号0 1 2 3 ... for (int i 0; i col; i) { printf(%-2d , i); } printf(\n); // 打印每一行行号 格子内容 for (int j 1; j row; j) { printf(%-2d , j); for (int k 1; k col; k) { printf(%-2c , arr[j][k]); } printf(\n); } printf(-------------------\n); }我们在初始化完后可以打印一下这两个数组如上图是在test.c文件中看看是否初始化成功运行截图可以看到初始化成功我们还在数组前给他添加了坐标便于游玩者寻找正常的坐标3SetMine函数利用rand函数在随机位置设置雷在mine棋盘中需要在主函数mian函数中调用srandunsigned inttimeNULL函数才能正确使用rand函数void SetMine(char mine[Rows][Cols], int row, int col, char set) { int count Low; while (count) { int x rand() % row 1; int y rand() % col 1; if (mine[x][y] ! set) { mine[x][y] set; count--; } } }我们可以观察是否设置好雷运行截图10颗雷已设置完成4FindMine函数用于实现排查坐标的函数void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col) { int i 0; int j 0; int count Low; int amount 0; while (amount (row * col - Low)) { printf(请选择需要排查的坐标:\n); scanf(%d%d, i, j); if (i 0 i row j 0 j col) { if (show[i][j] ! *) { printf(已经被排查过了\n); continue; } if (mine[i][j] 0) { show[i][j] GetGround(mine, i, j) 0; PrintBoard(show, Row, Col); // PrintBoard(mine, Row, Col); amount; } else { printf(不好意思你被炸死了\n); PrintBoard(mine, Row, Col); break; } } else { printf(坐标非法输入\n); } } if (amount row * col - Low) { printf(恭喜你排雷成功\n); PrintBoard(mine, Row, Col); } }因为show棋盘中打印的是字符而GetGround函数返回的是整型类型的数字当数字加上字符0时对应的才是ascll里的该数字才可以用字符占位符打印出来它本身如printf(%c, 20)因为0的asll码值是48,所以就是24850ascll码值50对应的数字就是2所以才会打印2当你写printf(%c,2)时打印的是ascll值为2对应的字符而不会打印数字2这里的循环条件是每翻一个格子amount就加1直到amount加到等于格子总数-雷的个数时则说明游戏胜利结束循环5GetGround函数用于统计坐标周围雷的总数int GetGround(char mine[Rows][Cols], int i, int j)//统计周围坐标周围雷的个数 { return (mine[i - 1][j - 1] mine[i - 1][j] mine[i - 1][j 1] mine[i][j - 1] mine[i][j 1] mine[i 1][j - 1] mine[i 1][j] mine[i 1][j 1]) - 8 * 0; }当然也可以用for循环来写int GetGround(char mine[ROWS][COLS], int x, int y) { int sum 0; for (int i -1; i 1; i) { for (int j -1; j 1; j) { sum sum mine[xi][yj]; } } return sum - 9 * 0; }因为mine数组里不是雷的位置存的本来就是0所以我们将该格包括该格周围所有数的ascll码的值相加后还要9个字符‘0’相乘才能得到十进制整型数字到此扫雷扫码整体的功能已实现效果展示详细总代码照搬可直接运行game.h#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h #define Row 9 #define Col 9 #define Rows 11 #define Cols 11 #define Low 10 void menu(); void game(); void InitBoard(char arr[Rows][Cols], int rows, int cols, char set); void PrintBoard(char arr[Rows][Cols], int row, int col); void SetMine(char mine[Rows][Cols], int row, int col, char set); void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col); #include time.h #include stdlib.hgame.c#define _CRT_SECURE_NO_WARNINGS 1 #include game.h 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 PrintBoard(char arr[Rows][Cols], int row, int col) { // 打印顶部列号0 1 2 3 ... for (int i 0; i col; i) { printf(%-2d , i); } printf(\n); // 打印每一行行号 格子内容 for (int j 1; j row; j) { printf(%-2d , j); for (int k 1; k col; k) { printf(%-2c , arr[j][k]); } printf(\n); } printf(-------------------\n); } void SetMine(char mine[Rows][Cols], int row, int col, char set) { int count Low; while (count) { int x rand() % row 1; int y rand() % col 1; if (mine[x][y] ! set) { mine[x][y] set; count--; } } } int GetGround(char mine[Rows][Cols], int i, int j)//统计周围坐标周围雷的个数 { return (mine[i - 1][j - 1] mine[i - 1][j] mine[i - 1][j 1] mine[i][j - 1] mine[i][j 1] mine[i 1][j - 1] mine[i 1][j] mine[i 1][j 1]) - 8 * 0; } void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col) { int i 0; int j 0; int count Low; int amount 0; while (amount (row * col - Low)) { printf(请输入要排查的坐标); scanf(%d%d, i, j); if (i 0 i row j 0 j col) { if (show[i][j] ! *) { printf(已经被排查过了\n); continue; } if (mine[i][j] 0) { show[i][j] GetGround(mine, i, j) 0; PrintBoard(show, Row, Col); // PrintBoard(mine, Row, Col); amount; } else { printf(不好意思你被炸死了\n); PrintBoard(mine, Row, Col); break; } } else { printf(坐标非法输入\n); } } if (amount row * col - Low) { printf(恭喜你排雷成功下面给出雷所在的棋盘供你查看\n); PrintBoard(mine, Row, Col); } }test.c#define _CRT_SECURE_NO_WARNINGS 1 #include game.h void menu() { printf(*******************\n); printf(******1.enter******\n); printf(******0.exit*******\n); printf(*******************\n); } void game() { char mine[Rows][Cols] { 0 }; char show[Rows][Cols] { 0 }; char ch1 0; char ch2 *; char ch3 1; InitBoard(mine, Rows, Cols, ch1);//初始化棋盘 InitBoard(show, Rows, Cols, ch2);//初始化棋盘 //PrintBoard(mine, Row, Col); PrintBoard(show, Row, Col); SetMine(mine, Row, Col,ch3); //PrintBoard(mine, Row, Col);//观察是否设置雷成功 FindMine(mine, show,Row, Col); } int main() { menu(); int k 0; srand((unsigned int)time(NULL)); do { printf(请选择玩还是不玩\n); scanf(%d, k); switch (k) { case 1: { printf(进入游戏\n); printf(-------------------\n); game(); break; } case 0: { printf(退出游戏\n); break; } default: { printf(输入错误请重新输入\n); break; } } } while (k); return 0; }三、代码详细解析扩展功能版扩展功能•如果排查位置不是雷周围也没有雷可以展开周围的一片•是否可以标记雷•是否可以加上排雷的时间显示标记雷功能void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col) { int i 0; int j 0; int count Low; int amount 0; while (amount (row * col - Low)) { printf(请选择需要排查的坐标(输入0 0进入标记模式):\n); scanf(%d%d, i, j); //扩展标记雷的功能 if (i 0 j 0)//扩展标记雷的功能; { printf(请输入要标记的坐标); scanf(%d%d, i, j); if (i 0 i row j 0 j col) { if (show[i][j] *) { show[i][j] !; PrintBoard(show, Row, Col); continue; } else if (show[i][j] !) { show[i][j] *; printf(已经取消该坐标标记); PrintBoard(show, Row, Col); continue; } else { printf(该位置已被掀开无法标记); PrintBoard(show, Row, Col); continue; } } else { printf(坐标非法输入); continue; } } //排查雷的功能 if (i 0 i row j 0 j col) { if (show[i][j] ! *) { printf(已经被排查过了\n); continue; } if (mine[i][j] 0) { show[i][j] GetGround(mine, i, j) 0; PrintBoard(show, Row, Col); // PrintBoard(mine, Row, Col); amount; } else { printf(不好意思你被炸死了\n); PrintBoard(mine, Row, Col); break; } } else { printf(坐标非法输入\n); } } if (amount row * col - Low) { printf(恭喜你排雷成功\n); PrintBoard(mine, Row, Col); } }如果输入0 0我们就进入标记坐标模式如果输入标记的坐标在合法范围内则判断show[i][j]是‘*’则改为‘!’;如果标记的坐标show[i][j]是‘!’,则改为*如果重复标记则会说明该位置已被掀开无法标记而且每个if操作后都要加continue跳过下方的排查雷的代码否则标记完后那个坐标又会直接进入排查逻辑就混乱了排雷的时间显示首先普及一个知识点time_t 本质上就是整数类型一般是 long long / long void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col) { int i 0; int j 0; int count Low; int amount 0; time_t start_time time(NULL); while (amount (row * col - Low)) { int use_time (int)(time(NULL) - start_time); printf(\n); printf( 已用时%d 秒\n, use_time); printf(\n); printf(请选择需要排查的坐标输入 0 0 进入标记模式\n); scanf(%d%d, i, j); if (i 0 j 0)//扩展标记雷的功能; { printf(请输入要标记的坐标); scanf(%d%d, i, j); if (i 0 i row j 0 j col) { if (show[i][j] *) { show[i][j] !; PrintBoard(show, Row, Col); continue; } else if (show[i][j] !) { show[i][j] *; printf(已经取消该坐标标记); PrintBoard(show, Row, Col); continue; } else { printf(该位置已被掀开无法标记); PrintBoard(show, Row, Col); continue; } } else { printf(坐标非法输入); continue; } } if (i 0 i row j 0 j col) { if (show[i][j] ! *) { printf(已经被排查过了\n); continue; } if (mine[i][j] 0) { show[i][j] GetGround(mine, i, j) 0; PrintBoard(show, Row, Col); // PrintBoard(mine, Row, Col); amount; } else { printf(不好意思你被炸死了\n); PrintBoard(mine, Row, Col); break; } } else { printf(坐标非法输入\n); } } if (amount row * col - Low) { time_t total_time (int)time(NULL) - start_time; printf(\n); printf( 已用时%d 秒\n, total_time); printf(\n); printf(恭喜你排雷成功下面给出雷所在的棋盘供你查看\n); PrintBoard(mine, Row, Col); } }time_t start_time time(NULL);time函数的返回类型是time_t,可以返回一个时间戳所以我们创建了一个起始的时间变量start_time,表示初始时间int use_time (int)(time(NULL) - start_time); printf(\n); printf( 已用时%d 秒\n, use_time); printf(\n);我们使用变量use_time来记录走过时间的秒数当前时间戳减去刚才创建的初始时间戳的值就是走过的秒数并且打印出来并在每次执行操作排查或者标记之前打印一遍让我们做到每标记一个每排查一个之前都能看到所用时间模拟时间一直在屏幕的效果效果演示展开周围一片雷功能Expand函数利用递归实现展开void Expand(char mine[Rows][Cols], char show[Rows][Cols], int x, int y, int row, int col) { // 1. 如果坐标越界直接返回 if (x 1 || x row || y 1 || y col) return; // 2. 该格子已经被翻开/标记过不再处理 if (show[x][y] ! *) return; //计算该位置周围有没有雷 int count GetGround(mine,x,y); //如果有雷则显示出来 if (count 0 ) { show[x][y] count0; //PrintBoard(show, Row, Col);可以看到一步步的递归过程看到怎扩展的 return; } else { show[x][y] 0; for (int i -1; i 1; i) { for (int j -1; j 1; j) { Expand(mine, show, xi, yj ,Row, Col); } } } }首先判断排查的该坐标是否越界也就是是否会排查9*9格子以外的格子如果越界的话就直接返回上一层Expand函数不执行下方的代码防止越界。然后判断show[x][y]如果不是*,而是其他数字说明已经被翻开过不用再次展开。上述两个条件很重要这是递归运行下去的条件然后我们利用int count GetGround(mine,x,y)计算该位置周围有没有雷如果count0贼将该位置改为周围雷的总数如果count0说明没有雷则对其周围所有位置再次进行自身函数调用不断展开形成递归GetGround函数用于计算坐标周围雷的个数int GetGround(char mine[Rows][Cols],int i, int j)//统计周围坐标周围雷的个数 { return (mine[i - 1][j - 1] mine [i-1][j] mine[i-1][j1] mine[i][j-1] mine[i][j1] mine[i1][j-1] mine[i 1][j] mine[i 1][j 1]) - 8 * 0; }GetCount函数用于统计当前还有多少个没有翻开的格子int GetCount(char show[Rows][Cols], int row, int col)//排查有多少个没开的格子 { int count 0; for (int i 1; i row; i) { for (int j 1; j col; j) { if (show[i][j] *) { count; } } } return count; }FindMine函数用于排查和标记雷void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col) { int i 0; int j 0; int count Low; int amount 0; time_t start_time time(NULL); while (GetCount(show, Row, Col) Low) { int use_time (int)(time(NULL) - start_time); printf(\n); printf( 已用时%d 秒\n, use_time); printf(\n); printf(请选择需要排查的坐标输入 0 0 进入标记模式\n); scanf(%d%d, i, j); if (i 0 j 0)//扩展标记雷的功能; { printf(请输入要标记的坐标); scanf(%d%d, i, j); if (i 0 i row j 0 j col) { if (show[i][j] *) { show[i][j] !; PrintBoard(show, Row, Col); continue; } else if (show[i][j] !) { show[i][j] *; printf(已经取消该坐标标记); PrintBoard(show, Row, Col); continue; } else { printf(该位置已被掀开无法标记); PrintBoard(show, Row, Col); continue; } } else { printf(坐标非法输入); continue; } } if (i 0 i row j 0 j col) { if (show[i][j] !) { printf(该位置已被标记不能排查); PrintBoard(show, Row, Col); continue; } if (show[i][j] ! * show[i][j] ! !) { printf(已经被排查过了\n); PrintBoard(show, Row, Col); continue; } if (mine[i][j] 0) { //show[i][j] GetGround(mine, i, j)0; Expand(mine,show,i,j,Row,Col); PrintBoard(show, Row, Col); } else { printf(不好意思你被炸死了\n); PrintBoard(mine, Row, Col); break; } } else { printf(坐标非法输入\n); } } if (GetCount(show, Row, Col) Low) { time_t total_time (int)time(NULL) - start_time; printf(\n); printf( 已用时%d 秒\n, total_time); printf(\n); printf(恭喜你排雷成功\n); PrintBoard(mine, Row, Col); } }这里我们while循环的判断条件原本是amount (row * col - Low)需要改成GetCount(show, Row, Col) Low添加GetCount(函数来统计当前还有多少个没有翻开的格子如果未翻开格子数大于Low贼说明还有无雷格子没翻开如果未翻开格子数等于Low则说明棋盘上剩的全是有雷格子已全部排查完游戏胜利为什么要这样改呢是因为我们在之前用amount统计的位置现在调用了Expend函数Expend函数会扩展展开很多个格子但amount只加1无法正确统计翻开的格子数所以我们重新用一个GetCount函数一格一格验证是否翻开然后统计我们在该逻辑下要的正确的未翻开的格子数最后如果GetCount(show, Row, Col) Low则说明棋盘上剩余格子全是雷如下图代码所示if (GetCount(show, Row, Col) Low) { time_t total_time (int)time(NULL) - start_time; printf(\n); printf( 已用时%d 秒\n, total_time); printf(\n); printf(恭喜你排雷成功\n); PrintBoard(mine, Row, Col); }我们此时又创建了一个总时间total_time变量并用当前时间戳减去我们查找程序刚开始时创建的start_time变量就是我们游戏使用的总时长时间然后打印出来并说明游戏胜利给出玩家雷所在的棋盘。到此功能扩展完成。如果你想增加棋盘的难度想扩展棋盘的大小只需要在game.h的头文件里的宏定义中下方的game.h头文件是扩展功能之后的代码头文件#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h #define Row 9 #define Col 9 #define Rows 11 #define Cols 11 #define Low 10 void menu(); void game(); void InitBoard(char arr[Rows][Cols], int rows, int cols, char set); void PrintBoard(char arr[Rows][Cols], int row, int col); void SetMine(char mine[Rows][Cols], int row, int col, char set); #include time.h #include stdlib.h int GetGround(char mine[Rows][Cols], int i, int j); int GetCount(char show[Rows][Cols], int row, int col); void Expand(char mine[Rows][Cols], char show[Rows][Cols], int x, int y, int row, int col); void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col);简单9*9 棋盘10 个雷中等 16*16 棋盘40 个雷困难 30*16 棋盘99 个雷比如你想扩展成中等难度的棋盘游戏就这样改改棋盘大小和扩展棋盘的大小#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h #define Row 16 #define Col 16 #define Rows 18 #define Cols 18 #define Low 40 void menu(); void game(); void InitBoard(char arr[Rows][Cols], int rows, int cols, char set); void PrintBoard(char arr[Rows][Cols], int row, int col); void SetMine(char mine[Rows][Cols], int row, int col, char set); #include time.h #include stdlib.h int GetGround(char mine[Rows][Cols], int i, int j); int GetCount(char show[Rows][Cols], int row, int col); void Expand(char mine[Rows][Cols], char show[Rows][Cols], int x, int y, int row, int col); void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col);就可以了扩展后详细总代码照搬可直接运行game.h#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h #define Row 16 #define Col 16 #define Rows 18 #define Cols 18 #define Low 40 void menu(); void game(); void InitBoard(char arr[Rows][Cols], int rows, int cols, char set); void PrintBoard(char arr[Rows][Cols], int row, int col); void SetMine(char mine[Rows][Cols], int row, int col, char set); #include time.h #include stdlib.h int GetGround(char mine[Rows][Cols], int i, int j); int GetCount(char show[Rows][Cols], int row, int col); void Expand(char mine[Rows][Cols], char show[Rows][Cols], int x, int y, int row, int col); void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col);game.c#define _CRT_SECURE_NO_WARNINGS 1 #include game.h 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 PrintBoard(char arr[Rows][Cols], int row, int col) { // 打印顶部列号 1 2 3 ... for (int i 0; i col; i) { printf(%-2d , i); } printf(\n); // 打印每一行行号 格子内容 for (int j 1; j row; j) { printf(%-2d , j); for (int k 1; k col; k) { printf(%-2c , arr[j][k]); } printf(\n); } printf(-------------------\n); } void SetMine(char mine[Rows][Cols], int row, int col, char set) { int count Low; while(count) { int x rand()%row1; int y rand()%col1; if (mine[x][y] ! set) { mine[x][y] set; count--; } } } void Expand(char mine[Rows][Cols], char show[Rows][Cols], int x, int y, int row, int col) { // 1. 如果坐标越界直接返回 if (x 1 || x row || y 1 || y col) return; // 2. 该格子已经被翻开/标记过不再处理 if (show[x][y] ! *) return; //计算该位置周围有没有雷 int count GetGround(mine,x,y); //如果有雷则显示出来 if (count 0 ) { show[x][y] count0; //PrintBoard(show, Row, Col);可以看到一步步的递归过程看到怎扩展的 return; } else { show[x][y] 0; for (int i -1; i 1; i) { for (int j -1; j 1; j) { Expand(mine, show, xi, yj ,Row, Col); } } } } int GetGround(char mine[Rows][Cols],int i, int j)//统计周围坐标周围雷的个数 { return (mine[i - 1][j - 1] mine [i-1][j] mine[i-1][j1] mine[i][j-1] mine[i][j1] mine[i1][j-1] mine[i 1][j] mine[i 1][j 1]) - 8 * 0; } int GetCount(char show[Rows][Cols], int row, int col)//排查有多少个没开的格子 { int count 0; for (int i 1; i row; i) { for (int j 1; j col; j) { if (show[i][j] *) { count; } } } return count; } void FindMine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col) { int i 0; int j 0; int count Low; int amount 0; time_t start_time time(NULL); while (GetCount(show, Row, Col) Low) { int use_time (int)(time(NULL) - start_time); printf(\n); printf( 已用时%d 秒\n, use_time); printf(\n); printf(请选择需要排查的坐标输入 0 0 进入标记模式\n); scanf(%d%d, i, j); if (i 0 j 0)//扩展标记雷的功能; { printf(请输入要标记的坐标); scanf(%d%d, i, j); if (i 0 i row j 0 j col) { if (show[i][j] *) { show[i][j] !; PrintBoard(show, Row, Col); continue; } else if (show[i][j] !) { show[i][j] *; printf(已经取消该坐标标记); PrintBoard(show, Row, Col); continue; } else { printf(该位置已被掀开无法标记); PrintBoard(show, Row, Col); continue; } } else { printf(坐标非法输入); continue; } } if (i 0 i row j 0 j col) { if (show[i][j] !) { printf(该位置已被标记不能排查); PrintBoard(show, Row, Col); continue; } if (show[i][j] ! * show[i][j] ! !) { printf(已经被排查过了\n); PrintBoard(show, Row, Col); continue; } if (mine[i][j] 0) { //show[i][j] GetGround(mine, i, j)0; Expand(mine,show,i,j,Row,Col); PrintBoard(show, Row, Col); } else { printf(不好意思你被炸死了\n); PrintBoard(mine, Row, Col); break; } } else { printf(坐标非法输入\n); } } if (GetCount(show, Row, Col) Low) { time_t total_time (int)time(NULL) - start_time; printf(\n); printf( 已用时%d 秒\n, total_time); printf(\n); printf(恭喜你排雷成功\n); PrintBoard(mine, Row, Col); } }test.c#define _CRT_SECURE_NO_WARNINGS 1 #include game.h void menu() { printf(*******************\n); printf(******1.enter******\n); printf(******0.exit*******\n); printf(*******************\n); } void game() { char mine[Rows][Cols] { 0 }; char show[Rows][Cols] { 0 }; char ch1 0; char ch2 *; char ch3 1; InitBoard(mine, Rows, Cols, ch1);//初始化棋盘 InitBoard(show, Rows, Cols, ch2);//初始化棋盘 //PrintBoard(mine, Row, Col); PrintBoard(show, Row, Col); SetMine(mine, Row, Col,ch3); //PrintBoard(mine, Row, Col);//观察是否设置雷成功 FindMine(mine, show,Row, Col); } int main() { menu(); int k 0; srand((unsigned int)time(NULL)); do { printf(请选择玩还是不玩\n); scanf(%d, k); switch (k) { case 1: { printf(进入游戏\n); printf(-------------------\n); game(); break; } case 0: { printf(退出游戏\n); break; } default: { printf(输入错误请重新输入\n); break; } } } while (k); return 0; }

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询