一、项目介绍
扫雷游戏的核心玩法是:玩家通过点击格子排查地雷,根据格子显示的数字判断周围雷的数量,最终在不触雷的情况下排查完所有安全区域即可获胜。
用C语言实现扫雷,能帮助我们深入理解二维数组操作、函数模块化设计、随机数生成等知识点,是从语法学习到项目实践的重要过渡。
二、实现思路
1.采用两个二维数组分别维护游戏状态:
- mine 数组:存储地雷的实际分布( '1' 表示有雷, '0' 表示无雷)。
- show 数组:展示给玩家的界面( '*' 表示未排查,数字表示周围雷的数量)。
为避免数组越界,我们将数组尺寸定义得比实际棋盘大2(如棋盘是9×9,数组定义为11×11),方便处理边缘格子的逻辑。
2. 功能模块划分
将游戏拆分为以下核心函数,实现高内聚、低耦合:
- InitBoard :初始化棋盘(地雷棋盘初始为 '0' ,显示棋盘初始为 '*' )。
- DisplayBoard :打印棋盘,展示游戏界面。
- SetMine :随机布置指定数量的地雷。
- GetMineCount :统计某个坐标周围的地雷数量。
- FindMine :处理玩家的排查操作,判断胜负或“炸死”。
三、代码详细解析
1. 头文件与宏定义( game.h )
先定义通用头文件、宏和函数声明,为后续功能实现做准备:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define EASY_COUNT 10 // 简单难度雷的数量
#define ROW 9 // 棋盘行数
#define COL 9 // 棋盘列数
#define ROWS ROW+2 // 实际数组行数(防止越界)
#define COLS COL+2 // 实际数组列数(防止越界)
// 初始化棋盘
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);
// 统计周围雷数(辅助函数)
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. 功能函数实现( game.c )
(1)初始化棋盘 InitBoard
通过双重循环将棋盘每个元素初始化为指定字符:
#include "game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
这里的set可以接收两种参数
(2)打印棋盘 DisplayBoard
打印时先输出列号,再逐行输出行号+棋盘内容,让玩家能清晰定位坐标:
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("--------扫雷游戏--------\n");
// 打印列号
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
// 打印每一行
for (i = 1; i <= row; i++)
{
printf("%d ", i); // 打印行号
int j = 0;
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
(3)布置雷 SetMine
利用 rand() 生成随机坐标,循环布置指定数量的雷(确保雷的位置不重复):
c
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
// 生成1~row、1~col的随机坐标
int x = rand() % row + 1;
int y = rand() % col + 1;
// 只有当前位置无雷时,才布置雷
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
(4)统计周围雷数 GetMineCount
这是一个巧妙的实现:利用 '1' 和 '0' 的ASCII码差异,直接对周围8个格子的字符求和,再减去8个 '0' 的ASCII码,即可得到雷的数量:
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');
}
当然我们还能用for循环来写:
static int Get_Mine_Count(char mine[ROWS][COLS], int x, int y)
{
int sum = 0;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
sum = sum + mine[x+i][y+j];
}
}
return sum - 9 * '0';
}
(5)排查雷 FindMine
处理玩家的排查逻辑,包括坐标合法性判断、触雷检测、胜负判断:
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int 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);
}
}
3. 主逻辑与菜单( test.c )
封装菜单和游戏主流程,通过 do-while 和 switch 实现交互:
#include "game.h"
void menu()
{
printf("********************\n");
printf("***** 1. play *****\n");
printf("***** 0. exit *****\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()
{
int input = 0;
srand((unsigned int)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); // input为0时退出循环
return 0;
}
四、运行效果演示
1. 启动程序后显示菜单,选择“1. play”进入游戏:
2. 展示初始棋盘,玩家可输入坐标排查:

请输入要排查的坐标:>
3. 若排查的格子无雷,将显示周围雷数(如输入 1 2 ,周围有2个雷):
请输入要排查的坐标:>

4. 若触雷,将展示所有雷的位置并提示失败;若排查完所有安全格子,提示“排雷成功”。
五、功能扩展建议
1. 难度选择:增加简单、中等、困难模式,调整 ROW 、 COL 和 EASY_COUNT (如中等难度设为16×16,雷数40)。
2. 标记雷功能:允许玩家用 '#' 标记疑似雷的位置,避免误触。
3. 界面优化:用颜色区分雷区(红色)、数字(蓝色),提升视觉体验。
4. 自动展开功能:当排查的格子周围无雷时,自动展开周围所有安全格子(类似Windows扫雷的连锁反应)。
六、总结
通过实现扫雷游戏,我们巩固了二维数组操作、函数模块化、随机数生成等C语言核心知识。希望本文的解析能帮你在C语言学习路上更进一步,也欢迎在评论区交流扩展功能的实现思路!
C语言实现扫雷游戏详解
1万+

被折叠的 条评论
为什么被折叠?



