ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从零开始用 C 语言写扫雷

从零开始用 C 语言写扫雷 目录项目结构文件划分菜单和棋盘初始化为什么用 11×11 存 9×9打印棋盘雷区与显示区随机埋雷生成玩家操作输入、判断、输赢游戏主循环菜单与流程控制踩坑记录完整代码总结1.项目结构本项目采用多文件编程将声明、实现和入口分离让每个文件职责清晰方便后续维护和调试。文件职责game.h定义棋盘大小等宏声明所有函数game.c实现初始化、埋雷、打印、玩家操作等逻辑test.c编写main()函数调用菜单和游戏流程2.菜单和棋盘初始化打印菜单的代码如下test.cvoidmenu(){printf(- - - - - - - - - - - -\n);printf(- - - - 1.play - - - -\n);printf(- - - - 0.exit - - - -\n);printf(- - - - - - - - - - - -\n);}intmain(){intn0;do{menu();printf(the number is: );scanf(%d,n);switch(n){case1://game();break;case0:printf(exit);break;default:printf(error);break;}}while(n);return0;}在这里我把玩游戏的区域设为 9×9 但对于整个棋盘需设置为 11×11 因为在后续计算每个格子周围 8 个方向的雷数时边缘格子会访问到 [-1] 或 [9] 这样的越界下标。多出一圈围墙后所有合法格子的周围 8 个方向都在数组范围内不需要额外写边界判断。game.h#defineROWS11#defineCOLS11#defineROW9#defineCOL9voidInitboard(charboard[ROWS][COLS],intr,intc,charset);test.cvoidgame(){charmine[ROWS][COLS]{0};charshow[ROWS][COLS]{0};Initboard(show,ROWS,COLS,?);Initboard(mine,ROWS,COLS,0);}game.cvoidInitBoard(charboard[ROWS][COLS],intr,intc,charset){for(inti0;ir;i){for(intj0;jc;j){board[i][j]set;}}}3. 打印棋盘雷区与显示区game.hvoidDislayBoard(charboard[ROWS][COLS],intr,intc);game.cvoidDisplayBoard(charboard[ROWS][COLS],intr,intc){inti0;intj0;for(j;jr;j){printf(%d ,j);}printf(\n);for(i1;ir;i){printf(%d ,i);for(j1;jc;j){printf(%c ,board[i][j]);}printf(\n);}printf(\n);}test.cvoidgame(){DisplayBoard(show,ROW,COL);DisplayBoard(mine,ROW,COL);}4. 随机埋雷生成game.h#includestdlib.h#includetime.h#defineSET10voidSetmine(charboard[ROWS][COLS],intr,intc);game.cvoidSetmine(charboard[ROWS][COLS],intr,intc){intcountSET;while(count){intxrand()%r1;intyrand()%c1;if(board[x][y]0){board[x][y]1;count--;}}}test.cvoidgame(){Setmine(mine,ROW,COL);}intmain(){srand((unsignedint)time(NULL));}5. 玩家操作输入、判断、输赢这个模块是玩游戏的重要部分下面我讲拆成一下六个部分来讲解输入坐标通过输入行号和列号来选择要翻开的格子比如输入 2 3 表示翻开第 2 行第 3 列。合法性判断输入的坐标不能越界并且不能是已经翻过的格子这里需要判断合不合法不合法时提示重新输入合法才继续。踩雷判断翻开格子后需根据mine棋盘看是 ‘1’ 还是 ‘0’ 是 ‘1’ 结束游戏 是 ‘0’ 继续游戏。计算周围的雷数如果没踩雷统计该格子周围 8 个方向有多少个 ‘1’把结果写入 show 棋盘对应位置。关于计算雷数的方法有多种这里我介绍两个方法1returnboard[x1][y]board[x1][y-1]board[x1][y1]board[x][y1]board[x][y-1]board[x-1][y]board[x-1][y1]board[x-1][y-1]-8*0;思路把 8 个方向的字符全部加起来最后统一减去 8 * ‘0’把 8 个字符都转成数字。方法2for(i-1;i1;i){for(j-1;j1;j){count(mine[xi][yj]-0);}}returncount;思路用 i 和 j 从 -1 到 1 遍历刚好覆盖周围 8 个方向加上自身。每个格子单独减 ‘0’ 转成数字后累加。胜利判断每次成功翻开一个格子后检查是否所有非雷格子都已被翻开。如果是则玩家获胜。循环控制把以上步骤放在一个循环里玩家每回合操作一次直到踩雷失败或全部翻开胜利才退出循环。结合以上思路得到以下代码game.hvoidSearchmine(charshow[ROWS][COLS],charmine[ROWS][COLS],intr,intc);game.cinttne_number_of_mine(charboard[ROWS][COLS],intx,inty){returnboard[x1][y]board[x1][y-1]board[x1][y1]board[x][y1]board[x][y-1]board[x-1][y]board[x-1][y1]board[x-1][y-1]-8*0;}voidSearchmine(charshow[ROWS][COLS],charmine[ROWS][COLS],intr,intc){intx,y;intamount0;printf(site : );scanf(%d %d,x,y);while(amountr*c-SET){if(x0xry0yc){if(show[x][y]?){intcounttne_number_of_mine(mine,x,y);show[x][y]0count;DisplayBoard(show,ROW,COL);amount;}else{printf(bomb! you dead\n);DisplayBoard(mine,ROW,COL);break;}}else{printf(the address is illegal\n);break;}}if(amountr*c-SET){printf(congratulation! you make it\n);DisplayBoard(mine,ROW,COL);}}test.cvoidgame(){Searchmine(show,mine,ROW,COL);}6. 踩坑记录再写代码时需注意这两个函数的顺序SetMine(mine, ROW, COL); 在前DisplayBoard(mine, ROW, COL);在后。SetMine(mine,ROW,COL);DisplayBoard(mine,ROW,COL);7. 完整代码game.h#includestdio.h#includestdlib.h#includetime.h#defineROWS11#defineCOLS11#defineROW9#defineCOL9#defineSET10voidInitboard(charboard[ROWS][COLS],intr,intc,charset);voidDislayBoard(charboard[ROWS][COLS],intr,intc);voidSetmine(charboard[ROWS][COLS],intr,intc);voidSearchmine(charshow[ROWS][COLS],charmine[ROWS][COLS],intr,intc);game.c#define_CRT_SECURE_NO_WARNINGS#includegame.hvoidInitboard(charboard[ROWS][COLS],intr,intc,charset){inti0;intj0;for(i1;ir;i){for(j1;jc;j){board[i][j]set;}}}voidDisplayBoard(charboard[ROWS][COLS],intr,intc){inti0;intj0;for(j;jr;j){printf(%d ,j);}printf(\n);for(i1;ir;i){printf(%d ,i);for(j1;jc;j){printf(%c ,board[i][j]);}printf(\n);}printf(\n);}voidSetmine(charboard[ROWS][COLS],intr,intc){intcountSET;while(count){intxrand()%r1;intyrand()%c1;if(board[x][y]0){board[x][y]1;count--;}}}inttne_number_of_mine(charboard[ROWS][COLS],intx,inty){returnboard[x1][y]board[x1][y-1]board[x1][y1]board[x][y1]board[x][y-1]board[x-1][y]board[x-1][y1]board[x-1][y-1]-8*0;}voidSearchmine(charshow[ROWS][COLS],charmine[ROWS][COLS],intr,intc){intx,y;intamount0;printf(site : );scanf(%d %d,x,y);while(amountr*c-SET){if(x0xry0yc){if(show[x][y]?){intcounttne_number_of_mine(mine,x,y);show[x][y]0count;DisplayBoard(show,ROW,COL);amount;}else{printf(bomb! you dead\n);DisplayBoard(mine,ROW,COL);break;}}else{printf(the address is illegal\n);break;}}if(amountr*c-SET){printf(congratulaton! you make it\n);DisplayBoard(mine,ROW,COL);}}test.c#define_CRT_SECURE_NO_WARNINGS#includegame.hvoidmenu(){printf(- - - - - - - - - - - -\n);printf(- - - - 1.play - - - -\n);printf(- - - - 0.exit - - - -\n);printf(- - - - - - - - - - - -\n);}voidgame(){charmine[ROWS][COLS]{0};charshow[ROWS][COLS]{0};Initboard(show,ROWS,COLS,?);Initboard(mine,ROWS,COLS,0);DisplayBoard(show,ROW,COL);Setmine(mine,ROW,COL);DisplayBoard(mine,ROW,COL);Searchmine(show,mine,ROW,COL);}intmain(){intn0;srand((unsignedint)time(NULL));do{menu();printf(the number is: );scanf(%d,n);switch(n){case1:game();break;case0:printf(exit);break;default:printf(error);break;}}while(n);return0;}8. 总结本文用 C 语言实现了一个 9×9 的扫雷小游戏核心要点如下多文件结构game.h声明、game.c实现、test.c入口职责清晰。11×11 存 9×9多出一圈围墙避免统计周围雷数时数组越界。随机埋雷用rand()在非雷位置生成 10 颗雷。玩家操作输入坐标 → 合法性判断 → 踩雷判断 → 统计周围雷数 → 胜利判断循环直到输赢。踩坑提醒先SetMine埋雷再DisplayBoard打印顺序不能反。
返回列表