From d5777fba071a88cee3b062bfc2e6e30bb5099c77 Mon Sep 17 00:00:00 2001 From: Davide Cappellini Date: Mon, 14 Sep 2026 22:25:39 +0200 Subject: [PATCH] fix(SNNBot): apply weight update for every matured snapshot, not just last MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- SNNBot_garage/src/SNNBot.nim | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/SNNBot_garage/src/SNNBot.nim b/SNNBot_garage/src/SNNBot.nim index 04763be..65ae93c 100644 --- a/SNNBot_garage/src/SNNBot.nim +++ b/SNNBot_garage/src/SNNBot.nim @@ -464,13 +464,9 @@ method run*(bot: SNNBot) = # Retroactive would-have-hit error signal: find the most recently matured snapshot. # A snapshot matures when currentTick >= snapshotTick + ceil(distance / BULLET_SPEED). # Look up enemy position at impact tick from ring buffer (offset from most-recent write). - var retroTarget = bot.lastRelBearing # fallback (unused if no matured snapshot) + var retroTarget = bot.lastRelBearing # fallback; overwritten by each matured snapshot (last one used for logging) var hasMatured = false var keepIdx = 0 # first non-matured snapshot to keep - # matureSnap holds the last matured snapshot's SNN state for the weight update. - var matureSpikes: array[N_HID, float] - var matureVSnap: array[N_HID, float] - var maturePreTrace: array[N_IN, float] for i in 0 ..< bot.snapshots.len: let snap = bot.snapshots[i] let travelTicks = int(ceil(snap.distance / BULLET_SPEED)) @@ -487,11 +483,10 @@ method run*(bot: SNNBot) = let ex = bot.posBuf[foundSlot].x let ey = bot.posBuf[foundSlot].y let absBearing = directionTo(snap.botX, snap.botY, ex, ey) - retroTarget = normalizeRelativeAngle(absBearing - snap.gunHeading) - matureSpikes = snap.spikes - matureVSnap = snap.vSnap - maturePreTrace = snap.preTrace - hasMatured = true + retroTarget = normalizeRelativeAngle(absBearing - snap.gunHeading) + # Update weights for every matured snapshot immediately; earlier ones were previously discarded. + bot.snn.superSpikeUpdate(snap.spikes, snap.vSnap, snap.preTrace, retroTarget) + hasMatured = true keepIdx = i + 1 # discard matured snapshots up to and including this one else: break # snapshots are in order; stop at first non-matured @@ -499,10 +494,6 @@ method run*(bot: SNNBot) = # or points past the last matured entry; the rest of bot.snapshots is kept intact). if keepIdx > 0: bot.snapshots = bot.snapshots[keepIdx .. ^1] - if hasMatured: - # Use SNN state captured at DECIDE time — not the stale bot.lastSpikes/lastVSnap - # which have been overwritten by subsequent DECIDE cycles. - bot.snn.superSpikeUpdate(matureSpikes, matureVSnap, maturePreTrace, retroTarget) # else: skip weight update — no matured snapshot yet (early game) # Compute verbose logging metrics var spikeCount = 0