# 贪吃蛇 tick 成本模拟

本文件记录采用前的成本模型与原生复核方法。轻量捷径方案已经过模拟验证，并按用户要求应用到 `dinosaur_32.py`；旧脚本完整保存在 `dinosaur_32_baseline.py`，完整回路实验保持不变。后续算法调整仍先模拟再采用。

后续新增了保留原选路策略的轻量捷径实验：20 个种子的成本模型显示，预计比原版少用 92.3% tick，比完整回路少用 47.8%，但仍保留原策略的增长死路。该实现现已用于主脚本，`--include-light` 会直接读取生产代码。三方数据和实现说明见 [dinosaur_shortcut_experiment.md](dinosaur_shortcut_experiment.md)。下文保留原版与完整回路的两方结果及成本依据。

## 已运行的本地模拟

```bash
python -B -m unittest -v dinosaur_tick_model_test
python -B dinosaur_tick_model.py --seeds 20 --size 32 --output dinosaur_tick_model_results.json
```

模型通过 AST 插桩统计实际执行的运算、分支、索引、容器操作和位置查询，按苹果进度记录移动次数。模拟器自身的碰撞检查、随机数生成和 CPython 运行时间不计入成本。20 个种子、两种算法的 40 局均填满，移动步数与此前未插桩的模拟逐局一致。

采用公开游戏文档及第三方公开反编译源码快照中的规则，**结果是成本估算，不是本机游戏引擎实测**。该快照没有与用户安装版本核对；标量字典键成本、语言解析细节和模型的均匀空格苹果分布仍需原生模拟复核。

关键规则：

- 恐龙移动初始内部成本 400；离开苹果并成功生成下一颗苹果时，先执行 `ticks -= floor(ticks * 0.03)`，再为本步计费。第一段为 388，99 次递减后停在 33。不能用 `400 * 0.97**n` 并下限为 1 来代替。
- 列表 `pop(i)` 收费为删除前长度减去索引，因此 `body.pop(0)` 收费等于蛇身长度；字典的标量键 `pop` 按 1 计。
- 普通赋值、变量读取、直接函数调用、`return`、一元运算和循环迭代本身不收费。
- 数值二元运算、标量比较、索引、`if`、二元布尔操作各按 1 计；循环按每次进入整体收 1，`len`、`range` 各 1。
- 列表字面量成本 `max(1, 长度)`，字典字面量 `1 + 长度`，`append` 为 1。

32×32，20 局均值：

| 费用（预计 tick） | 原版捷径 | 完整回路实验 |
| --- | ---: | ---: |
| 移动 | 4,812,292 | 13,839,559 |
| 语言操作及容器基本费用 | 25,404,455 | 556,437 |
| 位置查询与测量 | 670,923 | 1,024 |
| 列表删除额外移位费用 | 66,501,547 | 0 |
| 合计 | **97,389,216** | **14,397,020** |

逐项取整可能造成 1 tick 的加总差异。完整回路预计少用约 **85.2%** tick；比值约 0.148，即原版预计耗时约为候选的 6.76 倍。原版 `pop(0)` 的基本 1 tick 已在语言费用中，额外 `n-1` 单列，未重复收费。

这张表比较算法主体，未包含公共的外层苹果循环、清场、换帽和统计打印。方向表的一次性构建操作数单独记录在 JSON 的 `route_setup_counts`，不混入每局移动循环费用。

敏感性检验也保存在 JSON：将语言费用乘 0.5 或 2，候选预计减少约 83.3%～87.8%；故意把所有移动固定为 200 tick 的压力模型下，候选仍较低。压力模型是检验结论稳定性的反事实参数，不代表游戏实际规则。早期使用几何衰减到 1 tick 和统一 AST 权重的初步模型已被替换，勿使用其临时结果。

五项自动化测试覆盖循环计费样例、短路布尔求值、不同位置的列表删除费用、恐龙移动递推及插桩前后路线一致性。

## 游戏原生 simulate() 复核入口

已准备两个独立文件：

1. `dinosaur_sim_worker.py`：在新模拟世界中运行指定算法一局，通过 `get_tick_count()` 输出 `NATIVE_SIM` 成本、满图状态、骨头和一次性路线构建成本。
2. `dinosaur_simulate_benchmark.py`：按截图中的六参数 `simulate()` 接口调用 worker，默认五个固定种子，两种算法使用相同科技和虚拟初始库存，每个种子交换运行顺序。

在游戏中创建与上述文件名对应的两个代码窗口后，运行 driver。每次调用独立重置模拟状态，使用满级科技、32×32 地图、100,000,000 仙人掌和零初始能量；不拿现实农场作为测试场地。`BENCH_MODE` 和 `BENCH_SEED` 通过 `sim_globals` 注入，worker 不会用默认赋值覆盖它们。

`simulate()` 的返回值 `run_time` 是**模拟游戏秒数**，不是 tick。`speedup` 只改变现实等待时间，不应乘到结果上；满级速度下也不能机械地用秒数乘 400 换算 tick。比较 tick 应读取 worker 打印的 `NATIVE_SIM`，其中 `cold_total_ticks` 包含方向表构建。

当前开发环境没有该游戏运行时，因此尚未执行原生 `simulate()`。入口的参数、全局注入、运行顺序和满图输出已用 API 桩验证；桩 tick 只测试程序接口，不参与上表的性能估计。

## 依据

- [恐龙机制文档](https://github.com/scp3500/Docs-of-The-Farmer-Was-Replaced/blob/e28a4326fa86ca55ac1b6584f644a6bfa8a3b157/编程农场/开发文档/解锁/作物/恐龙.md)
- [计时文档](https://github.com/scp3500/Docs-of-The-Farmer-Was-Replaced/blob/e28a4326fa86ca55ac1b6584f644a6bfa8a3b157/编程农场/开发文档/解锁/高级/计时.md)
- [simulate 文档](https://github.com/scp3500/Docs-of-The-Farmer-Was-Replaced/blob/e28a4326fa86ca55ac1b6584f644a6bfa8a3b157/编程农场/开发文档/解锁/高级/模拟.md)
- [公开源码快照](https://github.com/MengLeiFudge/TFWR_Simulator/blob/55514a27d14a3819e28577bb4e1b027beb4d7887/references/DecompiledSource/Core/Core.decompiled.cs)：DinosaurHat 2041 行、OnMove 2107 行、Pop 6284 行、赋值 7222 行、二元运算 7510 行、字典 8485 行、列表 8920 行。
