Commit Graph

28 Commits

Author SHA1 Message Date
SirStone 3c90a5941d feat(selector): range-aware firing gate fitted to 2611 measured shots
Measured, not assumed. With the gate temporarily opened to 20 deg, every
real shot was logged (tick, angle error at fire time, distance, power,
hit) across 3 gauntlets: 2611 shots, 57.3% aggregate. Findings:

- The geometric cone atan(BotRadius/d) is directionally confirmed but a
  WEAK lever: even at 0.0-0.1 deg error the hit rate at 400-600px is only
  ~53-57%, because PREDICTION error dominates alignment error.
- Real effect of tightening the gate: 57.9% -> 68.0% aggregate hit rate
  (fixed 0.1 deg), not the 76.9% previously reported -- that was a
  high-variance draw (per-rep 62.8/66.4/77.2%).
- The shipped range-aware gate (SafetyFactor 0.6) does NOT beat the fixed
  2.0 deg gate on hit rate (55.8% vs 57.9%, ~1.5 sigma, inside noise). It
  fires 22-28% more shots and therefore lands more total hits (~509 vs
  ~434 per rep). No per-adversary score delta exceeded the 300-point
  run-to-run noise band, so no config is demonstrably better on score.

Shipped anyway because it is strictly more expressive (a fixed threshold is
the special case), tunable from one const, and physically motivated, but
the honest verdict is recorded in-code: the gate is not the bottleneck.

AimThresholdDeg is removed; shouldFire now takes distPx. Degenerate or NaN
distance falls back to the ceiling rather than dividing by zero.

Also adds a per-shot logger to ModularBot behind 'const ShotLog' so the
measurement above is reproducible, and 10 new guard checks (24 total, all
passing) covering monotonicity, clamping, formula, perfect alignment,
gross misalignment and degenerate distance.

Cross-checked against the server source: the gun fires BEFORE the turn is
applied, so the logged angle error is the true departure error, and
fireAssist auto-aim is off (unset by the Nim API and forced false by
setAdjustRadarForGunTurn).
2026-09-20 23:28:31 +02:00
SirStone 0cc682152d fix(guns): per-bin wave queues unbreak GF/DecayGF/KNN learning; fix vbullet drops
Wave queues (guess_factor, decay_gf, knn_gun): predict() stored ONE wave
per tick while onResult() popped one per resolved bullet (~4/tick), so the
queue drained to empty within a few dozen ticks, ~3 of every 4 resolutions
returned without learning, and the survivor paired with a same-tick wave
(bearingDelta ~= 0) pinning the histogram at centre. PROOF: GF.vHits ==
HeadOn.vHits and DecayGF.vHits == HeadOn.vHits byte-for-byte in every one
of 50 rounds — the guns had degenerated to HeadOn.

Now each gun keeps a per-bin FIFO with an O(1) head cursor. At most one
push per (tick, bin) so the fire site's 5th predict() call is a no-op, and
onResult pops the oldest wave of its OWN bin via e.bulletPower. Aiming
math untouched (it was already correct: 0 deg = East, CCW+).

maxBullets 2048 -> 8192: the rack spawns 52 bullets/tick so the ring wrapped
every ~39 ticks while a long power-3 shot needs ~90, silently discarding
unresolved bullets and biasing every measured hit rate by range. Added a
droppedBullets counter so a future overflow is measurable, and wavePushes/
waveStarved counters on the three guns. After the fix: vDropped = 0 and
vStarved = 0 across all 48 recorded rounds.

fitnessFor is now exported, deterministic (enemies iterated in ascending id
order) and shared by the selector and the stats dump, replacing a hand-rolled
merge in ModularBot that never advanced its window head.

Round lines gain additive keys: vDropped, vStarved.
2026-09-20 22:27:52 +02:00
SirStone a90a0cc9b5 chore: untrack ModularBot_garage/ModularBot build artifact
nimble bin output lands at the garage root, so the existing
'*_garage/out/' ignore rule never covered it and every build dirtied
the tree with a 1.1 MB binary. File stays on disk; build regenerates it.
2026-09-20 22:15:42 +02:00
SirStone 26b66cbb24 feat(gun_harness): per-gun REAL hit attribution + bestPower cold-start fix
Attribution is proven, not guessed: the server assigns a per-round-unique
bulletId (GunEngine.nextBulletId) and stamps the same id on BulletFired,
BulletHitBot, BulletHitWall and BulletHitBullet. Keep a FIFO of fired gun
ids, stamp bulletId -> gunId on onBulletFired, resolve through that map.

Hits are deferred when onBulletHit precedes onBulletFired in the same
turn (client dispatches priority 70 > 60), which recovered 14
unattributed hits. 99.9% of shots and 99.8% of hits attributed.

Stats lines now carry per-gun realShots/realHits/realHitRate; the old
keys and round-level totals are unchanged.

