Skip to content

About

SCP:SL 自动游玩贪吃蛇

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

5 Commits

Folders and files

Repository files navigation

SCPSL Auto Snake

SCP: Secret Laboratory 贪吃蛇彩蛋自动游玩机器人。项目通过只读本地游戏进程内存感知 横向 18×11 棋盘,再用正常方向键驱动本机蛇。2.2 版加入可覆盖在游戏上方的原生 Windows 悬浮小窗,并针对游戏后期持续加速重做了轮询、按键调度和算法截止机制。

合规边界

  • 进程权限仅为 PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
  • 只调用 ReadProcessMemory,不写内存、不注入 DLL、不创建远程线程;
  • 输出仅为本机方向键,SCPSL 不在前台时会拒绝发送;
  • 仅面向本地彩蛋玩法,不提供竞技功能。使用者仍需自行遵守游戏服务条款。

2.2:18×11 横向棋盘、高速后期与悬浮小窗

  • 默认基准棋盘从实验用 8×8 改为游戏实际的 18×11 横向棋盘(宽 18、高 11,共 198 格);
  • 最大内存轮询间隔从 30ms 降至 5ms,并根据观察到的蛇步周期动态收紧到最低 1ms;
  • 去掉 50ms 方向键冷却。主循环本来就只在蛇头移动后决策一次,额外冷却只会漏掉高速转向;
  • Hamilton 正常后继/安全捷径直接依赖回路顺序不变量,不再每步重复执行 BFS,正常热路径为 O(1);
  • Temporal/Adaptive 除节点上限外新增墙钟预算,默认每次搜索 3ms,避免状态爆炸阻塞下一帧;
  • 完整 GUI 增加占用率、实时 Hz、方向/食物、AI 平均/最慢耗时、性能余量、移动/按键数、 PID、运行时长与食物计数,信息密度更高但仍按运行优先级分组;
  • 完整窗棋盘画布按 18:11 横向比例固定高度,日志移到棋盘下方,不再用竖向大画布制造空白;
  • 新增 680×300 无边框悬浮小窗:精选棋盘、分数、蛇长/占用率、步频、AI 延迟和路线信息, 默认 88% 透明、始终置顶,可拖动并完整覆盖在游戏画面上方;
  • 完整窗和小窗共享实时状态,可在 55%–98% 范围调节透明度;全局快捷键无需游戏失焦即可 启停、切换小窗、显隐和调整透明度;
  • GUI 使用独立机器人子进程和 JSONL 遥测,停止按钮通过控制管道请求优雅退出,界面不会被 内存扫描或 AI 搜索卡住;子进程管道固定为 UTF-8,避免中文日志在 GBK Windows 上乱码。

安装与运行

要求 Windows 10/11、Python 3.10+。

pip install -r requirements.txt
copy config.example.toml config.toml
python run.py

python run.py 现在默认打开 GUI。启动机器人后需把 SCPSL 切回前台;GUI 可以留在后台监控, 游戏失去前台时程序会继续读取状态但拒绝发键。

GUI 快捷键:

操作 窗口内 全局(游戏前台时也有效)
启动 / 停止机器人 F5 Ctrl+Alt+S
完整窗 / 悬浮小窗 F8 Ctrl+Alt+F8
显示 / 隐藏窗口 — Ctrl+Alt+H
提高 / 降低透明度 — Ctrl+Alt+↑ / Ctrl+Alt+↓

若某个组合已被其它软件占用,GUI 会在运行日志中明确报告注册失败;其它快捷键仍可使用。

命令行与 TUI 仍完整保留:

scpsl-auto-snake-gui
scpsl-auto-snake run --config config.toml
scpsl-auto-snake run --strategy hamilton --no-ui
scpsl-auto-snake benchmark --jobs 4

核心配置:

[runtime]
poll_interval = 0.005       # 最大轮询间隔,后期会按步频自动缩短至最低 1ms
key_cooldown = 0.0          # 兼容上限;非零值也会按当前步周期自动压低
wait_between_scans = 2.0
decision_budget_ms = 4.0    # 整次策略决策告警阈值

[ai]
strategy = "hamilton"      # hamilton | adaptive | temporal | astar | greedy
hamilton_shortcut = true
temporal_max_expanded = 4000
temporal_time_budget_ms = 3.0
adaptive_switch_occupancy = 0.45

decision_budget_ms 是监控阈值;temporal_time_budget_ms 是时序搜索的实际截止条件。截止检查 每 16 个展开节点进行一次,所以整次策略决策可能略高于搜索预算。

算法实现

Hamilton

