happy-birds-cracker/README.md

152 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# happy-birds-cracker
基于 [MaaFramework](https://github.com/MaaXYZ/MaaFramework) 的**滑动三消(消消乐)自动求解器**。
MaaFramework 负责 **截屏 + 图像识别 + ADB 滑动控制**;本项目负责把画面变成棋盘模型、
计算最优一步、再把交换映射回屏幕滑动。
> ⚠️ 仅供学习与离线/单机研究。请遵守目标游戏的服务条款,线上对战/带反作弊的游戏请勿使用。
## 设计要点
- **网格动态可变,恒为矩形**:尺寸由 `GridConfig(rows, cols)` 决定,换关卡只需改行列数
(或在识别阶段探测后填入),核心算法与尺寸无关。
- **三种块类型**`CellKind`,为后续编程预留 `meta` 扩展字段):
- `NORMAL` 正常块:可交换,带 `color`
- `BRICK` 砖块:不可移动的障碍,会打断连线。
- `EMPTY` 空块/空洞:无方块,会打断连线。
## 目录结构
```
src/hbc/
board.py 棋盘数据模型Cell / CellKind / Board动态矩形
solver.py 三消求解:找匹配 + 遍历相邻交换搜索最优解
config.py GridConfig像素<->格子映射,可存 JSON/ 模板比对参数
state.py GameState识别与动作之间共享 Board / 当前关卡
templates.py 模板图像库:子图比对识别,支持多种墙(推荐识别方式)
recognizer.py 截图 -> Board可插拔分类器模板/颜色 + MaaFw 识别桩)
level.py 关卡识别OCR 标题"关卡一" -> 关卡号 -> 载入对应布局
calibrate.py 标定工具:框选棋盘生成布局、预览、导出格子图(窗口自适应屏幕)
actuator.py Swap -> ADB 滑动(纯函数 + MaaFw 自定义动作 SwapAction
main.py 连接设备、加载资源、注册自定义模块、循环运行(支持 --dry-run
resource/
pipeline/
pipeline.json MaaFramework 低代码流程:识别棋盘 -> 执行交换 -> 循环
templates/ 模板库你标定后放入normal/ wall/ empty/
layouts/ 各关布局level1.json level2.json ...(你标定后生成)
tests/
test_solver.py 求解器与模型测试
test_recognition.py 模板识别 + 标定 + 多关卡布局测试(合成图,无需真机)
test_level.py 关卡号 OCR 文本解析测试
```
## 如何识别棋盘
本游戏网格逐关变大且含空格。布局**按关卡分文件**存在 `layouts/` 文件夹下
`layouts/level1.json`、`layouts/level2.json` ...),每关只需标定一次。
标定窗口会**自动缩放适配屏幕**(截图比屏幕大也能完整框选)。
```bash
# 1) 框出棋盘 + 填该关行列数 -> 写入 layouts/level1.json弹窗自动缩放鼠标拖框回车确认
python -m hbc.calibrate roi --image src-images/level1.jpg --level 1 --rows 5 --cols 5
# 窗口仍太大可调上限:--max-display 700
# 无 GUI / 想直接给坐标:--box x,y,w,h按原图像素
# 2) 叠加网格预览,确认每个格子对齐(绿框=棋盘,橙线=网格,红点=格子中心)
python -m hbc.calibrate preview --image src-images/level1.jpg --level 1 --out preview_level1.png
# 3) 把每个格子切成小图,导出到 cells/,再人工分类到模板库
python -m hbc.calibrate export --image src-images/level1.jpg --level 1 --out cells/
# 后续关卡同理,换 --level 2/3/... 和对应行列数即可
python -m hbc.calibrate roi --image src-images/level2.jpg --level 2 --rows 6 --cols 6
```
运行时用 `--level` 选择关卡:`python -m hbc.main --level 1`。
### 对齐技巧(棋盘四周有 padding
均匀切分基于你框的矩形,所以框要贴着**棋子区域**而不是外层面板:
从**左上角棋子的左上角**拖到**右下角棋子的右下角**(把面板留白排除在外),
再用 `preview` 看红点是否落在每个棋子中心,不对就重框。反复"框 → 预览"几次即可对齐。
### 运行时自动识别当前是第几关OCR
游戏顶部写着"关卡一"MaaFramework **自带 OCR**PaddleOCR 的 ONNX 模型),运行时
可直接识别,**不用你预先截图**。流程:标定一次标题区域 ROI -> `LevelRecognition`
`level.py`OCR 标题 -> `parse_cn_level` 解析成关卡号 -> 自动载入 `layouts/level{N}.json`
若你的 MaaFw 资源里没带 OCR 模型,去掉该节点、改用 `--level` 手动指定即可。
把导出的小图按类别放进模板库(文件名即类别):
```
templates/
normal/red.png green.png blue.png ... 每种正常块一张(文件名->稳定颜色 id
wall/stone.png ice.png chain.png ... 墙可以有多种,每种一张
empty/hole.png 空块/空洞
```
### 为什么用模板比对而不是纯颜色
MaaFramework 的颜色识别对光照/特效/相近色容易误判。本项目识别走**子图比对**
把每个格子缩放后与模板逐像素比相似度,取最高分。相似度对**颜色和形状都敏感**
(不像 `TM_CCOEFF_NORMED` 会忽略颜色),更适合消消乐。仍保留 `ColorClassifier` 作为兜底。
### 冰块 = 低置信度即判为墙
本游戏除正常生物/空格外只有一种特殊方块——**冰块**(冰下隐约有正常图案)。冰下图案
模糊,模板匹配置信度天然偏低,因此采用一条简单规则:**凡是匹配不够自信的格子,
一律判为冰墙**`cell.meta['wall']='ice'`,不可交换、打断连线)。
冰墙不会被直接交换,但当它旁边发生消除时,游戏里冰会化掉、露出正常生物,下一帧重新
识别就变回可用的普通块,于是自然推进。这是有意的取舍:牺牲对"未登记新方块"的健壮性,
换取对冰块的零配置支持。阈值在 `TemplateMatchConfig.score_threshold` /
`empty_min_score`,需要时可调。
### 新增正常生物
后续关卡出现新动物时,把它的一张干净小图放进 `templates/normal/<名字>.png` 即可
(每个不同文件名 = 一个独立可消除类型;如灰色魟鱼 `stingray.png` 与青色水母
`jellyfish.png` 是两种)。用 `hbc.calibrate export` 可批量导出格子图来挑样本。
### 多种墙(可选)
若以后遇到别的固定障碍,可在 `templates/wall/` 放多张墙图(石墙、锁链……),
它们都识别为 `CellKind.BRICK`,种类记在 `cell.meta['wall']`,便于针对性写逻辑。
## 数据流
```
MaaFramework 截屏
-> BoardRecognitionrecognizer: 按网格切格、判颜色/砖块/空块 -> Board
-> SwapActionactuator: Solver.find_best_swap(board) -> 最优 Swap
-> 通过控制器 post_swipe 滑动
-> 循环
```
求解与控制是解耦的:`board.py` + `solver.py` 完全不依赖 MaaFramework / 真机,可独立测试。
## 快速开始
```bash
# 安装为可编辑包:之后在项目根目录任何位置都能用 hbc无需设置 PYTHONPATH 或 cd src
pip install -e .
# 离线验证求解器(不需要设备)
python -m pytest tests/ -q
# 连接设备后运行(需先标定 config 中的 ROI 与颜色,见下)
python -m hbc.main # 自动探测第一个 adb 设备
python -m hbc.main 127.0.0.1:16384 # 或指定模拟器地址
python -m hbc.main --level 2 # 求解第二关
```
## 预留的扩展点
- `Cell.meta`:放特殊方块(条状/炸弹/彩球)、墙的种类 `wall`、砖块血量、冰冻层数等。
- `Solver``scorer`自定义打分策略默认按消除格子数4/5 连额外加权)。
- `Solver._cells_cleared_by`:补充"相邻砖块被消除破坏"等连锁规则。
- `GridConfig.rows/cols`:动态调整网格尺寸(每关不同时重新标定/探测)。
- `recognizer` 的分类器可插拔:默认模板库,必要时换 `ColorClassifier` 兜底。