基于python的扫雷 – 苏的小站

成功 用自己的方式度过一生

个人作品展示

苏的小站 · 科技爱好者

爱好者

面试作品 简历展示、项目简介、技术栈
风格 现代、简约

基于python的扫雷

注:这是本人做的小游戏,目的是帮助人学习

项目地址: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 标准库组件,无需额外安装依赖。

总结:具体可以看我项目仓库。



发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注