Autopilot · write-up
Firing-lane routing: remove repeated terrain work
This change retains the Python route search. c-firing-old in
compare_kernels.py selects the previous implementation; c enables reuse.
No C API, build integration, or gameplay tactics change is included.
Removed work
- Cache discovered-free tile membership until geometry changes, rather than rebuilding it from every persistent map cell for every route request.
- Build the bottom endpoint of each contiguous free column run once with that cache. Goal checks become interval comparisons rather than repeated scans from the target down to each explored cell.
- Return immediately when every target column is blocked or unknown directly below the target: no firing goal exists, so searching cannot produce a route.
The route's start selection, neighbor ordering, shortest-path search and hazard exposure penalties remain unchanged. Unknown cells still block firing rays. Confirmed destructible-wall openings, new walls, resident seeding, RAM terrain synchronization and resets invalidate the geometry cache through the existing map invalidation paths. Bookkeeping-only observations keep it valid.
Cache contents are never mutated after publication. Replay snapshots may share old cached geometry safely; invalidation replaces the live map's reference. Only geometry is cached, not routes dependent on moving targets or hazard lanes.
Validation
New tests compare exact paths on 100 randomized maps and check cache reuse,
wall changes, destruction confirmation, snapshot sharing, and reset behavior.
The full test suite passes 924 tests; log:
xenon_tools/run_logs/firing-reuse-tests-0908.txt.
Timing
Two sequential CPU-4-pinned runs in opposite variant order replayed Level 1 frames 2367–10059 (7,693 observations). Both repeats produced identical decisions.
| Metric | Old firing route | Reused geometry | Reduction |
|---|---|---|---|
| Mean observation time | 3.3566 ms | 3.1919 ms | 4.91% |
| Mean of per-run p95 | 7.7558 ms | 7.2718 ms | 6.24% |
These are full observation-pipeline measurements, not just route-search times.
Report: xenon_tools/run_logs/firing-reuse-timing-0908/comparison.json.
Profile and cross-level checks
A separate instrumented replay measured 1,662 route calls in both variants:
| Work | Old | Reuse |
|---|---|---|
| Firing-route cumulative seconds | 2.4471 | 0.1994 |
| Goal checks | 1,914,764 | 135,323 |
| Cached geometry access/build cumulative seconds | — | 0.0121 |
The route routine costs 91.9% less under the profiler. The goal-check reduction
also confirms avoided searches where no firing goal exists. Profile times are
instrumented and must not replace the uninstrumented timing estimate above.
Report: xenon_tools/run_logs/firing-reuse-profile-0908/comparison.json with
c-firing-old-1.pstats and c-1.pstats beside it.
Old/new verdicts match in the profiled Level 1 replay and Level 2 (961 frames),
Level 3 (225), Level 4 (900), and Level 5 (5,652) recordings. Reports are under
xenon_tools/run_logs/firing-reuse-level{2,3,4,5}-0908/comparison.json.
These are recorded-observation comparisons, not new closed-loop gameplay runs.
With the remaining route time now small, porting this routine to C should be reprioritized against larger current hotspots rather than justified by the old profile. No native rebuild was needed; all changes are Python and documentation.