feat(BNNBot): 44-bit encoding with sin/cos bearing+heading, distance%, velocity
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
# BNNBot — binary encoding data collector.
|
||||
# Radar lock on enemy, converts each scan to a 50-bit BinaryVector, prints it.
|
||||
# Radar lock on enemy, converts each scan to a 44-bit BinaryVector, prints it.
|
||||
# No aiming, no firing — pure scan visualization for BNN research.
|
||||
|
||||
import std/[math, os]
|
||||
@@ -18,7 +18,6 @@ type
|
||||
hasLastPos: bool
|
||||
velocity: float # signed velocity (from heading + speed)
|
||||
heading: float # enemy heading (degrees)
|
||||
speed: float # enemy speed (units/tick)
|
||||
distance: float
|
||||
tick: int
|
||||
|
||||
@@ -27,7 +26,6 @@ method onScannedBot*(bot: BNNBot, e: ScannedBotEvent) =
|
||||
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
|
||||
@@ -41,7 +39,6 @@ method onScannedBot*(bot: BNNBot, e: ScannedBotEvent) =
|
||||
distance: bot.distance,
|
||||
velocity: bot.velocity,
|
||||
heading: bot.heading,
|
||||
speed: bot.speed,
|
||||
)
|
||||
let vec = encode(scan)
|
||||
echo $bot.tick, " ", formatBinary(vec)
|
||||
|
||||
@@ -1,42 +1,61 @@
|
||||
## binary_encoding — scan data → binary vector (10-bit per value).
|
||||
|
||||
import std/math
|
||||
|
||||
const
|
||||
BITS_PER_VALUE* = 10
|
||||
NUM_VALUES* = 5
|
||||
TOTAL_BITS* = BITS_PER_VALUE * NUM_VALUES # 50
|
||||
TOTAL_BITS* = 44
|
||||
|
||||
type
|
||||
BinaryVector* = array[TOTAL_BITS, uint8]
|
||||
|
||||
ScanData* = object
|
||||
bearing*: float # 0-360
|
||||
distance*: float # 0-2000
|
||||
velocity*: float # -8 to +8
|
||||
heading*: float # 0-360
|
||||
speed*: float # 0-8
|
||||
bearing*: float # 0-360 degrees
|
||||
distance*: float # 0-1414 pixels (will be converted to 0-100%)
|
||||
velocity*: float # -8 to +8 integer steps
|
||||
heading*: float # 0-360 degrees
|
||||
|
||||
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 intVal = int(norm * 1023.0) # 0-1023 fits in 10 bits
|
||||
for i in 0..<BITS_PER_VALUE:
|
||||
result[BITS_PER_VALUE - 1 - i] = uint8((intVal shr i) and 1) # MSB first
|
||||
const MAX_DISTANCE = 1414.0 # diagonal of 1000x1000 arena
|
||||
|
||||
proc toBits(value: int, bits: int): seq[uint8] =
|
||||
result = newSeq[uint8](bits)
|
||||
for i in 0..<bits:
|
||||
result[bits - 1 - i] = uint8((value shr i) and 1)
|
||||
|
||||
proc encode*(scan: ScanData): BinaryVector =
|
||||
let parts = [
|
||||
toBits(scan.bearing, 0.0, 360.0),
|
||||
toBits(scan.distance, 0.0, 2000.0),
|
||||
toBits(scan.velocity, -8.0, 8.0),
|
||||
toBits(scan.heading, 0.0, 360.0),
|
||||
toBits(scan.speed, 0.0, 8.0)
|
||||
]
|
||||
var offset = 0
|
||||
for p in parts:
|
||||
for i in 0..<BITS_PER_VALUE:
|
||||
result[offset + i] = p[i]
|
||||
offset += BITS_PER_VALUE
|
||||
|
||||
# 1. bearing_sin: sin(bearing), -1..+1 → 0..199 → 8 bits
|
||||
let bSin = int((sin(degToRad(scan.bearing)) + 1.0) / 2.0 * 199.0)
|
||||
let bSinBits = toBits(clamp(bSin, 0, 199), 8)
|
||||
for i in 0..<8: result[offset + i] = bSinBits[i]
|
||||
offset += 8
|
||||
|
||||
# 2. bearing_cos: cos(bearing), -1..+1 → 0..199 → 8 bits
|
||||
let bCos = int((cos(degToRad(scan.bearing)) + 1.0) / 2.0 * 199.0)
|
||||
let bCosBits = toBits(clamp(bCos, 0, 199), 8)
|
||||
for i in 0..<8: result[offset + i] = bCosBits[i]
|
||||
offset += 8
|
||||
|
||||
# 3. distance %: 0-100% of max → 0..99 → 7 bits
|
||||
let distPct = int(clamp(scan.distance / MAX_DISTANCE * 99.0, 0.0, 99.0))
|
||||
let distBits = toBits(distPct, 7)
|
||||
for i in 0..<7: result[offset + i] = distBits[i]
|
||||
offset += 7
|
||||
|
||||
# 4. velocity: -8..+8 → 0..16 → 5 bits
|
||||
let vel = int(clamp(scan.velocity + 8.0, 0.0, 16.0))
|
||||
let velBits = toBits(vel, 5)
|
||||
for i in 0..<5: result[offset + i] = velBits[i]
|
||||
offset += 5
|
||||
|
||||
# 5. heading_sin: sin(heading), -1..+1 → 0..199 → 8 bits
|
||||
let hSin = int((sin(degToRad(scan.heading)) + 1.0) / 2.0 * 199.0)
|
||||
let hSinBits = toBits(clamp(hSin, 0, 199), 8)
|
||||
for i in 0..<8: result[offset + i] = hSinBits[i]
|
||||
offset += 8
|
||||
|
||||
# 6. heading_cos: cos(heading), -1..+1 → 0..199 → 8 bits
|
||||
let hCos = int((cos(degToRad(scan.heading)) + 1.0) / 2.0 * 199.0)
|
||||
let hCosBits = toBits(clamp(hCos, 0, 199), 8)
|
||||
for i in 0..<8: result[offset + i] = hCosBits[i]
|
||||
|
||||
proc formatBinary*(vec: BinaryVector): string =
|
||||
for b in vec:
|
||||
|
||||
Reference in New Issue
Block a user