Let's Minesweeper(一起来扫雷) 自动扫雷程序

因为自己在玩一个Steam的多人扫雷游戏,最近又进一步学习了AI开发和测试,所以心血来潮做了一个自动扫雷程序。

难点不在于扫雷的算法,而是在这个超大的地图中通过什么样的拖动导航,精确找到未打开和已开格子的边缘地带。

好在最后终于也是成功开发,虽然导航还是存在一丝丝问题,但是完全可以可以用了。

项目地址: Github:letsminesweeper-bot

Let's Minesweeper 自动扫雷程序

这是一个完全离线运行的 Let's Minesweeper(一起来扫雷) 自动扫雷辅助程序。它通过读取当前游戏窗口截图,识别棋盘格、数字、地雷和特殊图形,再使用本地规则推理决定下一步操作。

程序只处理当前可见视口,不尝试读取或保存整张超大地图;当当前区域没有可执行操作时,会通过拖动鼠标探索相邻区域。

一、Let's Minesweeper 简单介绍

Let's Minesweeper(一起来扫雷) 是经典扫雷游戏的玩法。与普通固定大小的扫雷不同,本游戏地图非常大,需要按住鼠标左键拖动视口来查看不同区域。

游戏中主要存在以下类型的格子:

  • 已打开的空白格和数字格。
  • 未打开的灰色格。
  • 灰色背景上带有图形的已确认雷格。
  • 已打开的雷图形。
  • 黄色宝箱,包括打开和关闭两种外观,属于安全图形格。

二、特性

识别与推理

  • 自动定位当前窗口和可见棋盘网格。
  • 支持数字 1–6 的颜色识别。
  • 灰格上出现任何图形时,按游戏规则识别为地雷。
  • 支持黄色宝箱安全图形识别。
  • 支持“已经打开的雷”图形识别,并将其计入周围数字的雷数。
  • 使用基础扫雷规则和集合差分规则推导安全格与地雷。
  • 只执行确定性操作,不进行概率猜雷。

自动操作

  • 连续批量右键标旗,再连续批量左键开格。
  • 点击带有移动等待、按键保持和点击间隔,降低游戏漏收输入的概率。
  • 自动拖动地图,拖动后等待画面稳定并重新校准网格。
  • 允许从任意完整棋盘格开始拖动,拖动不会触发开格或踩雷。
  • 沿未开区域边缘顺时针探索,并尽量让已开格与未开格各占视口一半。
  • 当前视口清空时,先沿最后一次开格或标雷方向移动一次,再进入顺时针探索。
  • 识别异常时最多进行 8 次恢复拖动,恢复成功后继续运行。
  • 中央小块未开区域会被识别为孤岛并主动离开,避免围绕孤岛循环。
  • 沿前沿搜索超过一分钟没有找到可执行区域时,在战术台提示按 F8 停止并手动更换区域。

战术台

  • 观察窗口默认不勾选“每秒自动刷新”,需要时手动开启。
  • 自动运行时观察窗口保持打开。
  • F8 紧急停止。
  • 统计自动程序实际执行的累计开格和标旗数量。
  • 统计数据持久化到本地,重启程序或重新开始自动运行不会清零。
  • 提供“清除统计”按钮,只有手动点击后才会归零。
  • 截图识别在后台线程运行,减少窗口卡顿。
  • 小窗口布局下,开始、暂停、执行一批、重新读取和自动刷新选框仍保持可见。

三、运行要求

操作系统

  • Windows 10 或 Windows 11。
  • 屏幕必须处于解锁状态。
  • Let's Minesweeper 窗口需要保持可见;使用屏幕截图后备方式时不能被其他窗口遮挡。

软件环境

  • Python 3.10 或更高版本。
  • Python 标准库中的 Tkinter。
  • Pillow。
  • NumPy。
  • OpenCV-Python。

当前项目使用的导入依赖为:

1
2
3
Pillow
numpy
opencv-python

自动点击通常需要以管理员权限运行程序;如果出现 WinError 5,请使用“以管理员身份运行”。

四、软件说明

Github文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
lets-minesweeper-bot/
├─ app.py # 战术台界面和程序入口
├─ start-minesweeper-bot.cmd # Windows 启动脚本
├─ minesweeper/
│ ├─ automation.py # 自动扫雷、导航和恢复逻辑
│ ├─ capture.py # 游戏窗口截图
│ ├─ geometry.py # 棋盘网格校准
│ ├─ input_control.py # 鼠标点击和拖动
│ ├─ observer.py # 观察、稳定检测和图像覆层
│ ├─ recognition.py # 格子与特殊素材识别
│ ├─ solver.py # 局部扫雷约束求解
│ └─ statistics.py # 累计统计持久化
├─ tests/ # 离线测试
├─ samples/ # 本地截图和识别结果样本
├─ data/statistics.json # 累计开格/标旗数据
└─ shice.png # 游戏实际效果图

