Per-tick SVG drawText overlay above the bot showing round number and
running average reward (e.g. "R:42 avg:3.50"). Per-round summary also
printed to the UI console via printToStdOut with tick count and score.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
arctan2(dy, dx) gives east-based math bearing; Tank Royale uses north=0°, CW+.
Swapping to arctan2(dx, dy) gives the correct game-space bearing.
Symptom: radar commanded 45°/tick away from a target directly ahead.
Adds test_radar_lock.nim as regression test (20-tick lock, ±15° tolerance).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- enemy_tracker: toggle lastOvershootDir each tick; make getRadarTurnRate take var tracker
- training: remove threadvar Adam globals; pass adamStates as var param to ppoUpdate; export ACAdamStates
- PPO_Bot: carry ACAdamStates through TrainingArgs/TrainingResult; drop trainingDone bool and Lock — use resultChan.tryRecv() directly as synchronisation
- weights: sort checkpoint dirs newest-first by mtime instead of hardcoded order
- tests/test_training: pass explicit ACAdamStates to ppoUpdate
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Manual-backprop PPO with Adam: TrajectoryBuffer, computeGAE, ppoUpdate
(4 epochs, minibatch 64, clip 0.2, grad norm 0.5). Reward helpers
computeTickReward/computeRoundReward. Bot wired: tick transitions
collected in run loop, ppoUpdate called on onRoundEnded. Fix: add
arraymancer import to PPO_Bot.nim so Tensor resolves at top level.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two-hidden-layer MLP actor-critic (42→64→64→5/1) with stochastic
actorForward, logStd floor at -3, and BotAction mapper wired into
the run() loop. Assert-based test suite covers shapes, finiteness,
logStd collapse, and all action range bounds.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>