diff --git a/SNNBot_garage/src/SNNBot.nim b/SNNBot_garage/src/SNNBot.nim index 05f2dbf..4115626 100644 --- a/SNNBot_garage/src/SNNBot.nim +++ b/SNNBot_garage/src/SNNBot.nim @@ -380,12 +380,38 @@ method onGameStarted*(bot: SNNBot, e: GameStartedEventForBot) = # ── Reservoir helpers ───────────────────────────────────────────────────────── -proc toBitVec80(inputs: array[N_IN, float]): BitVec80 = +proc toBinaryInput(bearing: float, velDir: float, velSpeed: float, hasVel: bool): BitVec80 = + ## Binary-native encoding: ~5 bits per channel, ~13 total active bits result = [0'u64, 0'u64] - for i in 0 ..< N_IN: - if inputs[i] > 0.5: - let word = i div 64 - let bit = i mod 64 + + # Bearing: bits 0-35 (36 bits, 10° bands) + # Activate center band + 2 neighbors on each side = 5 bits + let bNorm = (bearing + 180.0) / 10.0 # 0..36 + let bCenter = int(bNorm) mod 36 + for offset in -2 .. 2: + let idx = (bCenter + offset + 36) mod 36 + let word = idx div 64 + let bit = idx mod 64 + result[word] = result[word] or (1'u64 shl bit) + + if hasVel: + # Velocity direction: bits 36-71 (36 bits, 10° bands) + # Same scheme: 5 bits active + let vNorm = (velDir + 180.0) / 10.0 + let vCenter = int(vNorm) mod 36 + for offset in -2 .. 2: + let idx = 36 + (vCenter + offset + 36) mod 36 + let word = idx div 64 + let bit = idx mod 64 + result[word] = result[word] or (1'u64 shl bit) + + # Speed: bits 72-79 (8 bits, 1 unit/tick bands) + # Activate center + 1 neighbor on each side = 3 bits + let sCenter = clamp(int(velSpeed), 0, 7) + for offset in -1 .. 1: + let idx = 72 + clamp(sCenter + offset, 0, 7) + let word = idx div 64 + let bit = idx mod 64 result[word] = result[word] or (1'u64 shl bit) # ── Main loop ───────────────────────────────────────────────────────────────── @@ -409,9 +435,8 @@ method run*(bot: SNNBot) = of DECIDE: let relBearing = normalizeRelativeAngle(bot.enemyBearing - gunDir) bot.lastRelBearing = relBearing - let inputs = encodeInputFull(relBearing, bot.velDirDeg, bot.velSpeed, bot.hasLastPos) when USE_RESERVOIR: - let binInput = toBitVec80(inputs) + let binInput = toBinaryInput(relBearing, bot.velDirDeg, bot.velSpeed, bot.hasLastPos) let winBin = bot.res.forward(binInput) let aimAngle = bot.res.interpolatedAngle(winBin) bot.lastBinInput = binInput @@ -419,6 +444,7 @@ method run*(bot: SNNBot) = bot.lastDecideGunDir = gunDir echo "RES tick=" & $bot.tick & " bin=" & $winBin & " aim=" & formatFloat(aimAngle, ffDecimal, 1) else: + let inputs = encodeInputFull(relBearing, bot.velDirDeg, bot.velSpeed, bot.hasLastPos) # Multi-tick inference: accumulate sin/cos and spike counts over N_INFER ticks var totalSin = 0.0; var totalCos = 0.0 var tickSpikes: array[N_HID, float] @@ -477,7 +503,7 @@ method run*(bot: SNNBot) = echo "RES tick=" & $bot.tick & " bin=" & $winBin & " aim=" & formatFloat(aimAngle, ffDecimal, 1) & " target=" & formatFloat(targetRel, ffDecimal, 1) & - " err=" & formatFloat(abs(aimAngle - targetRel), ffDecimal, 1) & + " err=" & formatFloat(abs(normalizeRelativeAngle(aimAngle - targetRel)), ffDecimal, 1) & " readout_pop_correct=" & $readoutPopCorrect else: let err = abs(normalizeRelativeAngle(gunDir - bot.enemyBearing))