feat(BNNBot): scaffold binary neural network bot with scan data collection and binary encoding visualization

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 22:15:51 +02:00
parent 85005c1c27
commit 808ae44703
7 changed files with 254 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
# BNNBot — binary encoding data collector.
# Radar lock on enemy, converts each scan to a 112-bit BinaryVector, logs + prints it.
# No aiming, no firing — pure scan visualization for BNN research.
import std/[math, strformat, 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
hasContact: bool
enemyBearing: float
lastEnemyX: float
lastEnemyY: float
hasLastPos: bool
velocity: float # signed velocity (from heading + speed)
heading: float # enemy heading (degrees)
speed: float # enemy speed (units/tick)
distance: float
tick: int
method onScannedBot*(bot: BNNBot, e: ScannedBotEvent) =
let bx = getX(); let by = getY()
bot.enemyBearing = directionTo(bx, by, e.x, e.y)
bot.distance = distanceTo(bx, by, e.x, e.y)
bot.heading = e.direction
bot.speed = abs(e.speed)
bot.velocity = e.speed # signed: positive = forward, negative = reverse
if bot.hasLastPos:
discard # velocity from e.speed is more accurate; position delta kept for future use
bot.lastEnemyX = e.x
bot.lastEnemyY = e.y
bot.hasLastPos = true
bot.hasContact = true
let scan = ScanData(
bearing: bot.enemyBearing,
distance: bot.distance,
velocity: bot.velocity,
heading: bot.heading,
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)
method onRoundStarted*(bot: BNNBot, e: RoundStartedEvent) =
setAdjustGunForBodyTurn(true)
setAdjustRadarForBodyTurn(true)
setAdjustRadarForGunTurn(true)
radar_lock.init()
bot.hasContact = false
bot.hasLastPos = false
bot.tick = 0
setTargetSpeed(0.0)
setTurnRate(0.0)
method onGameStarted*(bot: BNNBot, e: GameStartedEventForBot) =
# Truncate log on game start
try:
let f = open(scanLog, fmWrite)
f.close()
except:
discard
method run*(bot: BNNBot) =
while isRunning():
inc bot.tick
setTargetSpeed(0.0)
setTurnRate(0.0)
if not bot.hasContact:
setRadarTurnRate(45.0)
go()
continue
setRadarTurnRate(radar_lock.doRadar(getRadarDirection(), bot.enemyBearing))
go()
when isMainModule:
var bot = BNNBot()
start(bot, botJsonPath)