用C语言实现简单扫雷游戏
基于C语言实现一个命令行扫雷程序,涵盖菜单交互、随机布雷、坐标校验及递归展开等功能。
结果与目标
本文旨在提供一个结构清晰的C语言扫雷示例。最终实现的程序包含初始菜单、9x9的游戏棋盘、10个随机分布的地雷。核心亮点在于当点击无雷区域时,程序能递归自动计算并展示周围所有安全格子的信息,直至边界出现数字提示。
准备条件与文件架构
本项目将代码拆分为三个核心文件,以实现模块化设计:
game.h:存放头文件引用、宏定义(如行列数、地雷数)及函数声明。test.c:作为主入口,存放main()和menu()函数,负责程序流程控制。game.c:存储具体的业务逻辑,包括初始化、布雷、打印及扫雷算法。
运行环境需支持标准C库函数,建议使用 srand(time(NULL)) 生成随机种子。
真实操作顺序
第1步:初始化界面与全局宏
目的:定义棋盘尺寸、地雷数量及必要的标准库依赖。
操作:在 game.h 中定义以下常量,用于后续内存分配与循环控制:
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
// 预留一圈,防止越界访问
#define ROWS 11
#define COLS 11
#define EASY_COUNT 10 // 地雷数量
void InitBoard(char board[ROWS][COLS],int row,int col,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);
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
第2步:构建主菜单与入口逻辑
目的:提供玩家选择开始或退出的交互入口。
操作:在 test.c 中使用 do-while 循环维持游戏进程,通过 switch 分发指令。
int main()
{
int input;
srand((unsigned)time(NULL));
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;
}
第3步:设置棋盘并初始化
目的:区分“地雷信息”与“玩家视野”。地雷图全设为 '0',显示图全设为 '*'。
操作:InitBoard 函数遍历数组,将指定字符填入对应位置。
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
第4步:随机布置地雷
目的:在游戏区域内生成指定数量的地雷,且不能重复。
操作:使用 rand() % row + 1 生成 1~9 的随机坐标,判断该位置是否为 '1'(已有雷),若为空则标记为 '1' 并减少计数。
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] != '1')
{
board[x][y] = '1';
count--;
}
}
}
第5步:打印棋盘样式
目的:为玩家提供带行列标号的直观界面。
操作:打印顶部行号标尺,逐行输出数组内容,每行结束后换行。注意仅遍历有效区域(1~9)。
第6步:执行扫雷逻辑
目的:接收玩家输入,判断是否踩雷,并更新界面。
操作:
- 获取坐标
x, y并验证是否在 1~9 范围内。 - 若
mine[x][y] == '1',游戏结束并揭示所有地雷。 - 若无雷,调用
Unfold函数展开区域。
第7步:递归展开空白区域
目的:实现扫雷核心机制——翻开一个零雷格子后,自动翻开周围相邻的格子,直到遇到数字边界。
图片展示展开效果:
四周无地雷继续向外展开,直到出现地雷信息
操作:
- 核心逻辑:计算当前坐标周围8格的雷数。如果结果为0,将该格设为空格 ' ',并对周围8个方向进行递归调用。
- 防越界与防重:每次递归前检查坐标合法性以及是否已被访问过(即
show[x][y]仍为 '*')。 - 返回值处理:传入
win指针记录已翻开的安全格子数,当总数达到目标时判定胜利。
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int *win)
{
if (show[x][y] == '*')
{
*win += 1;
int count = GetMineCount(mine, x, y);
if (count == 0)
{
show[x][y] = ' ';
// 对周围8个方向进行递归
if(x-1>=1 && x-1<=9 && y-1>=1 && y-1<=9) Unfold(mine, show, x - 1, y - 1, win);
if(x-1>=1 && x-1<=9 && y>=1 && y<=9) Unfold(mine, show, x - 1, y, win);
// ...此处省略其他六个方向的边界判断代码,逻辑同上...
if(x+1>=1 && x+1<=9 && y+1>=1 && y+1<=9) Unfold(mine, show, x + 1, y + 1, win);
}
else
{
show[x][y] = count + '0';
return;
}
}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +
mine[x][y - 1] + mine[x][y + 1] +
mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
}
第8步:整合与验证
目的:确保所有模块无缝衔接,修正 FindMine 中的逻辑以配合递归。
操作:在 game.c 中统一整理各函数实现,并在 FindMine 中移除旧的逐个计数的循环逻辑,替换为对 Unfold 的单次调用。验证输入非法坐标时的异常处理能力。
完成判断与排错
成功标志:程序启动后输入1进入游戏,能够准确展开大片空白区域而不引发崩溃;踩中任意地雷显示失败面板;翻开所有非雷区域显示胜利信息。
常见问题排查:
- 栈溢出:如果递归深度过大(极罕见情况),可能导致栈空间不足。优化方法是将递归改为迭代(使用队列)。
- 数组越界:由于定义了 11x11 的数组,只需确保逻辑上只操作 1~9 的区域即可避开边缘越界风险。
- 雷数重复:确保
SetMine中的if判断严格。
简要总结
本教程通过C语言实现了一个功能完整的命令行扫雷游戏。从基础的菜单循环到核心的二维数组操作,再到运用递归解决大面积连开难题,展示了编程思维在实际小游戏构建中的应用。以上就是关于用C语言实现简单扫雷游戏的详细内容,更多关于C语言小游戏开发的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









