C语言二维数组实战:实现扫雷游戏
本文详细介绍如何利用C语言的二维数组在控制台中开发一款扫雷游戏。通过分析棋盘数据的存储结构、防越界处理技巧以及随机布雷算法,完整呈现从菜单设计到游戏核心逻辑的代码实现过程,适合初学者深入理解数组操作。
结果或目标
使用C语言编写一个基于控制台的扫雷程序。程序需具备以下功能: - 显示 9×9 的游戏界面,初始状态隐藏所有格子。 - 系统随机生成 10 个地雷位置。 - 用户输入坐标后,若未踩雷则显示该位置周围 8 个方向的雷数;若踩雷则游戏结束并展示全盘。 - 在未踩雷的情况下翻开所有非雷格子即视为胜利。
准备条件
为了实现该功能,需要构建三个核心文件:
- game.h:包含宏定义(行列数、雷数)、函数声明及必要的头文件引入。
- test.c:负责主循环、菜单打印及游戏流程调度。
- game.c:实现棋盘初始化、展示、布雷及找雷的核心逻辑。
第1步:定义数据结构与接口
目的:确立棋盘大小及安全边界的数学模型,提供标准化的函数接口。
操作:
在 game.h 中,由于需要统计边缘位置的周围雷数,直接访问相邻索引会导致数组越界。因此,实际使用的逻辑数组大小应为 ROWS x COLS(例如 11x11),而显示给用户的仅为中间部分(9x9)。
#ifndef __GAME_H__
#define __GAME_H__
#include <stdio.h>
#define ROW 9 // 显示行数
#define COL 9 // 显示列数
#define ROWS (ROW+2) // 实际行数,含安全边
#define COLS (COL+2) // 实际列数,含安全边
#define MINE_NUM 10 // 雷的数量
#include <stdlib.h>
#include <time.h>
// 函数原型声明
void InitBoard(char board[][COLS], int rows, int cols, char set);
void DisplayBoard(char board[][COLS], int row, int col);
void SetMine(char board[][COLS], int row, int col);
void FindMine(char mine[][COLS], char show[][COLS], int row, int col);
#endif
第2步:实现主控流程
目的:建立游戏入口,处理用户选择并调用游戏模块。
操作:
在 test.c 中,main 函数通过 do-while 循环维持程序运行。进入 game() 后,分配两个二维数组:
- Mine[ROWS][COLS]:后台数据,'0'表示无雷,'1'表示有雷。
- Show[ROWS][COLS]:前台数据,初始化全部为 '*' 以遮蔽信息。
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("********0.exit********\n");
printf("********1.play********\n");
printf("**********************\n");
}
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
// 1. 初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
// 2. 布置地雷
SetMine(mine, ROW, COL);
// 3. 开始游戏
FindMine(mine, show, ROW, COL);
}
int main()
{
int input = 0;
do {
menu();
printf("请选择:>>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入无效,请重新输入\n");
}
} while (input); // 输入为0时退出循环
return 0;
}
第3步:实现底层逻辑函数
目的:完成数据初始化、渲染、随机算法及核心判定逻辑。
操作:
在 game.c 中:
- 初始化:使用嵌套循环遍历数组赋予指定字符。
- 打印:
DisplayBoard仅输出 1 到ROW的范围,跳过第 0 行/列和最后新增的一行/列,保持界面整洁。 - 布雷:利用
srand(time(NULL))配合rand() % ROW + 1在有效范围内(避开边缘安全层)随机放置‘1’。 - 计算雷数:针对用户输入的坐标 (x, y),累加其周围 8 个邻接点的值。注意这里字符 '1' 的 ASCII 码为 49,减去 8 个 '0' (ASCII 48) 即可得到整数雷数。
- 交互循环:检查输入合法性,若无雷则更新显示矩阵并减少剩余空格计数;若遇雷则调用
DisplayBoard(mine)揭示真相。
第4步:关键排错与注意事项
问题1:数组越界风险
当用户输入边界坐标(如 1,1)时,程序需读取 (0,0) 到 (2,2) 的区域。若数组不扩充,索引 -1 将导致非法内存访问。解决方案是在物理内存中开辟多出一圈的“安全垫”,且将该圈初始化为 '0'。
问题2:字符与整数的转换
数组元素类型为 char,但统计雷数时需进行数学加法。示例代码中的写法 Mine[x-1][y-1] + ... - 8*'0' 是一种紧凑实现。需注意,如果某位置没有地雷是字符 '0',它参与加法会产生偏移量,必须统一减去基准值 '0' 才能还原为数值 0 或 1。
问题3:随机数重复
虽然简单的 rand() 可能产生重复坐标,但在本实现的简单版本中,重复覆盖只是导致该位置保持为 '1'。若要求严格保证 N 个雷且不重叠,需加入判断逻辑确保写入前该坐标未被占用。
简要总结
通过本案例,我们掌握了如何利用 C 语言二维数组处理带有“上下文依赖”的逻辑问题。特别是通过扩充数组维度来解决边界检测难题,以及灵活运用字符 ASCII 码进行轻量级数据存储的技巧。以上就是C语言利用二维数组实现扫雷游戏的详细内容,更多关于C语言数组进阶应用的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









