Add --max-speed flag to TestBattleRunner (sets defaultTurnsPerSecond=-1 for unlimited TPS).
Add SNNBot_garage/tests/test_bullet_economy.nim: 10-round vs WallsBot, prints per-round and summary stats for tuning.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Document exception handling, zero-value BotResult trap, shared adversary bots
- Add offline parsing example using parseServerOutput
- Skip tests gracefully when JARs missing (guard before suite blocks)
- Fix blocking readLine in runner_process.nim: poll with 50ms sleep + atEnd check
(was preventing timeout enforcement, now blocks correctly during battle)
- Add test task to QBot.nimble and config.nims setup docs to AGENTS.md
- Add debug logging to TestBattleRunner for bot identity tracking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements:
- BattleResult type and JSON-lines parser (#127)
- TR server lifecycle manager (#128)
- Bot compiler using nim c (#129)
- runBattle() orchestrator (#130)
- Example test in OscillatorBot_garage (#131)
- Framework usage guide (#132)
- TestBattleRunner.java for external server (#133)
- BattleRunner process lifecycle (#134)
Fix: runner_process.nim was redefining TimeoutError locally; now
uses std/net.TimeoutError consistently with server_manager.nim.
Three bugs caused the radar to sweep continuously instead of locking:
1. run() loop set radar to Inf every tick, overwriting any lock
→ replaced with enemy_tracker.getRadarTurnRate()
2. onScannedBot used radarBearingTo() (math convention, east=0 CCW)
→ removed; run loop now handles radar via enemy_tracker
3. enemy_tracker.getRadarTurnRate() had arctan2(dx,dy) instead of
arctan2(dy,dx) — introduced by fd22535; bearing was off by ~90°
Also relaxed stale-lock threshold from 2 to 8 ticks to survive
brief scan gaps without falling back to full sweep.
Added tools/battle_runner for automated 1v1 testing.
Result: 1303/1308 ticks with successful scan (was ~1 in 4).