18×11 至少一边为偶数,可以构造覆盖全部 198 格的 Hamilton 回路。策略初始化时比较正向与 反向回路,选择与当前蛇身方向兼容的一侧。正常移动沿回路后继前进;安全捷径必须同时满足:

  1. 当前蛇身从头到尾仍符合回路循环顺序;
  2. 新头不会到达或越过尾巴;
  3. 新头不会越过当前食物;
  4. 新方向不是反向且不会立即撞身。

这些条件本身就是顺序安全证明,因此不再附加 BFS 复核。初始化 O(V),兼容状态下 每步 O(1),V=W×H。只要回路不变量成立,偶数边棋盘可保证最终填满,是 18×11 高速实战 默认策略。

因此“食物看起来就在旁边”不一定代表 Hamilton 可以直接吃:该方向可能是反向移动、可能在 回路顺序上位于蛇头后方,或会到达/越过尾巴。捷径还会在蛇身暂时不符合回路顺序时整体停用。 遇到这些情况,策略会继续沿安全回路前进,视觉上可能绕完整个棋盘再吃;这是换取填满保证的 预期行为。希望路线更直接可选 temporal/greedy,但它们不保证填满;adaptive 则是保留 Hamilton 安全顺序的折中方案。

Greedy(静态 BFS 基线)

将当前蛇身视为静态障碍,用 BFS 找到食物最短路;整条路径会真实模拟至吃下食物,并验证 吃完后头尾仍连通。找不到安全食物路时,按头尾连通、可达空间、出口数和食物距离兜底。

它简单、延迟低,但静态障碍模型看不到即将让出的尾巴,也没有全局完成不变量。在 18×11 后期常进入“不会死、也不再得分”的安全循环。

A*(静态启发式基线)

状态、安全验证和兜底与 Greedy 相同,只将 BFS 换成环面曼哈顿启发式的 A*。理论复杂度为 O(V log V);它通常减少无关格展开,但堆操作会抵消一部分收益,也无法修复静态身体模型的 根本限制。因此 A* 是寻路效率对照,而不是完成保证算法。

Temporal(时序 A*)

搜索节点为 (完整蛇身元组, 当前方向)。每次展开真实执行新头插入、增长、尾巴让出、反向 禁入和环形回绕,能找到静态 BFS/A* 看不到的“等待尾巴让路”路径。到达食物后还要验证新的 头尾连通。

状态数最坏近似指数增长。18×11 默认同时受 4000 节点和 3ms 墙钟限制;预算耗尽即用 生存评分兜底。它在大棋盘得分高,但独立使用没有填满保证,且几乎持续吃满实时预算。

Adaptive(Hamilton 不变量 + 限时时序捷径)

Adaptive 从开局就建立 Hamilton 回路,时序 A* 只允许展开仍保持回路顺序不变量的状态;占用率 达到 adaptive_switch_occupancy 后完全交回 Hamilton。即使搜索超时,回路后继仍是安全退路。

它保留偶数边棋盘完成保证,并尝试在前期缩短取食路径。18×11 实测步数与 Hamilton 接近, 平均决策约高一个数量级,属于“有安全证明的实验型加速”,而非高速场景默认项。

所有算法横向评价

策略 状态模型 18×11 填满保证 实时延迟 后期高速适配 主要价值 主要风险
hamilton 固定回路 + 顺序安全捷径 是 最低且最稳 最佳 默认实战,稳定填满 平均取食路线偏长
adaptive Hamilton 不变量 + 限时时序 A* 是 中等,前期有 3ms 尾部 好 安全证明下尝试捷径 本轮步数优势不稳定
temporal 动态完整蛇身 A* 否 最高,常触及预算 一般 处理移动尾巴,得分高 状态爆炸、超时后可能循环
greedy 静态身体 BFS 否 低 好 最简单可靠的基线 后期安全循环
astar 静态身体 A* 否 低 好 比较启发式寻路效率 大棋盘仍无全局策略

复杂度中的 V=W×H,S 为时序搜索实际展开状态数:

策略 单次新规划时间 额外空间
Hamilton 初始化 O(V),正常每步 O(1) 回路/序号 O(V)
Greedy O(V+E),四邻域下为 O(V) O(V)
A* O(V log V) O(V)
Temporal O(S log S),另受墙钟截止 O(S×蛇长)
Adaptive 前期限时 Temporal,后期 Hamilton 前期 O(S×蛇长)

结论很直接:18×11 横向棋盘且游戏后期越来越快时选择 Hamilton。Adaptive 可用于实验;Temporal 适合离线分析或奇×奇棋盘;Greedy/A* 只适合作为低延迟基线,不能用“零死亡”替代完成率。

18×11 横向基准

环境:Windows、Python 3.13.9;日期 2026-08-05;每策略 3 局;食物模式 scan;配对种子 20260805+i;单局最多 15000 步;--jobs 4;Temporal/Adaptive 为 4000 节点、3ms 搜索 预算。满分为 198-3=195。

