diff --git a/SNNBot_garage/src/SNNBot.nim b/SNNBot_garage/src/SNNBot.nim index 34cb810..99f7f25 100644 --- a/SNNBot_garage/src/SNNBot.nim +++ b/SNNBot_garage/src/SNNBot.nim @@ -460,9 +460,12 @@ method run*(bot: SNNBot) = let absBearing = directionTo(myX, myY, futureX, futureY) let targetRel = normalizeRelativeAngle(absBearing - bot.lastDecideGunDir) when USE_RESERVOIR: - let winBin = bot.res.forward(toBitVec80(encodeInputFull( - normalizeRelativeAngle(bot.enemyBearing - bot.lastDecideGunDir), - bot.velDirDeg, bot.velSpeed, bot.hasLastPos))) + # state/scores already set by DECIDE's forward(); re-forwarding would corrupt them + let winBin = block: + var best = 0; var bestS = -1 + for k in 0 ..< N_BINS: + if bot.res.scores[k] > bestS: bestS = bot.res.scores[k]; best = k + best let aimAngle = bot.res.interpolatedAngle(winBin) bot.res.learn(targetRel) echo "RES tick=" & $bot.tick & " bin=" & $winBin & diff --git a/SNNBot_garage/src/reservoir.nim b/SNNBot_garage/src/reservoir.nim index 06c5cb6..f78f5e6 100644 --- a/SNNBot_garage/src/reservoir.nim +++ b/SNNBot_garage/src/reservoir.nim @@ -47,12 +47,6 @@ proc sparseBits(r: var Reservoir, density: float): uint64 = if r.nextRand() < thresh: result = result or (1'u64 shl bit) -proc randomDecayMask(r: var Reservoir): uint64 = - ## ~1% bits set: AND 6 random words (1/2^6 = 1/64 ≈ 1.5% density). - result = r.nextRand() - for _ in 0 ..< 5: - result = result and r.nextRand() - # ── Init ─────────────────────────────────────────────────────────────────────── proc initReservoir*(seed: int): Reservoir = @@ -67,13 +61,8 @@ proc initReservoir*(seed: int): Reservoir = for w in 0 ..< 16: result.wRec[i][w] = sparseBits(result, SPARSITY_REC) - let inPop = popcount(result.wIn[i][0]) + popcount(result.wIn[i][1]) - let recPop = block: - var s = 0 - for w in 0 ..< 16: s += popcount(result.wRec[i][w]) - s - # Threshold: ~50% of expected input votes + ~30% of expected recurrent votes - result.threshold[i] = max(1, int(float(inPop) * 0.5 + float(recPop) * 0.3)) + # ponytail: threshold=1 gives ~50% firing; raise if reservoir saturates (all neurons fire every tick) + result.threshold[i] = 1 # readout and state are zero-initialized by default @@ -158,7 +147,4 @@ proc learn*(r: var Reservoir, correctAngle: float) = for w in 0 ..< 16: r.readout[worstBin][w] = r.readout[worstBin][w] and (not r.state[w]) - # Decay: clear ~1.5% of bits per bin to prevent saturation - for k in 0 ..< N_BINS: - for w in 0 ..< 16: - r.readout[k][w] = r.readout[k][w] and (not randomDecayMask(r)) + # ponytail: decay removed; add back if readout weights saturate (all scores converge to same value)