Files
SirRoboGarage/BNNBot_garage/src/predictor.nim
T
SirStone 254c7dc997 feat(ModularBot): pluggable bot with 4 guns, phantom meteor movement, radar harness
- Gun harness: virtual bullet tracker, rolling fitness, auto-selector
- Guns: head-on, linear (extrapolation), circular (integrated formula), tsetlin machine (learning)
- Movement: phantom meteor gravity engine (danger histograms, phantom bullets, fire detection)
- Radar: harness + radar_lock adapter
- Color-coded modules: turret/bullet color per gun, body per movement, scan per radar
- Beats Target, SpinBot, Crazy, TrackFire in 10-round battles
2026-09-20 00:37:10 +02:00

51 lines
1.7 KiB
Nim

import std/math
import binary_encoding
const
N_SECTORS = 8
N_BANDS = 3
LEARNING_RATE = 0.2
BAND_THR_LO = 33.0
BAND_THR_HI = 66.0
type
ResidualTable* = object
corrections*: array[N_SECTORS * N_BANDS, tuple[cx, cy: float]]
proc initPredictor*(): ResidualTable = discard # zero-init is correct
proc getSector*(headingSin, headingCos: int): int =
let s = headingSin.float / 199.0 * 2.0 - 1.0
let c = headingCos.float / 199.0 * 2.0 - 1.0
var deg = radToDeg(arctan2(s, c))
if deg < 0.0: deg += 360.0
int(deg / 45.0) mod N_SECTORS
proc getBand*(distance: int): int =
if distance.float < BAND_THR_LO: 0
elif distance.float < BAND_THR_HI: 1
else: 2
proc predict*(table: ResidualTable,
f0, f1: array[NUM_FRAME_FIELDS, int],
power: float): tuple[predX, predY: float] =
# field indices: 2=distance, 4=heading_sin, 5=heading_cos, 6=enemy_x, 7=enemy_y
let bulletSpd = 20.0 - 3.0 * power
let distancePx = f0[2].float / 99.0 * 1414.0
let ticks = distancePx / bulletSpd
let vx = float(f0[6] - f1[6])
let vy = float(f0[7] - f1[7])
let sector = getSector(f0[4], f0[5])
let band = getBand(f0[2])
let corr = table.corrections[sector * N_BANDS + band]
result.predX = f0[6].float + vx * ticks + corr.cx
result.predY = f0[7].float + vy * ticks + corr.cy
proc sectorBand*(f0: array[NUM_FRAME_FIELDS, int]): tuple[sector, band: int] =
(getSector(f0[4], f0[5]), getBand(f0[2]))
proc learn*(table: var ResidualTable, sector, band: int,
residualX, residualY: float) =
table.corrections[sector * N_BANDS + band].cx += LEARNING_RATE * residualX
table.corrections[sector * N_BANDS + band].cy += LEARNING_RATE * residualY