974528d5cf
Gun evaluation previously required a full end-to-end battle (Java server + battle runner + websocket IPC to 2 bot processes, 50 rounds, ~3.4 min) and yielded only ~300-900 REAL shots across 13 guns -- far too few to rank guns, which is why tuning needed many repetitions. VirtualTracker is already a pure function of (WorldState stream, gun list); the only reason it needed Java was where WorldState came from. So the range replays a seq[WorldState] through the SAME tracker: offline and online scores are the same metric by construction, not an approximation. ACCEPTANCE TEST (the point of the whole thing): record one live round, replay it offline, compare per-gun virtual hit rates. 12/12 deterministic guns match EXACTLY, reproduced twice. Tsetlin is compared separately because tmLearnOne calls rand(). Getting to 12/12 exposed two real ordering quirks in the live loop: run() calls go() before the aim/fire block, so tickBullets resolves against the NEXT tick's scan while the prediction used the previous one; and if the target dies during that go() the final tick's spawn+resolution is skipped entirely. The recorder emits an end marker for the second case. The 5th (selected-gun) predict call was verified to be a no-op. Measured cost: 8 fixtures (1770 ticks, ~92k virtual bullets, 13 guns) replay in 2.9 s, ~32k virtual bullets/s -- roughly 70x faster and 100x more samples than a live gauntlet. Also adds a per-tick WorldState recorder behind const RecordWorldState (default off, mirrors the ShotLog idiom) which records the state the bot ACTUALLY builds, staleness included, rather than true positions -- recording the latter would hand the guns perfect information and produce flattering scores. 9 new guard checks (33 total, all passing), including fixture round-trip, replay determinism, stationary->HeadOn 100%, constant-velocity->Linear>HeadOn, and the energy-threshold turner crossing at t=41.
44 lines
745 B
Plaintext
44 lines
745 B
Plaintext
# Compiled output
|
|
*.out
|
|
|
|
# Python cache
|
|
__pycache__/
|
|
*.pyc
|
|
*.pyo
|
|
|
|
# Log files
|
|
*.log
|
|
|
|
# Training logs
|
|
*.jsonl
|
|
|
|
# Test binaries (but keep .nim source files)
|
|
**/tests/test_*
|
|
!**/tests/test_*.nim
|
|
!**/tests/test_*.nims
|
|
|
|
# User-specific dev environment
|
|
.envrc
|
|
devbox.json
|
|
devbox.lock
|
|
|
|
# Compiled bot binaries — all builds go to *_garage/out/
|
|
*_garage/out/
|
|
|
|
# Java compiled classes
|
|
*.class
|
|
|
|
# Log and snapshot directories
|
|
**/logs/
|
|
**/snapshots/
|
|
|
|
# Git worktrees
|
|
worktrees/
|
|
|
|
# Nimble puts the bot binary at the garage root (out/ is ignored, this was not)
|
|
*_garage/ModularBot
|
|
|
|
# Test fixtures are data, not logs - the *.jsonl rule above was written for
|
|
# training logs and silently excluded the entire gun-range fixture set.
|
|
!tools/fixtures/**/*.jsonl
|