bestPower: a gun with zero observations in every bin previously returned
the HIGHEST bin (power 3.0) because an empty bin satisfied the
'count == 0' clause on the first countdown iteration. Cold guns now
return the lowest bin as the docstring always claimed. Warm-gun path
untouched.
2026-09-20 22:15:42 +02:00
SirStone 343e631633 fix(gun_harness): random tiebreak + drop AntiSurfer + raise MinObsBeforeCompete
- bestGun: replace first-index-wins argmax with random pick among guns
  within TieMargin (2%) of best rate. HeadOn at index 0 was silently
  winning every tie, starving Tsetlin/Linear/etc.
- MinObsBeforeCompete 15 -> 50 (Pattern entered competition on noise)
- add MinHitRateFloor 0.10: if no gun clears it, fall back to HeadOn
  instead of selecting the best of a bad field
- ModularBot: remove AntiSurfer gun (0% virtual hit rate everywhere),
  14 -> 13 guns, renumber ids and selection counters
2026-09-20 22:07:49 +02:00
SirStone c034eb9d25 feat(testing): gun rack gauntlet + analysis reports
- fix(ModularBot): onBulletHitBot → onBulletHit (real hits were never tracked)
- feat(ModularBot): per-round gun stats dump to /tmp/gun_stats.jsonl
- feat(ModularBot): gun selection counter per round
- fix(tests): adversary paths _garage suffix removed from 7 test files
- feat(tests): test_gauntlet_5bots.nim — 10-round gauntlet vs all 5 adversaries
- feat(tests): analyze_gun_stats.nim — JSONL parser for gun performance tables
- docs: gun_rack_analysis.md — full per-gun performance report
- docs: gun_rack_summary.md — TL;DR verdict table (keep/drop/tune)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 21:14:12 +02:00
SirStone 2cc2a3bd87 fix(ModularBot): ram loop prevention, dead-target guards, cleaner logging
- 30-tick cooldown after ghost-stuck/timeout ram exit prevents re-entry loop
- enemy_tracker.update() skips dead bots to prevent same-tick scan resurrection
- TFIL graphics cleared when ramming is active movement
- [config] logs: white base with green-highlighted changes only
- [ram:enter] logs trigger reason and key values on false→true transition
- [death] and [target-invalid] logs retained for diagnostics
2026-09-20 20:44:45 +02:00
SirStone 7657699531 fix(movement): lock target during ram — no switching until target dies or ram exits 2026-09-20 12:39:11 +02:00
SirStone c90874affd refactor(movement): extract ram to harness — phantom meteor dodge-only, rammer module via harness decision
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 12:36:09 +02:00
SirStone ae9a5fec6d feat(movement): multi-enemy awareness — phantom meteor + minimum risk track all enemies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 12:28:27 +02:00
SirStone ab473c6b68 feat(ModularBot): melee targeting — multi-enemy tracker, per-enemy gun fitness, radar auto-switch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 12:25:10 +02:00
SirStone 30d00ba163 feat(movement): dodge timing, wall avoidance, distance control, ram finisher
PhantomMeteor:
- Ram finisher: charge at enemy when <200px and their energy <10
- Ram opportunity: charge when <60px and we have >20 energy advantage
- Integrated gunheat tracker for 1-2 tick earlier wave detection
- Distance control: smooth linear ramp toward preferred engagement distance
- Phantom range expanded 150→250px to catch closer threats

WaveSurfer:
- Wall-aware dodge bin selection: penalize bins leading off-arena
- Dodge timing: predict future position 15 ticks ahead for safety
- Distance control: radial blend when outside deadband (350±50px)
- Wall escape: invert strafe if pushing further into wall, blend toward center

