注:这是本人做的小游戏,目的是帮助人学习
项目地址:suyihang15/minesweeper_game: 基于python的扫雷小游戏
成品下载:https://github.com/suyihang15/minesweeper_game/releases/download/1.0.0/minesweeper.exe
扫雷游戏 — 原理与实现
一、游戏概述
扫雷(Minesweeper)是一款经典的单人逻辑推理游戏,核心玩法是在一个隐藏地雷的矩形网格中,通过翻开格子解读数字线索,安全地定位所有地雷。本实现使用 **Python + tkinter** 完整还原经典扫雷的核心机制,并加入了 Chord 双击展开、胜利烟花动画等进阶体验。
二、操作说明
| 左键点击(未翻开) | 翻开格子 |
| 左键点击(已插旗) | 快速解旗,无需右键循环 |
| 左键点击(已翻开数字格) | Chord 双击展开 |
| 右键点击 | 循环切换:无标记 → 旗子 → 问号 |
| 右键点击(游戏开始前) | 允许提前插旗标记(与标准扫雷一致) |
翻开格子显示 数字 (1~8):表示该格周围 8 个相邻格子中的地雷数。
翻开格子为 **空格**(雷数为 0):自动递归展开连通空白区域。
翻开格子为 **地雷**:游戏失败,展示所有地雷位置。
旗子和问号标记的格子受到保护,不会被左键意外翻开。
胜利条件
所有非雷格子均被翻开即获胜,无需给每一颗雷插旗。胜利时触发彩色烟花动画。
三、数据结构
board[r][c] : int -1 = 地雷, 0~8 = 周围雷数
revealed[r][c] : bool 是否已翻开
flagged[r][c] : int 0 = 无标记, 1 = 旗子, 2 = 问号
buttons[r][c] : Button 对应的 tkinter 按钮对象引用
所有数据以二维数组存储,索引 `(r, c)` 对应棋盘坐标。
四、核心算法
4.1 首次点击安全保障
首次点击前地雷尚未布置。玩家点击后:
1. 将该位置及其 3×3 邻域(共最多 9 格)标记为安全区;
2. 从安全区外的所有格子中随机选取 `mines_count` 个放置地雷;
3. 遍历棋盘,计算每个非雷格的周围地雷数。
- safe_cells = {(safe_row + dr, safe_col + dc) for dr in (-1,0,1) for dc in (-1,0,1)}
- candidates = [pos for pos in all_cells if pos not in safe_cells]
- mine_positions = random.sample(candidates, mines_count)
复杂度:O(rows × cols),在布雷阶段一次性完成。
4.2 周围雷数统计
对每个非雷格子,统计其 8 个方向上的地雷数量:
[NW] [N ] [NE]
[W ] [ X] [E ]
[SW] [S ] [SE]
count = 每个相邻位置是否为地雷(布尔累加)
该值直接决定了格子翻开后显示的数字或空格。
4.3 空格自动展开(Flood Fill)
翻开雷数为 0 的格子(空格)时,使用深度优先搜索(DFS)递归展开:
reveal_cell(r, c):
if revealed[r][c] or 有旗子/问号标记 → 停止
标记 (r, c) 为已翻开
if board[r][c] > 0: 显示数字,停止
if board[r][c] == 0: 对 8 个邻居递归调用 reveal_cell
点击一个空格即可让整个连通空白区域一次性展开,并在边界处停下显示数字。
4.4 Chord 双击展开
在已翻开的数字格上左键点击触发,是进阶玩家的高效操作:
do_chord(r, c):
number = board[r][c]
flag_count = 统计周围旗子数
if flag_count != number:
数字格金色闪烁 250ms(视觉反馈)
return
if 周围有未保护的地雷:
游戏失败,直接展示所有雷(不翻开任何中间格)
return
翻开周围所有安全格子
原理:当周围插的旗子数恰好等于该格数字时,意味着剩余未翻开邻居必然是安全的。Chord 一键翻开它们,大幅提升操作效率。若旗子数与数字不匹配,数字格短暂变为金黄色作为反馈;若旗子标错且翻开的是地雷,直接判定失败。
4.5 胜利判定
遍历整个棋盘,确认没有非雷格子处于未翻开状态:
check_win():
for each cell:
if board[r][c] != -1 and not revealed[r][c]:
return False
return True
五、烟花庆祝动画
胜利后触发彩色粒子烟花:
1. Canvas 覆盖层 — 在窗口上方创建透明 tkinter Canvas 画布
2. 多轮爆发 — 分别在 100ms、600ms、1100ms 产生三轮随机位置爆发(4+3+3 次)
3. 粒子物理 — 每次爆发约 30 个粒子,具有随机方向初速度,受重力(+0.25/帧)和空气阻力(×0.94/帧)影响
4. 淡出效果 — 粒子生命周期内按比例缩小至消失
5. 自动清理 — 所有粒子消失后自动销毁 Canvas
六、难度配置
| 难度 | 棋盘大小 | 雷数 | 雷密度 |
| 初级 | 9×9 | 10 | ~12.3% |
| 中级 | 16×16 | 40 | ~15.6% |
| 高级 | 16×30 | 99 | ~20.6% |
七、运行方式
python minesweeper.py
环境要求:Python 3.x。tkinter 是 Python 标准库组件,无需额外安装依赖。
总结:具体可以看我项目仓库。