Commit Graph

29 Commits

Author SHA1 Message Date
SirStone b4e2cb5b3c feat(SNNBot): force learning on input change for fast re-acquisition
When enemy starts moving after stationary phase, the dead zone keeps error
low and skips learning. Now learn when input pattern changes significantly
(Hamming distance > 2 bits), forcing immediate re-adaptation regardless of
error magnitude. Balances stability vs. responsiveness.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-16 07:57:42 +02:00
SirStone 581bfb532c tune(SNNBot): tighten stationary dead zone to 0.5°
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-15 08:46:06 +02:00
SirStone 1790dd0ca4 tune(SNNBot): tighten adaptive dead zone to 1.5°–0.3°
Settled gun error at ~2.6° was within the 3.0° stationary dead zone,
too generous for reliable hits. Tightened bounds from [3.0°, 0.5°] to
[1.5°, 0.3°] across the lerp—revert to proven AIM_TOL=1.5° baseline
for stationary targets, 0.3° for full-speed movers (8 units/tick).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-15 08:43:34 +02:00
SirStone 3066a0c72b feat(SNNBot): adaptive learning dead zone scaled by enemy velocity
Stationary targets get large dead zone (3°) for stable aim. Fast movers
get small dead zone (0.5°) for rapid adaptation. Replaces fixed
threshold and jump-reset hack.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-15 08:40:03 +02:00
SirStone 87bcd3df6b fix(SNNBot): fast recovery on target move + bidirectional fire gate
Problem 1: Dead zone (skip learn when error < 1.5°) means stale exemplars
linger in ring buffer after target moves. Fix: detect error jump >5° and
reset ring buffer (aimer.count, aimer.nextSlot = 0) for fresh start.