战术台示意

战术台左侧显示当前棋盘截图和识别覆层,右侧显示当前安全格、建议标雷、未开格、累计统计和操作按钮。

颜色含义:

  • 蓝框:确定安全,可以开格。
  • 红框:逻辑推导出的待标雷。
  • 绿框:游戏画面中已经带图形的确认雷。
  • 深红框:已经打开的雷,不会再次操作。
  • 金色框:黄色宝箱安全格。
  • 紫色框:无法识别的格子,程序不会根据它点击或标雷。

关键安全机制

  • 拖动过程中不把中间截图交给识别器。
  • 鼠标释放后连续确认画面稳定,才重新识别棋盘。
  • 点击批次结束后等待绿色浮动加分文字消失。
  • 识别矛盾或网格异常时不执行点击。
  • F8 可以中断点击批次和拖动过程。

五、使用方法

1. 准备游戏窗口

  1. 启动 Let's Minesweeper。
  2. 将窗口还原并保持棋盘可见。
  3. 如果使用自动点击,请确保游戏和自动程序使用相同的权限级别;推荐都以管理员权限运行。

2. 启动战术台

双击:

start-minesweeper-bot.cmd

也可以cd到项目目录运行:

1
python .\app.py

3. 观察模式

程序启动后会自动读取一次当前视口。此时默认不会每秒刷新,也不会点击游戏。

需要持续观察时,勾选“每秒自动刷新”。

4. 执行一批

点击“执行一批”时,程序只处理当前截图中已经推导出的这一批标旗和开格操作,完成后返回观察状态。

5. 开始自动运行

点击“开始自动运行”后,程序会等待一秒,然后循环执行:

1
2
3
4
5
6
读取当前视口
→ 批量标雷
→ 批量开格
→ 等待动画和加分文字消失
→ 重新识别
→ 必要时拖动探索

6. 暂停和紧急停止

  • 点击“暂停”:等待当前鼠标按键释放后停止。
  • 按 F8:立即停止后续操作;拖动过程中会释放左键。
  • 如果一分钟内一直找不到可开区域,按提示使用 F8 停止,再手动把游戏换到新的区域。

六、测试过程

项目使用本地截图样本和离线单元测试验证,不需要网络。

测试覆盖内容包括:

  • 普通灰格、数字、空白格识别。
  • 数字 6 识别。
  • 黄色宝箱和关闭宝箱识别。
  • 已打开雷识别及雷数约束。
  • 拖动动画期间不识别,稳定后重新校准。
  • 从任意格子开始拖动。
  • 顺时针未开区域边缘导航。
  • 开格/未开格比例救援。
  • 中央未开孤岛逃离。
  • 当前视口清空后的探索。
  • 异常识别后的最多 8 次恢复拖动。
  • 累计统计持久化和手动清零。
  • 战术台默认自动刷新状态。

运行测试:

1
python -m unittest discover -s .\tests -v

当前已验证全部 34 项测试通过,并完成 Python 编译检查:

1
python -m compileall -q .\app.py .\minesweeper .\tests

注意事项

  • 本程序只针对当前 Let's Minesweeper 的画面风格和交互方式进行识别。
  • 游戏窗口移动、缩放或遮挡后,程序需要重新读取并校准。
  • 遇到新图形素材时,建议先保持观察模式并采集截图,再加入识别规则。
  • 程序不会获取或保存整张超大地图,只保留当前视口和少量导航状态。
  1. Let's Minesweeper 自动扫雷程序
    1. 一、Let's Minesweeper 简单介绍
    2. 二、特性
      1. 识别与推理
      2. 自动操作
      3. 战术台
    3. 三、运行要求
      1. 操作系统
      2. 软件环境
    4. 四、软件说明
      1. Github文件结构
      2. 战术台示意
      3. 关键安全机制
    5. 五、使用方法
      1. 1. 准备游戏窗口
      2. 2. 启动战术台
      3. 3. 观察模式
      4. 4. 执行一批
      5. 5. 开始自动运行
      6. 6. 暂停和紧急停止
    6. 六、测试过程
    7. 注意事项