[C语言]控制台扫雷游戏
用精简的代码回顾数组、函数和游戏逻辑的核心应用。还记得Windows自带的扫雷吗这次我们用C语言实现一个9x9的简易版适合用来巩固函数封装、二维数组和随机数等知识点。1. 整体思路扫雷的核心功能可以拆成几块打印菜单支持多次游玩用两个二维数组分别记录雷的分布mine和玩家看到的棋盘show随机布置雷玩家输入坐标排雷程序统计周围雷数并更新棋盘判断输赢为了让代码清晰我们将不同功能拆分到三个文件中main.c游戏主体控制流程game.c具体功能实现game.h函数声明和宏定义2. 处理数组边界问题我们玩的是9×9的棋盘但排雷时需要统计某个格子周围8个方向的雷数。如果直接用9×9数组边缘格子会数组越界。解决办法创建11×11的数组只使用中间9×9区域下标1~9边缘多出来的一圈作为缓冲区这样统计时就不会越界。在game.h头文件中定义宏方便后续修改#defineROW9#defineCOL9#defineROWSROW2#defineCOLSCOL2#defineMINE_COUNT103. 初始化棋盘mine数组0表示无雷1表示有雷show数组*表示未翻开用init_board函数初始化两个数组voidinit_board(charboard[ROWS][COLS],introws,intcols,charset){for(inti0;irows;i){for(intj0;jcols;j){board[i][j]set;}}}调用时分别传入0和*。4. 打印棋盘打印时加上行列号方便玩家输入坐标voidprint_board(charboard[ROWS][COLS],introw,intcol){printf( );for(inti1;icol;i){printf(%d ,i);}printf(\n);for(inti1;irow;i){printf(%d ,i);for(intj1;jcol;j){printf(%c ,board[i][j]);}printf(\n);}}5. 布置雷随机生成坐标1~9如果该位置还没放雷就放入1直到放满MINE_COUNT个。voidset_mines(charmine[ROWS][COLS],introw,intcol){intcount0;while(countMINE_COUNT){intxrand()%row1;intyrand()%col1;if(mine[x][y]0){mine[x][y]1;count;}}}6. 统计周围雷数输入坐标(x, y)统计它周围8个格子中雷的个数。利用字符1和0的ASCII差值将1 - 0转换为整数1累加即可。intget_mine_count(charmine[ROWS][COLS],intx,inty){return(mine[x-1][y-1]mine[x-1][y]mine[x-1][y1]mine[x][y-1]mine[x][y1]mine[x1][y-1]mine[x1][y]mine[x1][y1]-8*0);}7. 排雷逻辑玩家输入坐标后如果是雷 → 游戏结束打印雷阵如果不是雷 → 统计周围雷数更新到show棋盘每排一个安全格win计数加1直到排完所有非雷格子voidfind_mine(charmine[ROWS][COLS],charshow[ROWS][COLS],introw,intcol){//玩家输入坐标后// 如果是雷 → 游戏结束打印雷阵// 如果不是雷 → 统计周围雷数更新到 show 棋盘// 每排一个安全格win 计数加1直到排完所有非雷格子intwin0;while(winrow*col-MINE_COUNT){intx,y;printf(请输入坐标: );scanf(%d%d,x,y);if(x1||xrow||y1||ycol){printf(坐标非法重新输入\n);continue;}if(mine[x][y]1){printf(很遗憾你踩到雷了\n);print_board(mine,row,col);break;}elseif(show[x][y]*){// 防止重复翻开一个位置也能触发win避免只要一直翻开一个位置就能到达获胜了intcountget_mine_count(mine,x,y);show[x][y]count0;print_board(show,row,col);win;}}if(winrow*col-MINE_COUNT){printf(恭喜排雷成功\n);}}8. 主函数流程intmain(){intinput0;srand((unsignedint)time(NULL));do{printf(********************\n);printf(**** 1. 开始游戏 ***\n);printf(**** 0. 退出游戏 ***\n);printf(********************\n);printf(请选择: );scanf(%d,input);switch(input){case1:game();break;case0:printf(退出游戏\n);break;default:printf(选择错误请重新输入\n);break;}}while(input);return0;}game()函数中调用前面实现的功能voidgame(){charmine[ROWS][COLS];charshow[ROWS][COLS];init_board(mine,ROWS,COLS,0);init_board(show,ROWS,COLS,*);set_mines(mine,ROW,COL);print_board(show,ROW,COL);find_mine(mine,show,ROW,COL);}9. 调试技巧查看雷的布局可以在game()函数中打印雷的布局方便查看雷的布局print_board(mine,ROW,COL);验证是否能通关当翻开所有非雷坐标时才能通关9X9下要翻开71次我们可以适当的增加雷的数量来方便测试通关条件如修改雷数量的宏定义为#define MINE_COUNT 79这样只需要翻开两个坐标即可通关10. 可改进的方向棋盘展开经典扫雷中点到周围无雷的区域会自动展开一片。这个“递归展开”功能目前未实现可以作为一个进阶练习。标记功能支持玩家手动标记可疑格子。计时器增加游戏用时显示提升体验。11. 结语这个扫雷版本虽然简单但涵盖了C语言初阶的几个重要知识点二维数组、随机数生成、模块化编程、ASCII值转换等。你可以在此基础上尝试增加展开、计时等功能让游戏更完整。有什么问题或改进建议欢迎交流讨论。12. 源代码代码并不多可自行取用game.h//game.h#pragmaonce#define_CRT_SECURE_NO_WARNINGS1// 忽略 vs 对不安全的C函数的使用限制#defineROW9#defineCOL9#defineROWSROW2#defineCOLSCOL2#defineMINE_COUNT10//初始化棋盘voidinit_board(charboard[ROWS][COLS],introws,intcols,charset);//打印棋盘voidprint_board(charboard[ROWS][COLS],introw,intcol);//布置雷voidset_mines(charmine[ROWS][COLS],introw,intcol);//统计周围雷数intget_mine_count(charmine[ROWS][COLS],intx,inty);//排雷逻辑voidfind_mine(charmine[ROWS][COLS],charshow[ROWS][COLS],introw,intcol);game.c#includegame.h#includestdio.hvoidinit_board(charboard[ROWS][COLS],introws,intcols,charset){for(inti0;irows;i){for(intj0;jcols;j){board[i][j]set;}}}voidprint_board(charboard[ROWS][COLS],introw,intcol){//打印时加上行列号方便玩家输入坐标printf( );// 打印两个空格for(inti1;icol;i){// 打印列坐标 1 2 3 4 5 ...printf(%d ,i);}printf(\n);for(inti1;irow;i){printf(%d ,i);// 打印行坐标for(intj1;jcol;j){printf(%c ,board[i][j]);}printf(\n);}}voidset_mines(charmine[ROWS][COLS],introw,intcol){// 随机生成坐标1~9如果该位置还没放雷就放入 1直到放满 MINE_COUNT 个。intcount0;while(countMINE_COUNT){intxrand()%row1;intyrand()%col1;if(mine[x][y]0){// 生成的随机数 x 和 y 可能在之前就出现过了防止重复在一个位置放雷mine[x][y]1;count;}}}intget_mine_count(charmine[ROWS][COLS],intx,inty){// 输入坐标 (x, y)统计它周围8个格子中雷的个数。//利用字符 1 和 0 的ASCII差值将 1 - 0 转换为整数1累加即可。//在 C 语言中当 char、short 或位域参与算术运算时它们会被提升为 int 类型如果 int 能表示原类型的所有值否则提升为 unsigned int。return(mine[x-1][y-1]mine[x-1][y]mine[x-1][y1]mine[x][y-1]mine[x][y1]mine[x1][y-1]mine[x1][y]mine[x1][y1]-8*0);}voidfind_mine(charmine[ROWS][COLS],charshow[ROWS][COLS],introw,intcol){//玩家输入坐标后// 如果是雷 → 游戏结束打印雷阵// 如果不是雷 → 统计周围雷数更新到 show 棋盘// 每排一个安全格win 计数加1直到排完所有非雷格子intwin0;while(winrow*col-MINE_COUNT){intx,y;printf(请输入坐标: );scanf(%d%d,x,y);if(x1||xrow||y1||ycol){printf(坐标非法重新输入\n);continue;}if(mine[x][y]1){printf(很遗憾你踩到雷了\n);print_board(mine,row,col);break;}elseif(show[x][y]*){// 防止重复翻开一个位置也能触发win避免只要一直翻开一个位置就能到达获胜了intcountget_mine_count(mine,x,y);show[x][y]count0;print_board(show,row,col);win;}}if(winrow*col-MINE_COUNT){printf(恭喜排雷成功\n);}}main.c#includestdlib.h#includegame.hvoidgame(){charmine[ROWS][COLS];charshow[ROWS][COLS];init_board(mine,ROWS,COLS,0);init_board(show,ROWS,COLS,*);set_mines(mine,ROW,COL);print_board(show,ROW,COL);find_mine(mine,show,ROW,COL);}intmain(){intinput0;srand((unsignedint)time(NULL));do{printf(********************\n);printf(**** 1. 开始游戏 ***\n);printf(**** 0. 退出游戏 ***\n);printf(********************\n);printf(请选择: );scanf(%d,input);switch(input){case1:game();break;case0:printf(退出游戏\n);break;default:printf(选择错误请重新输入\n);break;}}while(input);return0;}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2472952.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!