Problem 2: Fire gate only checked start condition (err < threshold), never
stopped firing when error worsened. Fix: explicit setFire(0.0) when error
exceeds tolerance, making gate bidirectional (start and stop).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-15 08:35:10 +02:00
SirStone 94fbde2934 fix(SNNBot): use absolute bearing to break aim feedback loop
The input encoded relative bearing, which changes when the bot aims,
creating a closed-loop oscillation (aim→input→aim). Switching to
absolute bearing (world frame) makes the input independent of aim
commands, eliminating the feedback-induced jitter.
2026-09-15 08:23:08 +02:00
SirStone b843a79313 feat(SNNBot): fire only when aim is locked on target
Bot now conserves ammo by firing only when aimLocked=true (error < 1.5°).
During WAITING phase, checks aimLocked flag before firing FIRE_POWER; calls
setFire(0.0) when not locked. Prevents wasted shots on moving targets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-15 08:15:29 +02:00
SirStone c05fb7a32b fix(SNNBot): hold aim when error is within dead zone
Adds aim-lock mechanism to prevent re-running forward() pass during DECIDE when the
error is already within 1.5° dead zone. Lock is set in EVALUATE when error < 1.5°,
reusing the previous targetAngle in DECIDE. Lock releases on fresh enemy scan or when
error exceeds threshold, eliminating the ±0.9° wobble from input pattern drift.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-15 08:14:28 +02:00
SirStone 8685f0e794 fix(SNNBot): skip learning when aim error < 1.5° (dead zone)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-15 08:10:31 +02:00
SirStone 844abe0bb7 feat(SNNBot): replace bin-based aimer with exemplar kernel regression
Eliminates aim jitter by switching from 360-bin WTA to weighted circular
mean over stored exemplars. Continuous float output, no bins, no
hysteresis, no saturation. K=128 ring buffer, Hamming similarity with
quadratic weighting.
2026-09-15 07:52:32 +02:00
SirStone be032e4ebd feat(SNNBot): replace aim smoothing with bin hysteresis
Smoothing masked jitter, hysteresis removes it at the source.
Gun stays on current bin unless a new bin wins by >1 point.
Removes all EMA/smoothing code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-14 23:28:50 +02:00
SirStone 9cb2727fef feat(SNNBot): distance-adaptive aim smoothing
Far targets need more smoothing (small jitter = big miss at distance).
Close targets need less (fast tracking). Linear ramp α=0.3..0.9 over 0..600 units.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-14 23:25:50 +02:00
SirStone 21c974412c chore(SNNBot): remove SNN graph overlay, keep aiming lines
Deleted neuron panel visualization (input layer, hidden layer neurons, weight lines, output channels) from drawOverlay. Retain aiming lines: enemy bearing (green), gun direction (red), SNN target (yellow).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-14 23:23:42 +02:00
SirStone ac5301acb1 feat(SNNBot): exponential smoothing on aim angle to stop bin-flickering
Adjacent 1° bins have similar scores, causing the winner to flip
tick to tick. Circular EMA (α=0.6) on sin/cos dampens oscillation
while preserving tracking response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-14 23:22:43 +02:00
SirStone e9ddc7673d fix(SNNBot): binary-native input encoding with ~13 active bits
Float population code produced 0-1 active bits after binarization —
not enough to discriminate 72 bins. Replace with direct binary encoding:
5 bits per angular channel (center ± 2 neighbors), 3 bits for speed.
Adjacent bearings share 4/5 bits (smooth); distant bearings share 0
(clean separation). Fix circular error display.
2026-09-14 23:18:10 +02:00
SirStone f70d9e6d1e refactor(SNNBot): replace reservoir with direct binary readout
Delete 1024-neuron reservoir — it added noise, not features.
Direct 80-bit input → 72 output bins via popcount + WTA Hebbian.
Same learning rule (OR reinforce, AND NOT punish), zero indirection.
Reservoir adds value for temporal features (step 3), not now.
2026-09-14 23:13:01 +02:00
SirStone 45b167f2b3 fix(SNNBot): fix reservoir threshold, remove decay, stop re-forward in EVALUATE
- Threshold 4→1: neurons now fire (~50% rate) instead of never firing
- Remove aggressive decay that erased learning signal immediately
- Remove EVALUATE re-forward that corrupted reservoir state before learn()
2026-09-14 23:04:45 +02:00
SirStone dbfb58ca1e feat(SNNBot): add binary reservoir aimer as alternative to SuperSpike (#159)
New architecture: 1024 binary neurons in fixed random reservoir,
72-bin population-coded output, WTA Hebbian learning with binary ops.
Forward pass: AND + popcount. Learning: OR (reinforce) / AND NOT (punish).
No backprop, no floats in hot path. Toggle via USE_RESERVOIR const.

Forecast: ~200-400 ticks to learn stationary target aiming.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-14 23:00:22 +02:00
SirStone 17178158b2 refactor(SNNBot): replace retroactive error with predictive lead target
Delete ring buffer, aim snapshots, maturation loop (~80 lines).
Replace with simple velocity extrapolation: predict enemy position at
bullet impact time, use bearing to predicted position as SuperSpike
target. Immediate error signal every EVALUATE — no delay, no snapshot
state storage. Mathematically equivalent to retroactive for linear movers.
2026-09-14 22:39:28 +02:00
SirStone a78105c894 feat(SNNBot): fire bullets every tick at fixed power
Fire during WAITING phase using FIRE_POWER constant (matches error
signal's bullet speed calculation). Always shooting — fire timing
optimization is out of scope for this map.
2026-09-14 22:30:28 +02:00
SirStone 42b6cebd8e fix(SNNBot): average matured snapshot targets instead of multiple updates
Multiple superSpikeUpdate calls per EVALUATE caused oscillation by
effectively multiplying the learning rate. Now: accumulate retroTarget
via circular mean across all matured snapshots, apply one update with
the averaged target and most recent snapshot's SNN state.
2026-09-14 22:28:41 +02:00
SirStone d5777fba07 fix(SNNBot): apply weight update for every matured snapshot, not just last
Multiple snapshots can mature by EVALUATE time but only the last one
triggered a superSpikeUpdate. Earlier matured snapshots were silently
discarded — wasting learning signal. Now each matured snapshot with a
valid ring buffer hit gets its own weight update.
2026-09-14 22:25:39 +02:00
SirStone a80fd8d656 fix(SNNBot): increase learning rates — ETA 0.05→0.1, ETA_IH 0.005→0.02
Weights were barely moving: |wih| +0.14%, |wOut| +7.7% over full session.
Bump output ETA 2x and input→hidden ETA 4x to accelerate convergence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-14 22:21:29 +02:00
SirStone 80dbf81479 fix(SNNBot): tune SNN hyperparameters for 80-input layer
- Lower THRESH 0.2→0.08 to increase hidden firing rates (output layer was frozen due to rate≈0 in weight updates)
- Add ETA_IH=0.005 for input→hidden updates (10x smaller than output ETA=0.05 to prevent weight thrashing from large preTrace magnitudes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-14 22:16:51 +02:00
SirStone 0ee5c21ef5 fix(SNNBot): store SNN state in aim snapshots for correct retroactive learning
The retroactive error signal matures many ticks after the snapshot was taken,
but superSpikeUpdate was using bot.lastSpikes/lastVSnap which had been
overwritten by subsequent DECIDE cycles. Learning was applied against wrong
neural activity — effectively random weight perturbations.

Fix: AimSnapshot now captures spikes, vSnap, and preTrace at DECIDE time.
superSpikeUpdate receives these saved values at maturation instead of the
stale current state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-14 22:08:22 +02:00
SirStone 5740c56a9f feat(SNNBot): add velocity input encoding and retroactive error signal (#159)
- Expand input layer from 36 to 80 neurons: bearing (0-35) + velocity direction (36-71) + speed (72-79)
- Population-code velocity direction (same 10° band scheme as bearing) and speed (8 bands, 1 unit/tick)
- Compute 1-tick velocity from position deltas in onScannedBot
- Add 100-slot ring buffer with per-slot tick tracking for enemy positions
- Replace instantaneous bearing error with retroactive would-have-hit signal
- Skip learning until first aim snapshot matures (buffer fill period)
- Delayed-target SuperSpike: weight updates use most recently matured retroactive bearing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-14 21:34:59 +02:00
SirStone dbae449273 feat(SNNBot): replace R-STDP with SuperSpike learning rule (#158)
Three-factor local learning: Δw = η × pre_trace × σ'(U) × error
- Surrogate derivative σ'(U) = 1/(1+|β(U-ϑ)|)² gives directional gradient
- Random feedback weights project output error to hidden layer
- 10-tick inference window for rate-coded sin/cos output
- Fixed stale learning target bug (EVALUATE used wrong gun direction)

Hyperparams: ETA=0.05, THRESH=0.2, W_CLAMP=1.0, N_INFER=10, BETA=1.0
Removed: R-STDP eligibility traces, STDP timing window, exploration noise

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-13 20:07:31 +02:00
SirStone 2bfa8eb6a5 feat(SNNBot): add STDP learner and integration test (#153, #155)
- Implement reward-modulated STDP: spike timing, eligibility traces,
  reward-gated weight updates (w += η * reward * trace), clamp [-2,2]
- Add integration smoke test vs SittingDuck (compile + battle completion)
- Add tests/config.nims and nimble test task
2026-09-13 10:31:07 +02:00
SirStone c038128c2f feat(SNNBot): upgrade bot API, fix debug overlay and aiming lines
- Upgrade to robocode_tankroyale_botapi v1.0.7 (SVG viewBox fix)
- Fix Y-axis mirror in aiming line toXY helper
- Resize debug panel to half arena width/height
- Replace neuron boxes with barcode-style spike lines
- Thickness-encoded weight connections (all 216 lines)
- Add aiming line legend (top-left, white text)
- Dynamic aiming line length (distance + 50px overshoot)
2026-09-13 10:24:20 +02:00