C语言实现经典扫雷:核心逻辑与完整代码解析
本文详细解析使用C语言开发经典9x9扫雷游戏的实现原理。通过双二维数组设计(mine与show),结合边界扩展技巧解决坐标越界问题。文章涵盖棋盘初始化、布雷算法及排查雷核心逻辑,提供模块化头文件与源文件代码结构,帮助开发者掌握基础C语言在小型控制台游戏中的综合应用。
结果与目标
构建一个运行于控制台的经典扫雷游戏,初始界面为10个地雷散布的9x9网格。玩家输入行列坐标进行排查,系统反馈该位置周围的雷数;踩中地雷则游戏结束并展示全图,排尽所有非雷区域则判定胜利。
准备条件
- 开发环境:支持标准C语言编译的环境(如GCC、Clang或Visual Studio)。
- 关键数据结构:采用两个字符型二维数组。一个是真实布雷板 (Mine Board),用于存储雷的位置信息;另一个是显示面板 (Show Board),用于向玩家展示排查状态。
- 边界优化:虽然逻辑上是9x9网格,但为了简化计算并避免坐标越界检查,内部定义大小为(ROWS x COLS),其中
ROWS = ROW + 2,COLS = COL + 2。
真实操作顺序
第1步:模块划分与宏定义
首先建立工程的文件结构,通常分为头文件(声明接口与常量)、功能实现文件(函数逻辑)和测试主文件(主循环与菜单)。以下是头文件 game.h 的定义,它集中管理了棋盘尺寸与函数原型:
#define _CRT_SECURE_NO_WARNINGS
#define ROW 9
#define COL 9
#define ROWS (ROW + 2)
#define COLS (COL + 2)
#define EASY_COUNT 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
// 函数声明
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 mine[ROWS][COLS], int row, int col);
int GetMineCount(char mine[ROWS][COLS], int x, int y);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
第2步:初始化棋盘
将两个棋盘分别填充不同的占位字符。Mine Board全部置为 '0'(表示无雷),Show Board全部置为 '*'(表示未排查)。注意传入的是扩大后的行列值。
// game.c
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;
}
}
}
第3步:布置地雷
利用随机数函数 rand() 生成棋盘内的横纵坐标。为了防止重复布雷,每次放置前需判断目标格子是否为 '0',若是则标记为 '1',直到布雷数量达到设定值。
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1; // 确保范围在 1~row
int y = rand() % col + 1; // 确保范围在 1~col
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
第4步:获取周围雷数
这是扫雷的核心算法。由于使用了扩大2格的数组,当玩家在坐标 (x, y) 处排查时,其周围8个格子的合法索引必定存在。只需将这8个格子的字符ASCII值相加,再减去8倍的 '0' 即可得到整数型的雷数。
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[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0');
}
第5步:实现排查交互逻辑
在 FindMine 函数中,通过循环不断接收用户输入的坐标。如果输入合法且未被炸死,则调用 GetMineCount 更新 Show Board 并打印;若输入错误或触发炸弹,则给出提示并跳出循环。获胜条件是累计排查的安全格子数等于总格子数减去雷数。
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0, y = 0, 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);
}
}
第6步:组装主控流程
在 test.c 中包含头文件,实现菜单显示与 srand 种子初始化,确保每次运行布雷都是随机的。
// test.c
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
SetMine(mine, ROW, COL);
DisplayBoard(show, ROW, COL); // 初始打印空白棋盘
FindMine(mine, show, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
// 此处应包含 menu 循环调用 logic
game();
return 0;
}
简要总结
本示例通过分离数据存储与显示界面的思路,巧妙地避开了复杂的内存管理与复杂的数据结构。利用C语言的指针与数组特性,实现了高效的周边检索,是初学者理解多维数组应用及游戏底层逻辑的经典范例。以上就是C语言实现经典扫雷小游戏的详细内容,更多关于C语言开发入门的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