策略 完成率 平均得分 平均步数 死亡 超时 平均决策 p99 最慢
Hamilton 100.0% 195.0 8759.7 0 0 0.043ms 0.137ms 1.40ms
Adaptive 100.0% 195.0 8922.0 0 0 0.392ms 3.660ms 5.37ms
Temporal 0.0% 179.0 15000.0 0 3 2.890ms 3.904ms 6.61ms
Greedy 0.0% 137.7 15000.0 0 3 0.095ms 0.449ms 1.69ms
A* 0.0% 136.3 15000.0 0 3 0.102ms 0.429ms 2.08ms

三点需要分开看:

  • 五种算法均为 0 次死亡,但只有 Hamilton/Adaptive 完成,说明存活率不能代表算法质量;
  • Adaptive 本轮平均多 162.3 步(约 1.9%),样本量不足以说明稳定差异,延迟则明确更高;
  • “最慢”包含四进程并发调度和 Windows 抢占抖动;p99 与平均值更能代表持续实时负载。

复现命令:

scpsl-auto-snake benchmark --strategies hamilton,greedy,astar,temporal,adaptive `
  --games 3 --size 18x11 --max-steps 15000 --seed 20260805 `
  --food-mode scan --jobs 4 --temporal-max-expanded 4000 --temporal-budget-ms 3

scpsl-auto-snake benchmark --jobs 4 --json

scan 复刻游戏的“随机起点 + 外层 x/内层 y 回绕扫描”落点分布,但 Python RNG 不与 .NET System.Random 逐位相同;不同走法也会从第二个食物起改变空格扫描结果。

内存读取与一致性

SnakeEngine 是 IL2CPP 对象。定位优先级为:

  1. 验证过的 GameAssembly.dll base + klass RVA 缓存;
  2. 上次实例地址验证;
  3. ChaosKeycardItem.static_fields → SnakeSessions 指针链;
  4. metadata 定位 klass;
  5. 只读堆扫描兜底。

缓存永远不直接信任:代码会验证 klass 名、对象 klass、_deltaSender、棋盘范围、食物与蛇身 坐标。单帧读取先批量抓取固定字段,再读取 List<Vector2Int>;List._version 变化或前后 对象快照不一致时会整帧重试,拒绝把跨帧撕裂状态交给 AI。

当前核心偏移均为游戏版本相关实现细节:

结构 字段 偏移
SnakeEngine _areaSize / _segments 0x18 / 0x30
_gameoverSw / _deltaSender 0x40 / 0x48
_curMovDir / _foodPosition / Score 0x50 / 0x58-0x5C / 0x68
List<T> _items / _size / _version 0x10 / 0x18 / 0x1C
IL2CPP 数组 首元素 0x20

游戏更新后仍需在真实客户端做只读复核;缓存/RVA 验证失败会回退发现流程,而不是继续解析 错误地址。

测试与项目结构

pip install -e ".[dev]"
python -m pytest
python -m ruff check auto_snake tests
python -m ruff format --check auto_snake tests

测试覆盖 18×11 Hamilton 构造与完整对局、墙钟搜索截止、动态轮询、GUI 遥测、透明度与快捷键、路径首步假安全 反例、尾巴让路、增长碰撞、配置边界及模拟 ReadProcessMemory 的一致性快照。

auto_snake/
├── gui.py / hotkeys.py       # 完整 GUI、置顶悬浮小窗、全局快捷键
├── telemetry.py              # 子进程控制所用实时 JSON 遥测
├── realtime.py               # 随游戏步频自动收紧的轮询调度
├── state.py                  # 状态、碰撞、统一转移
├── strategies/               # 五种策略、拓扑缓存、限时时序搜索
├── benchmark.py              # 配对种子、多进程、质量与延迟统计
├── snake.py / memreader.py   # 只读定位、一致性快照、Win32 内存接口
├── cli.py / config.py        # GUI/TUI/基准入口与配置校验
└── ui.py / recorder.py       # rich TUI、JSONL 录制与回放
tests/                        # pytest 回归套件
tools/                        # 只读逆向与探针工具

客户端权威说明

反编译链路显示:持卡本地客户端持有 _deltaSender,本地执行 Move() 并产生同步消息;服务端 只中转消息,不维护该玩家的 SnakeEngine。本地实例对入站蛇消息会早退,因此服务端无法可靠 操控正在玩的本机蛇。这也是项目采用本地只读感知 + 正常键盘输入,而不是服务器插件或内存 写入的原因。

许可证

MIT License © 2026 FXDYJ

About

SCP:SL 自动游玩贪吃蛇

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages