语言项目实战:扫雷游戏完整实现(数组+函数综合应用) 学完了数组和函数是时候做一个综合项目来练手了本篇博客将带你从零实现经典的扫雷游戏涵盖游戏分析、数据结构设计、多文件组织、完整代码以及优化扩展让你真正掌握C语言模块化编程的精髓。 目录项目需求分析数据结构设计文件结构规划核心功能实现4.1 初始化棋盘4.2 打印棋盘4.3 布置雷4.4 统计周围雷数4.5 排查雷完整代码多文件游戏效果演示优化与扩展总结1. 项目需求分析扫雷是一款经典的单人益智游戏我们的目标是在控制台实现一个简化版。功能要求9×9 的棋盘随机布置10 个雷。玩家输入坐标排查雷。若踩雷游戏结束并显示所有雷的位置。若未踩雷显示该位置周围 8 个格子中雷的个数。当所有非雷格子被排查完玩家胜利。交互界面示例text扫雷游戏 0 1 2 3 4 5 6 7 8 9 1 * * * * * * * * * * 2 * * * * * * * * * * ... 请输入要排查的坐标 2 52. 数据结构设计2.1 棋盘大小我们使用9×9的有效区域但为了防止边界越界统计边缘格子周围雷数时会访问到数组外我们实际创建11×11的数组只在中间的 9×9 内布置雷和排查。2.2 两个数组各司其职mine[ROWS][COLS]存放雷的分布1表示雷0表示非雷初始全为0。show[ROWS][COLS]存放玩家看到的信息*表示未排查数字表示周围雷数初始全为*。这样设计清晰分离了“内部数据”和“显示界面”互不干扰。宏定义c#define ROW 9 #define COL 9 #define ROWS ROW2 #define COLS COL2 #define EASY_COUNT 10 // 雷的数量3. 文件结构规划采用多文件组织便于维护和扩展。文件作用game.h头文件宏定义、函数声明、库包含game.c函数实现初始化、打印、布置雷、统计、排查test.c主程序菜单、游戏流程控制4. 核心功能实现4.1 初始化棋盘将二维数组所有元素设为指定字符0或*。cvoid InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { for (int i 0; i rows; i) { for (int j 0; j cols; j) { board[i][j] set; } } }4.2 打印棋盘只打印有效区域1~ROW 行1~COL 列并加上行列号方便玩家输入。cvoid 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); } }4.3 布置雷使用rand()生成 1~ROW 和 1~COL 的随机坐标如果该位置还未布置雷0则置为1直到布置够EASY_COUNT个。cvoid SetMine(char board[ROWS][COLS], int row, int col) { int count EASY_COUNT; while (count) { int x rand() % row 1; int y rand() % col 1; if (board[x][y] 0) { board[x][y] 1; count--; } } }4.4 统计周围雷数给定坐标(x, y)返回周围 8 个格子中1的个数。巧妙方法将 8 个字符相加减去8 * 0得到整数雷数。cint GetMineCount(char mine[ROWS][COLS], int x, int y) { return (mine[x-1][y] mine[x-1][y-1] mine[x][y-1] mine[x1][y-1] mine[x1][y] mine[x1][y1] mine[x][y1] mine[x-1][y1] - 8 * 0); }4.5 排查雷玩家循环输入坐标检查合法性若坐标非法提示重新输入。若踩雷mine[x][y] 1游戏结束并显示雷阵。若安全计算周围雷数并更新show数组同时增加已排查计数win。当win达到总格子数减去雷数时玩家胜利。cvoid FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x 0, y 0; int win 0; while (win row * col - EASY_COUNT) { printf(请输入要排查的坐标); scanf(%d %d, x, y); if (x 1 x row y 1 y col) { if (mine[x][y] 1) { printf(很遗憾你被炸死了\n); DisplayBoard(mine, row, col); break; } else { int count GetMineCount(mine, x, y); show[x][y] count 0; // 数字转字符 DisplayBoard(show, row, col); win; } } else { printf(坐标非法请重新输入\n); } } if (win row * col - EASY_COUNT) { printf(恭喜你排雷成功\n); DisplayBoard(mine, row, col); } }5. 完整代码多文件game.hc#pragma once #include stdio.h #include stdlib.h #include time.h #define ROW 9 #define COL 9 #define ROWS ROW 2 #define COLS COL 2 #define EASY_COUNT 10 // 函数声明 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set); void DisplayBoard(char board[ROWS][COLS], int row, int col); void SetMine(char board[ROWS][COLS], int row, int col); void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);game.cc#include game.h void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { for (int i 0; i rows; i) { for (int j 0; j cols; j) { board[i][j] set; } } } void DisplayBoard(char board[ROWS][COLS], int row, int col) { printf( ); 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); } } void SetMine(char board[ROWS][COLS], int row, int col) { int count EASY_COUNT; while (count) { int x rand() % row 1; int y rand() % col 1; if (board[x][y] 0) { board[x][y] 1; count--; } } } int GetMineCount(char mine[ROWS][COLS], int x, int y) { return (mine[x-1][y] mine[x-1][y-1] mine[x][y-1] mine[x1][y-1] mine[x1][y] mine[x1][y1] mine[x][y1] mine[x-1][y1] - 8 * 0); } void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x 0, y 0; int win 0; while (win row * col - EASY_COUNT) { printf(请输入要排查的坐标行 列); scanf(%d %d, x, y); if (x 1 x row y 1 y col) { if (mine[x][y] 1) { printf( 很遗憾你被炸死了\n); DisplayBoard(mine, row, col); break; } else { int count GetMineCount(mine, x, y); show[x][y] count 0; DisplayBoard(show, row, col); win; } } else { printf(⚠️ 坐标非法请重新输入范围1~%d\n, row); } } if (win row * col - EASY_COUNT) { printf( 恭喜你排雷成功\n); DisplayBoard(mine, row, col); } }test.cc#include game.h void menu() { printf(************************\n); printf(***** 1. 开始游戏 ****\n); printf(***** 0. 退出游戏 ****\n); printf(************************\n); } void game() { char mine[ROWS][COLS]; char show[ROWS][COLS]; // 初始化 InitBoard(mine, ROWS, COLS, 0); InitBoard(show, ROWS, COLS, *); // 打印初始界面 DisplayBoard(show, ROW, COL); // 布置雷 SetMine(mine, ROW, COL); // 排查雷 FindMine(mine, show, ROW, COL); } int main() { srand((unsigned int)time(NULL)); 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); return 0; }6. 游戏效果演示初始界面text0 1 2 3 4 5 6 7 8 9 1 * * * * * * * * * * 2 * * * * * * * * * * ...排查中输入坐标2 5若安全则显示该位置周围雷数如2。踩雷失败text 很遗憾你被炸死了 显示雷阵胜利text 恭喜你排雷成功7. 优化与扩展基础版本实现了核心逻辑但仍有很大提升空间。下面列举几个优化方向并给出部分实现思路。7.1 展开无雷区域递归当排查位置周围雷数为 0 时自动展开周围 8 个格子类似 Windows 扫雷的“展开”功能。实现思路在FindMine中若count 0递归调用自身处理相邻格子需注意防止死循环用show[x][y] ! *判断已处理。cvoid Expand(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int* pwin) { if (x 1 || x ROW || y 1 || y COL || show[x][y] ! *) return; int count GetMineCount(mine, x, y); show[x][y] count 0; (*pwin); if (count 0) { for (int i x-1; i x1; i) { for (int j y-1; j y1; j) { if (i x j y) continue; Expand(mine, show, i, j, pwin); } } } }7.2 标记雷右键功能玩家可以标记疑似雷的位置用!或其他符号防止误排。实现增加一个菜单选项让玩家选择“排查”或“标记/取消标记”。7.3 难度选择通过宏或变量控制棋盘大小和雷数如简单9×910雷中等16×1640雷困难30×1699雷可将这些参数作为函数参数传递。7.4 计时功能使用time()函数在游戏开始时记录时间结束时计算耗时并显示。7.5 界面美化使用清屏system(cls)和颜色控制Windows 下可用SetConsoleTextAttribute提升用户体验。8. 总结通过扫雷项目我们综合运用了数组二维数组存储棋盘数据。函数模块化设计各司其职。多文件头文件与源文件分离工程化开发。随机数rand()srand(time())布置雷。逻辑思维边界处理、字符与数字转换、递归展开等。这个项目虽然不大但涵盖了C语言核心知识点是检验学习成果的绝佳练习。建议读者先自己尝试实现再对照代码优化并挑战扩展功能。下一篇预告VS调试技巧——高效定位Bug让编程更轻松