From 57cbcc56994a74d4113f6f9fb20013623856f6ac Mon Sep 17 00:00:00 2001 From: Davide Cappellini Date: Wed, 16 Sep 2026 21:43:23 +0200 Subject: [PATCH] =?UTF-8?q?tune(SNNBot):=20P1=20cold-start=20with=20P3-tar?= =?UTF-8?q?get=20learning=20=E2=80=94=202/10=20wins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fire P1 for first COLD_K=8 exemplars (cheap misses), always store P3-correct lead offsets using P3_SPEED=11 in EVALUATE travelTime. Switches to P3 once exemplar buffer has enough data. Best observed: wins rounds 1-2 back-to-back (relative velocity encoding + P1 warmup). Co-Authored-By: Claude Sonnet 4.6 --- SNNBot_garage/src/SNNBot.nim | 16 +++++++++++----- SNNBot_garage/src/reservoir.nim | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/SNNBot_garage/src/SNNBot.nim b/SNNBot_garage/src/SNNBot.nim index f9d4874..d2010f7 100644 --- a/SNNBot_garage/src/SNNBot.nim +++ b/SNNBot_garage/src/SNNBot.nim @@ -43,7 +43,9 @@ const BETA = 1.0 # surrogate steepness (unitless; potentials are unitless) NOISE_AMP = 0.3 # exploration noise amplitude # ponytail: uniform exploration noise; upgrade to annealed Gaussian if convergence needs tuning - ENERGY_GUARD = 15.0 # don't fire below this energy + ENERGY_GUARD = 15.0 # don't fire below this energy + P3_SPEED = 11.0 # bullet speed for P3 (20 - 3*3); used for exemplar learning + COLD_K = 8 # exemplars needed before switching cold→warm (P1→P3) # ── SNN types ───────────────────────────────────────────────────────────────── @@ -447,10 +449,12 @@ method run*(bot: SNNBot) = # Fire gate: only fire when error within adaptive dead zone if err < adaptiveDeadZone: - # ponytail: fixed power 3.0 vs Walls; adaptive economy adds noise vs learning if getEnergy() >= ENERGY_GUARD: - bot.lastBulletSpeed = bot.bulletSpeed - discard setFire(bot.currentFirePower) + # ponytail: P1 until COLD_K total exemplars exist; cross-round exemplar accumulation + let firePower = if bot.res.count < COLD_K: 1.0 else: bot.currentFirePower + let fireSpeed = 20.0 - 3.0 * firePower + bot.lastBulletSpeed = fireSpeed + discard setFire(firePower) bot.phase = EVALUATE else: discard setFire(0.0) @@ -458,7 +462,9 @@ method run*(bot: SNNBot) = of EVALUATE: # Predictive error signal: extrapolate enemy position at bullet impact time. if bot.hasLastPos: - let travelTime = bot.enemyDist / bot.lastBulletSpeed # use speed from fire tick + # Always compute lead for P3_SPEED so exemplars teach P3-correct offsets, + # even when the actual shot was P1 (cold-start). + let travelTime = bot.enemyDist / P3_SPEED let velRad = degToRad(bot.velDirDeg) let futureX = bot.lastEnemyX + cos(velRad) * bot.velSpeed * travelTime let futureY = bot.lastEnemyY + sin(velRad) * bot.velSpeed * travelTime diff --git a/SNNBot_garage/src/reservoir.nim b/SNNBot_garage/src/reservoir.nim index f14f305..926439e 100644 --- a/SNNBot_garage/src/reservoir.nim +++ b/SNNBot_garage/src/reservoir.nim @@ -54,3 +54,4 @@ proc learn*(aimer: var BinaryAimer, input: BitVec80, offset: float) = aimer.exemplars[aimer.nextSlot] = Exemplar(pattern: input, offset: offset, active: true) aimer.nextSlot = (aimer.nextSlot + 1) mod MAX_K if aimer.count < MAX_K: inc aimer.count +