Commit Graph

334 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 54e9757567 docs(research): TM learning tracks + note that the TM-DEB source was deleted
tm-learning-tracks.md covers three things, all marked [FACT]/[INFERENCE]/
[UNKNOWN]:
- Section A: the Tsetlin gun's label is measured against the wrong baseline.
  predX = linearX + cx, so rx = actual - predX = delta - cx, and inside
  tmLearnOne error = residual - predicted = (delta - cx) - cx = delta - 2cx.
  The fixed point is cx = delta/2 -- HALF the correction needed, even with
  perfect Granmo feedback. Fix: store linearX/linearY in TmTrace and train
  on delta. Also: hits zero the label instead of carrying their true
  residual, and the per-clause step is magnitude-blind.
- Section B: what a TM is actually good at (AND-clauses over binary
  literals, readable output) and why this repo suits it -- the gun already
  builds an 83-bit x 10-frame Gray-coded window (870 bits). Includes a
  falsifiable known-rule benchmark proposal.
- Section C: delayed-reward learning belongs to the MOVEMENT layer, not the
  gun. The gun's outcome is delayed but exactly pairable via
  (fireTick, powerBin), so its effective lambda is 1 and discounting would
  only destroy information.

Also records that docs/papers/tm-deb-paper.pdf was deleted by the user as
AI-generated and unverifiable, while the Granmo-based feedback diff in
tm-deb-assessment.md stands on its own.
2026-09-20 23:28:31 +02:00
SirStone 669f9acd41 docs(research): assess TM-DEB paper against the Tsetlin gun's real failure
Verdict: the document (docs/papers/tm-deb-paper.pdf, 'Generated by
Gemini Notebook') solves temporal credit assignment under delayed
reward, which is not our problem. Our gun's failure is clause
saturation (~131 of 1740 literals included per clause -> conjunction
fires with probability ~2^-131 -> correction identically 0), and
TM-DEB only scales update FREQUENCY by gamma^dt, so it would leave
the fixed point untouched and additionally delete the long-range
feedback we need: gamma^90 = 4.4e-7 at the paper's own gamma=0.85,
and those are the shots whose lead matters most.

Credibility signals recorded in the doc: reference [2] misattributes
authors/venue/year; Algorithm Spec 2 steps 9-12 are literal '%'
placeholders so the automata update is simply absent; Table 1 is
titled 'Expected' and reports never-measured accuracies; Eq. 12 is
not a faithful copy of Granmo's Lemma 2.

The audit also produced the actionable result: a line-by-line diff of
Granmo Table 2/3 feedback against tmLearnOne, identifying why the
automata saturate - Type I never conditions on the clause output so it
omits Granmo's c=0, lk=1 -> -1 w.p. 1/s counter-force (true literals
ratchet toward Include), Type II's guard cOut==1 AND lits[lit]==0 is
unsatisfiable and therefore dead code, and the (T - clip(v,-T,T))/(2T)
resource allocation is missing entirely.
2026-09-20 22:57:28 +02:00
SirStone e53690036b fix(guns): speed-sensitive caches, dead stop-shot branch, exact TM trace pairing
Four guns cached a whole prediction per tick while predict() is called once
per power bin, so every bin after the first (and the real fired shot, which
shares lastState) reused the power-1.0 lead. Fixed by caching only the
speed-INDEPENDENT derived state and recomputing the lead per requested speed:
- stop_shot: also fixes prevSpeed being written before it was read, which
  made abs(speed) < abs(prev) permanently false and the entire
  stop-prediction branch unreachable (it was just Linear).
- displacement: the cache key included bulletSpeed, so the guard missed on
  all four bins and the 15-tick window advanced ~4x/tick, making the
  inferred velocity ~4x too small.
- averaged_lead: tick cache removed outright. pattern_matcher: split into
  speed-independent match+path and per-call lead.

FeedbackEvent gains fireTick/powerBin (additive; only virtual_bullets
constructs one) so guns can pair feedback to the exact shot instead of
guessing by coordinates. tsetlin uses it: traces are now keyed exactly by
(fireTick, powerBin) with a 1024-slot ring, and the 10-frame window shifts
at most once per tick (it was shifting ~4-5x/tick, so isWarmedUp tripped
after ~2 ticks).

KNOWN INCOMPLETE: tsetlin still does not diverge from Linear in battle. The
two named bugs are fixed (a 600-tick sim shows trainedShots=2141,
traceMisses=0, and a fixed-input probe converges to a 9.6px correction), but
the TM's clause feedback itself is broken: ~131 of 1740 literals end up
included per clause, so its conjunction never fires. Sweeping TM_S,
TM_N_CLAUSES and a two-branch Type-I update did not change the correction
from 0. Needs a real TM fix or removal, not another bug fix.

First-ever guard tests for the gun selector: common_libs/tests/
test_gun_harness.nim (14 checks, headless, no Java). There were none before,
which is how six broken guns survived a full analysis cycle. Against the
previous HEAD, 5 of these checks FAIL - that is the regression guard.
2026-09-20 22:47:26 +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 1f8574db1d fix(rammer): rewrite heading logic — correct forward/backward steering toward enemy 2026-09-20 13:43:35 +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 f06b263ae5 feat(phantom_meteor): aggressive ram — wider thresholds, desperation mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 12:25:12 +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 5bbc8cbda7 fix(gun_harness): min 15 obs before competing, window 50→100, KNN min k=5
Gun selector now gates competition: guns with <15 total observations across
all power bins sit out until at least one gun qualifies. Falls back to ungated
selection if no gun reaches threshold, preventing cold-start stalls.

