扫雷游戏项目
扫雷游戏 —— 项目设计报告一、游戏简介扫雷是一款经典的单人益智游戏最早在 Windows 3.1 时代随系统附带而广为人知。游戏的目标很简单在不踩到地雷的前提下翻开棋盘上所有安全格子。基本规则如下棋盘由若干格子组成其中随机分布着一定数量的地雷。玩家每次点击输入一个坐标翻开该格子。如果翻开的是地雷游戏结束。如果翻开的不是地雷格子上会显示该位置周围 8 个相邻格子中地雷的总数帮助玩家推断哪些格子是安全的。当所有非雷格子都被翻开时玩家获胜。本项目实现的是一个基于控制台的 9×9 扫雷共 10 颗地雷玩家通过输入坐标来进行游戏。二、项目文件结构本项目采用 C 语言编写源文件一共三个文件名职责game.h头文件定义宏常量、全局变量声明、函数声明game.c核心逻辑实现棋盘初始化、布雷、翻开格子、游戏主循环test.c测试与入口包含main函数、菜单界面、游戏启动流程三个文件各司其职test.c负责程序入口和交互入口game.c负责游戏算法和核心逻辑game.h则把二者连接起来。三、数据结构设计3.1 双棋盘设计扫雷的核心设计思路是“双棋盘”——程序内部维护两块同样大小的二维数组charmine_board[SIZE][SIZE];// 底层地雷盘存放真实地雷分布charshow_board[SIZE][SIZE];// 玩家显示盘存放玩家能看到的信息mine_board是上帝视角的地雷分布图只有程序自己读写玩家看不到。初始化时所有格子设为0布雷时将地雷位置设为*。show_board是玩家实际看到的界面初始化时所有格子设为*代表未翻开随着游戏推进逐步被替换为具体数字或空格。这种分离有两个好处一是保证玩家无法通过查看内存作弊二是逻辑上把真实状态和显示状态解耦代码更清晰。3.2 为什么用char而不是int棋盘元素使用char类型而不是int原因是棋盘需要显示字符未翻开用*地雷用*翻开后用数字字符0~8。使用char可以直接存字符打印时无需额外转换代码更简洁。数字的转换利用了 ASCII 码的特性show[x][y]cnt0;// cnt 是 0~8 的整数加上 0 后变成对应字符这是一个很常用的技巧——字符0的 ASCII 码是 481是 49以此类推所以整数加0就能得到对应字符。四、核心功能实现4.1 棋盘初始化voidinit_board(charboard[SIZE][SIZE],charval){memset(board,val,SIZE*SIZE);}使用memset将整个棋盘填充为指定字符。mine_board初始化为0无雷show_board初始化为*全未翻开。memset按字节操作对于char数组来说刚好适用。4.2 随机布雷voidset_mine(charmine[SIZE][SIZE]){srand((unsignedint)time(NULL));intcount0;while(countMINE_NUM){intxrand()%SIZE;intyrand()%SIZE;if(mine[x][y]!*){mine[x][y]*;count;}}}这段代码的逻辑很直观用srand(time(NULL))以当前时间作为随机种子保证每次运行游戏地雷分布不同。循环生成随机坐标(x, y)范围是0到SIZE-1。如果该位置还没有布雷不是*就放置一颗地雷然后count加一。重复直到布够MINE_NUM10 颗地雷。这里有一个细节如果随机到的位置已经有雷就跳过不计入 count所以虽然rand()可能重复但最终一定会布够 10 颗雷。不过在雷数接近格子总数时效率会变低但对于 9×9 只有 10 颗雷的场景来说完全不是问题。4.3 翻开格子周围雷数计算voidopen_cell(charmine[SIZE][SIZE],charshow[SIZE][SIZE],intx,inty){if(x0||xSIZE||y0||ySIZE)return;if(show[x][y]!*)return;intcnt0;for(intix-1;ix1;i){for(intjy-1;jy1;j){if(i0iSIZEj0jSIZE){if(mine[i][j]*)cnt;}}}show[x][y]cnt0;}这是扫雷中最关键的算法之一。它的任务是给定一个坐标(x, y)统计它周围 3×3 范围内含自身有多少颗地雷然后把结果显示到show_board上。具体步骤边界检查如果坐标越界直接返回。重复检查如果该格子已经翻开不是*也不需要处理。遍历相邻格子用两层循环遍历(x-1, y-1)到(x1, y1)的 9 个位置跳过越界的位置统计其中地雷的数量。写入结果cnt 0将数字转为字符写入show_board。需要指出的是当前实现只翻开单个格子。标准扫雷中如果翻开的格子周围雷数为 0应该自动展开周围所有相邻格子递归展开 / 泛洪填充。本项目暂未实现这个功能后续可以在open_cell中加入递归调用来完善。4.4 游戏主循环voidgame_main(charmine[SIZE][SIZE],charshow[SIZE][SIZE],intx,inty){intnum0;while(SIZE*SIZE-MINE_NUM-num){printf(请输入坐标);scanf(%d %d,x,y);if(show[x][y]!*){printf(已经验证过了,试试别的值吧\n);}if(mine[x][y]*){printf(踩雷游戏结束\n);print_board(mine);exit(1);}else{open_cell(mine_board,show,x,y);print_board(show);num;}}printf(------恭喜你过关-----\n);}游戏主循环的逻辑循环条件是SIZE * SIZE - MINE_NUM - num即总格子数减去雷数再减去已翻开数只要不为 0 就继续。每次循环接收玩家输入的坐标。如果该格子已经翻开提示玩家重新选择。如果踩到雷打印地雷盘并退出程序。如果是安全格子调用open_cell处理并打印显示盘已翻开数加一。当所有安全格子都被翻开打印过关信息。4.5 菜单与入口intmain(){intnum;do{menu();printf(请输入你的选择);scanf(%d,num);switch(num){case1:game();break;case0:break;}}while(num);return0;}main函数通过do-while循环实现了一个简单的菜单系统显示菜单 → 接收选择 → 执行对应操作 → 循环直到选择退出。进入游戏时调用game()函数完成棋盘初始化、布雷和游戏循环的全部流程。五、程序运行流程整体运行流程可以用下面的流程图来概括程序启动 │ ▼ 显示菜单1. 开始游戏 / 0. 退出 │ ▼ 玩家选择 │ ├── 选择 0 → 退出程序 │ └── 选择 1 → 进入 game() │ ▼ 初始化两个棋盘 mine_board 全 0show_board 全 * │ ▼ 打印初始 show_board │ ▼ 随机布雷set_mine │ ▼ 进入游戏循环game_main │ ▼ 玩家输入坐标 │ ├── 踩雷 → 打印 mine_board游戏结束 │ └── 安全 → open_cell 计算周围雷数 更新 show_board 并打印 检查是否全部翻开 │ ├── 未完成 → 继续输入 └── 全部翻开 → 恭喜过关六、代码中的不足与改进方向在阅读和分析代码的过程中也发现了一些可以改进的地方6.1 全局变量的使用game.h中声明了全局变量intx;inty;charmine_board[SIZE][SIZE];charshow_board[SIZE][SIZE];全局变量会导致多个函数共享同一份数据虽然在这个小程序中问题不大但从工程规范上来说建议把这些变量移到main或game函数内部通过参数传递给各子函数这样代码的可维护性和可测试性会更好。6.2 缺少坐标合法性校验玩家输入坐标后代码没有检查x和y是否在合法范围内0到SIZE-1。如果输入了超出范围的值直接访问数组会导致越界可能产生不可预期的行为。建议在接收输入后加入范围校验。6.3 翻开逻辑的局限当前open_cell只处理单个格子没有实现零值自动展开。标准扫雷中当翻开的格子周围雷数为 0 时应该自动递归翻开所有相邻格子直到遇到雷数不为 0 的边界。这个功能可以用递归或 BFS 实现能大幅提升游戏体验。6.4 缺少插旗功能标准扫雷允许玩家标记疑似地雷的位置插旗帮助记忆和推理。当前版本没有这个功能可以通过在show_board中使用特殊字符如F来表示旗帜标记。6.5 胜利判定的潜在问题胜利条件while (SIZE * SIZE - MINE_NUM - num)依赖num的计数。但当前代码中如果玩家输入了已经翻开的坐标num不会增加循环条件仍然正确。不过更健壮的做法是直接统计show_board中未翻开且非雷的格子数而不是依赖计数器。七、总结本项目实现了一个基础但功能完整的控制台扫雷游戏。通过双棋盘设计将底层数据与显示分离利用memset初始化、rand随机布雷、双重循环统计周围雷数等手段用不到 200 行代码完成了扫雷的核心逻辑。