ModularBot:
- Wired KNN gun (purple/magenta)
- Shadows tracked for movement (safer GF prediction)
- Bullet lifecycle management (onBulletFired/onBulletHitBot/onBulletHitWall)
- Unified phantom_meteor movement (wave_surfer unplugged)
- Config logging on round start + gun switch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 11:59:05 +02:00
SirStone 6d16081fcc style(ModularBot): ANSI colored log tags — gun yellow, move cyan 2026-09-20 11:01:12 +02:00
SirStone 1eaaadf627 refactor: move adversarial test bots to common_libs/test_framework/adversaries/ 2026-09-20 10:49:31 +02:00
SirStone c0abd4c960 feat(ModularBot): virtual body movement selector — wave-based scoring replaces EMA damage
Implements VirtualBodyTracker (wave-based hit/miss scoring) instead of EMA damage accumulation. Movement switching now happens every tick, not every 3 rounds. Also refactors radar colors to dark teal (#004444/#0D4D4D) for faint visibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 10:44:49 +02:00
SirStone d2a2ebceb9 feat(ModularBot): movement selector — phantom meteor + wave surfer
- Adds WaveSurferModule as second movement option
- Tracks damage per round via onHitByBullet, EMA decay α=0.5
- Every round after round 2: switches to lower-damage movement
- Body color signals active mover (orange=phantom, blue=wave)
- vs SpinBot 10r: ModularBot 1412 vs SpinBot 650
- vs WaveSurfer 10r: ModularBot 1858 vs WaveSurfer 10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-20 01:55:47 +02:00
SirStone c94ba1f2fe feat(ModularBot): decay-GF gun (recency-weighted), 13 guns total
- Decay-GF: exponential decay on GF histogram (0.998/tick, ~350-tick half-life)
- Adapts faster to mid-battle strategy changes than standard GF
- Battle-tested vs WaveSurfer, Crazy, RandomMover
2026-09-20 01:52:22 +02:00
SirStone 3a1149359d fix(gun_harness): bump virtual bullet ring buffer 512→2048
With 12 guns × 4 power bins = 48 bullets/tick, 512 slots overflow
before slow bullets resolve (~36 ticks travel). 2048 gives headroom.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 01:49:21 +02:00
SirStone fbf9414375 feat(ModularBot): rammer movement + averaged-lead gun, 12 guns
- Ram movement: drive straight at enemy (not wired, needs selector)
- Averaged-lead gun: mean of linear+circular+wall-bounce predictions
- 12 guns total, battle-tested

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-20 01:46:52 +02:00
SirStone b373d3d505 feat(ModularBot): displacement-vector gun, 11 guns total
- Displacement gun: average velocity over sliding window, captures drift
- Complements instantaneous-velocity linear gun
- Battle-tested vs Crazy, WaveSurfer, PatternMover
2026-09-20 01:43:25 +02:00
SirStone a87be5f99f feat(ModularBot): stop-shot gun, 10 guns total
- Stop-shot gun: predicts enemy deceleration stop point
- Catches bots at direction reversal pauses
- Battle-tested vs WaveSurfer, Crazy, RandomMover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-20 01:37:45 +02:00
SirStone 18ff2d45b3 feat(ModularBot): acceleration predictor gun, 9 guns total
- Accel gun: tracks velocity+heading changes, extrapolates with acceleration
- Handles speed-up, slow-down, and combined accel+turn
- Battle-tested vs Crazy, RandomMover, Walls
2026-09-20 01:34:27 +02:00
SirStone b2cf02db11 feat(ModularBot): wave-surf movement + wall-bounce gun, 8 guns total
- Wave-surf movement module (not wired, needs movement selector)
- Wall-bounce gun: linear extrapolation with arena wall reflection
- 8 guns: head-on, linear, circular, tsetlin, guess-factor, pattern, anti-surfer, wall-bounce
- Battle-tested against Walls, SpinBot, WaveSurfer, PatternMover, TrackFire

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 01:31:41 +02:00
SirStone a3b4f26b69 feat(ModularBot): wall-bounce gun, 8 guns total
- Wall-bounce gun: linear extrapolation with arena wall reflection
- Simulates enemy tick-by-tick, bouncing off walls (billiard-ball reflection)
- 4-iteration convergence on ticksToArrive like circular gun
- 8 guns: head-on, linear, circular, tsetlin, guess-factor, pattern, anti-surfer, wall-bounce
- Turret: #CCCCCC (silver), bullet: #EEEEEE (white)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-20 01:30:21 +02:00
SirStone ebe5b1b7f1 feat(ModularBot): anti-surfer gun + wave-surf movement module
- Anti-surfer gun: inverse GF targeting for wave-surfing enemies
- Wave-surf movement: danger histogram dodge (not wired yet, needs movement selector)
- 7 guns total, battle-tested

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-20 01:28:29 +02:00
SirStone 1cb35e9e0e fix(ModularBot): GF gun cold-start + MEA fix, battle-tested 6 guns
- GF gun: triangular head-on prior replaces flat bins (was always aiming at GF=-1)
- GF gun: recompute MEA per bullet power in onResult (was using stale first-bin value)
- Scores improved: SpinBot 1805-48, Crazy 1557-46, WaveSurfer 1868-10, PatternMover 1846-4
- All 6 guns active in selection across gauntlet
2026-09-20 01:22:55 +02:00
SirStone 1ed7797cb6 feat(ModularBot): 6 guns, pattern matcher, melee modules, adversarial bots
- New guns: guess-factor (GF histogram), pattern-matcher (movement tape replay)
- New modules: minimum-risk melee movement, spinning melee radar
- New test bots: PatternMover, RandomMover, WaveSurfer
- Fixed: FeedbackEvent now carries actualX/actualY for proper GF learning
- Fixed: TM gun warmup gating + directional residuals
- Fixed: circular gun integrated formula + multi-bin omega cache
- Fixed: oscillator wall-bounce lockout
- Fixed: phantom meteor perpendicular body orientation
- 6/6 battle wins across all enemy types
2026-09-20 00:59:53 +02:00
SirStone 254c7dc997 feat(ModularBot): pluggable bot with 4 guns, phantom meteor movement, radar harness
- Gun harness: virtual bullet tracker, rolling fitness, auto-selector
- Guns: head-on, linear (extrapolation), circular (integrated formula), tsetlin machine (learning)
- Movement: phantom meteor gravity engine (danger histograms, phantom bullets, fire detection)
- Radar: harness + radar_lock adapter
- Color-coded modules: turret/bullet color per gun, body per movement, scan per radar
- Beats Target, SpinBot, Crazy, TrackFire in 10-round battles
2026-09-20 00:37:10 +02:00