From b31d1bf99ff16dabb1badc61e81acfcbe03dd93a Mon Sep 17 00:00:00 2001 From: Davide Cappellini Date: Thu, 17 Sep 2026 22:24:52 +0200 Subject: [PATCH] simplify(BNNBot): raw 10-bit binary encoding, clean output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace population/thermometer/signed-thermometer encoding with simple 10-bit binary per value - 5 values × 10 bits = 50 bits total (was 112) - Each value normalized to 0-1023, then bit-extracted MSB-first - Output is now just tick and raw binary string (no field labels, no debug log) - Remove file logging entirely; stdout only Co-Authored-By: Claude Opus 4.6 --- BNNBot_garage/src/BNNBot.nim | 25 +---- BNNBot_garage/src/binary_encoding.nim | 133 ++++++-------------------- 2 files changed, 32 insertions(+), 126 deletions(-) diff --git a/BNNBot_garage/src/BNNBot.nim b/BNNBot_garage/src/BNNBot.nim index 9555b79..8c301c3 100644 --- a/BNNBot_garage/src/BNNBot.nim +++ b/BNNBot_garage/src/BNNBot.nim @@ -1,22 +1,13 @@ # BNNBot — binary encoding data collector. -# Radar lock on enemy, converts each scan to a 112-bit BinaryVector, logs + prints it. +# Radar lock on enemy, converts each scan to a 50-bit BinaryVector, prints it. # No aiming, no firing — pure scan visualization for BNN research. -import std/[math, strformat, os] +import std/[math, os] import robocode_tankroyale_botapi import radar_lock/radar_lock as radar_lock import binary_encoding const botJsonPath = currentSourcePath().parentDir / "BNNBot.json" -const scanLog = "/tmp/bnnbot_scan.log" - -proc appendLog(s: string) = - try: - let f = open(scanLog, fmAppend) - f.writeLine(s) - f.close() - except: - discard type BNNBot = ref object of Bot @@ -53,10 +44,7 @@ method onScannedBot*(bot: BNNBot, e: ScannedBotEvent) = speed: bot.speed, ) let vec = encode(scan) - let fmt = formatBinary(vec) - let line = fmt"t={bot.tick} bear={bot.enemyBearing:.1f} dist={bot.distance:.0f} vel={bot.velocity:.2f} head={bot.heading:.1f} spd={bot.speed:.2f} pop={popcount(vec)} {fmt}" - echo line - appendLog(line) + echo $bot.tick, " ", formatBinary(vec) method onRoundStarted*(bot: BNNBot, e: RoundStartedEvent) = setAdjustGunForBodyTurn(true) @@ -70,12 +58,7 @@ method onRoundStarted*(bot: BNNBot, e: RoundStartedEvent) = setTurnRate(0.0) method onGameStarted*(bot: BNNBot, e: GameStartedEventForBot) = - # Truncate log on game start - try: - let f = open(scanLog, fmWrite) - f.close() - except: - discard + discard method run*(bot: BNNBot) = while isRunning(): diff --git a/BNNBot_garage/src/binary_encoding.nim b/BNNBot_garage/src/binary_encoding.nim index 458e03e..19db837 100644 --- a/BNNBot_garage/src/binary_encoding.nim +++ b/BNNBot_garage/src/binary_encoding.nim @@ -1,127 +1,50 @@ -## binary_encoding — scan data → binary vector for BNNBot. -## Encoding scheme: -## bearing/heading: population code (2 adjacent bits, triangular interpolation) -## distance/speed: thermometer (all bits below threshold active) -## velocity: signed thermometer (first half = negative, second half = positive) +## binary_encoding — scan data → binary vector (10-bit per value). import std/math const - BEARING_BITS* = 36 # 360° / 10° per bit - DISTANCE_BITS* = 16 # 0-2000 units, ~125 per bit (thermometer) - VELOCITY_BITS* = 16 # -8 to +8, signed thermometer - HEADING_BITS* = 36 # 360° / 10° per bit - SPEED_BITS* = 8 # 0-8, 1 per bit (thermometer) - TOTAL_BITS* = BEARING_BITS + DISTANCE_BITS + VELOCITY_BITS + HEADING_BITS + SPEED_BITS # 112 + BITS_PER_VALUE* = 10 + NUM_VALUES* = 5 + TOTAL_BITS* = BITS_PER_VALUE * NUM_VALUES # 50 type - BinaryVector* = array[TOTAL_BITS, uint8] # 0 or 1 + BinaryVector* = array[TOTAL_BITS, uint8] ScanData* = object - bearing*: float # absolute bearing to enemy (degrees) - distance*: float # distance to enemy - velocity*: float # enemy velocity (negative = moving backward) - heading*: float # enemy heading (degrees) - speed*: float # enemy speed (always positive) + bearing*: float # 0-360 + distance*: float # 0-2000 + velocity*: float # -8 to +8 + heading*: float # 0-360 + speed*: float # 0-8 -proc encodeBearing*(degrees: float, bits: int): seq[uint8] = - ## Population code: 2 adjacent bits active via triangular interpolation. - result = newSeq[uint8](bits) - let norm = ((degrees mod 360.0) + 360.0) mod 360.0 - let bandWidth = 360.0 / float(bits) - let idx = norm / bandWidth - let lo = int(idx) mod bits - let hi = (lo + 1) mod bits - result[lo] = 1 - result[hi] = 1 - -proc encodeThermometer*(value, minVal, maxVal: float, bits: int): seq[uint8] = - ## Thermometer code: all bits below threshold are 1. - result = newSeq[uint8](bits) +proc toBits(value: float, minVal, maxVal: float): array[BITS_PER_VALUE, uint8] = let clamped = clamp(value, minVal, maxVal) let norm = (clamped - minVal) / (maxVal - minVal) - let active = int(norm * float(bits)) - for i in 0..= 0: - let norm = clamped / maxAbs - let active = int(norm * float(halfBits)) - for i in 0..