相关新闻

校园网环境下Windows系统定时开机、自动登录与联网认证全自动方案

校园网环境下Windows系统定时开机、自动登录与联网认证全自动方案

1. 项目缘起:一个“懒人”的桌面自动化构想作为一名在校园里摸爬滚打多年的“老油条”,我每天到实验室的第一件事,就是按下电脑的电源键,然后等待漫长的启动过程。开机后,手动输入Windows密码登录,接着还得…

2026/8/2 17:52:26 阅读更多 →
Unity游戏Mod开发入门:基于BepInEx框架的完整实践指南

Unity游戏Mod开发入门:基于BepInEx框架的完整实践指南

1. 项目概述:从玩家到创造者的蜕变 如果你和我一样,是个深度游戏玩家,玩久了总会冒出一些“要是能这样改一下就好了”的念头。从《星露谷物语》里想随时换农场布局,到《幻兽帕鲁》里琢磨着加个新物种,这种“动手改造”…

2026/8/2 17:51:26 阅读更多 →
Flutter MethodChannel 深度指南:从原理到实战的跨平台通信

Flutter MethodChannel 深度指南:从原理到实战的跨平台通信

在实际的跨平台应用开发中,我们经常面临一个核心挑战:如何让一套代码逻辑,在 iOS 和 Android 两个生态系统中都能稳定、高效地运行。Flutter 的出现,通过自绘引擎和统一的 Dart 运行时,理论上解决了 UI 一致性的问题。…