Sliding window increased from 50 to 100 ticks to reduce switching noise.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 11:59:00 +02:00
SirStone 651ce80620 feat(ModularBot): KNN gun, gunheat tracker, bullet shadows — inspired by DrussGT
New DrussGT-inspired modules:
- KNNGun: K-nearest-neighbor statistical targeting using GF density peaks
- GunheatTracker: dual-heat system (predicted + confirmed) for 1-2 tick lead
- ShadowTracker: computes GF regions safe from in-flight bullets (enemy wave dodge)

VirtualBodyTracker now integrates gunheat for earlier fire detection and shadows
for safe-zone multiplier (90% reduction in danger zones).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 11:58:57 +02:00
SirStone 6d16081fcc style(ModularBot): ANSI colored log tags — gun yellow, move cyan 2026-09-20 11:01:12 +02:00
SirStone 63db0a4439 refactor: strip _garage suffix from adversarial test bots
Renames PatternMover_garage → PatternMover, RandomMover_garage → RandomMover,
WaveSurfer_garage → WaveSurfer. Updates all .json, .sh, .nimble, and config.nims
files to match TR Booter naming convention (directory name = bot name).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-20 10:50:32 +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 d27efd3f9a feat(ModularBot): random-oscillator movement module + battle tests
- Random-oscillator: perpendicular strafe with randomized reversal timing (15-45 ticks)
- Not wired (needs movement selector)
- Battle-tested 10-gun bot vs RamFire, Corners, VelociBot

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-20 01:39:49 +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 78723fce13 fix(GFGun): head-on prior + per-bin mea in onResult
- Cold-start bug: uniform bins[0..30]=0.1 made peakBin() always return
  0 (first-wins tie), giving GF=-1 (max CW escape) before any learning.
  Fixed with a triangular head-on bump at bin 15 (GF=0) as the prior.
- onResult now recomputes mea from FeedbackEvent.bulletPower instead of
  the stale first-bin mea cached by predict; correct per-power-bin GF.
- Add DebugGF const (default false) with [gf-dbg] echoes in predict/onResult.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-20 01:05:22 +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
SirStone c9191b7afb fix(circular-gun): correct turn-rate calculation for multi-scan delays
Two bugs fixed:
1. Multi-tick gaps: turn rate assumed 1 tick between observations, but scans can be 5+ ticks apart. Now divides by actual tickDelta.
2. Per-power-bin state corruption: predict() called 4x per tick (per power bin). After first call, prevHeading was already updated, causing subsequent calls to compute 0° delta. Now captures oldHeading/oldTick before updating.

Verified: OscillatorBot at 4°/tick captured correctly; normalization [-180°,180°] works; tickDelta=1 typical; first bin gets delta, subsequent bins see 0 (expected).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-19 19:43:40 +02:00
SirStone dd78f3c239 fix(hebbian): symmetric learning — both active and inactive outputs learn
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-18 00:13:32 +02:00
SirStone f12bdf810e feat(BNNBot): shaped reward based on miss distance — every shot teaches something
Replace binary hit/miss reward with exponential decay based on miss distance:
- reward = 2.0 * exp(-missDistance / 36.0) - 1.0
- At 0px: +1.0 (perfect hit)
- At 36px: -0.26 (near miss, small penalty)
- At 100px: -0.87 (big miss, large penalty)

Maintains virtual hit/miss counters for display (threshold: 36px).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-18 00:10:28 +02:00
SirStone 63685b1729 style(BNNBot): remove 870-bit binary dump from output 2026-09-18 00:05:20 +02:00
SirStone b945bb1ac5 fix(hebbian): random weight init to escape zero local minimum
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-09-18 00:03:26 +02:00
SirStone e600204c84 feat(BNNBot): add virtual hit percentage to output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-17 23:54:31 +02:00
SirStone 481f284e1a fix(BNNBot): correct sin/cos for bullet position, gentler 1-bit exploration
- Swap sin/cos in virtual bullet position calc to match Tank Royale convention
- Change exploration from flipping each bit with 50% chance to flipping exactly 1 random bit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-17 23:51:22 +02:00
SirStone 22aefbddb6 feat(BNNBot): Hebbian weight matrix with virtual bullet learning — 870→7 bit forward pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-17 23:49:59 +02:00
SirStone 50e3c6fae9 feat(BNNBot): 10-tick sliding window of enemy data + self state — 870 bits total
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-17 23:35:57 +02:00
SirStone 89f63540bc feat(BNNBot): energy to 11 bits for 0.1 HP precision — 123 bits total
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-17 23:25:09 +02:00
SirStone 152fcba0cc feat(BNNBot): add energy (8+8 bits) and gun ready (1 bit) — 117 bits total
Added myEnergy, enemyEnergy, and canFire to ScanData. Energy fields quantize 0-150 → 8 bits each; gun ready is 1 bit (1 = can fire, 0 = can't). Updated total encoding from 100 to 117 bits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-17 23:21:39 +02:00
SirStone 938c259260 feat(BNNBot): add wall distances for both bots to binary encoding (100 bits total)
8 new fields in ScanData (myWallN/S/E/W, enemyWallN/S/E/W), 7 bits each via Gray code,
appended after existing 44 bits. TOTAL_BITS 44 → 100.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-17 23:17:26 +02:00