2026/8/2 17:51:26 阅读更多 →

最新新闻

Unity游戏本地化实战:10分钟配置自动翻译插件,加速多语言开发

Unity游戏本地化实战:10分钟配置自动翻译插件,加速多语言开发

1. 项目概述:为什么需要自动翻译插件?如果你是一个独立游戏开发者,或者在一个小型团队里负责全球化发行,那么“本地化”这个词对你来说可能既熟悉又头疼。熟悉是因为你知道想让游戏卖到更多国家,翻译是必须的&#xff…

2026/8/2 19:13:09 阅读更多 →
Jenkins工具使用方法

Jenkins工具使用方法

0 Preface/Foreword1 Jenkins介绍1.1 基本概念Jenkins是一种提供持续集成软件(CI)的工具。该工具是web应用,由Java语言开发。

2026/8/2 19:13:09 阅读更多 →
113、LLC谐振变换器的参数扫描分析

113、LLC谐振变换器的参数扫描分析

113、LLC谐振变换器的参数扫描分析 从一次诡异的炸机说起 去年做一款300W的LED电源,LLC拓扑,设计时按经典K系数法算好了谐振参数。样机调试一切正常,效率93%,温升也OK。结果小批量产了50台,有3台在老化到第4小时突然炸管——MOSFET短路,保险丝烧得渣都不剩。 拆开分析…

2026/8/2 19:13:09 阅读更多 →
Unity直连西门子PLC:S7.NET实现工业数字孪生实时数据采集

Unity直连西门子PLC:S7.NET实现工业数字孪生实时数据采集

1. 项目概述:当Unity遇上西门子PLC如果你正在做工业数字孪生或者产线可视化,大概率会遇到一个核心难题:怎么让Unity这个游戏引擎,稳定、高效、实时地“读懂”产线上西门子PLC(可编程逻辑控制器)的数据&…

2026/8/2 19:13:09 阅读更多 →
UE4SS:虚幻引擎运行时脚本扩展与Lua模组开发实战指南

UE4SS:虚幻引擎运行时脚本扩展与Lua模组开发实战指南

1. 项目概述:为什么UE4SS是虚幻引擎开发者的“瑞士军刀”? 如果你是一名虚幻引擎(Unreal Engine, 简称UE)的开发者,无论是刚入门的新手,还是已经摸爬滚打多年的老手,可能都经历过这样…

2026/8/2 19:13:09 阅读更多 →
超级完整的 Git的下载、安装、配置与使用 以及命令

超级完整的 Git的下载、安装、配置与使用 以及命令

Git的下载、安装、配置与使用 以及命令 一、Git下载安装 1、访问git官方下载网址,点击这里,然后根据自己的电脑系统,下载对应的安装包: 2、在淘宝镜像网站 下载对应的安装包: 注: 如果由于官网下载速度过于缓慢,而且我还下载报错: 无法下载,需要授权。 可在git下载的…

2026/8/2 19:12:08 阅读更多 →

日新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/2 6:34:16 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/2 2:47:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/2 0:23:22 阅读更多 →