# BNNBot Research Brief ## Problem Predict enemy future position in Robocode Tank Royale to aim bullets accurately. The prediction must happen online (during battle), without pre-training. ## Hard Constraints - NO supervised learning (no labeled input→output training pairs) - NO gradient descent (no derivatives, no surrogate gradients, no STE) - Online learning only — must learn and improve during a single battle - Computational budget: ~1ms per tick - Binary-friendly (690-bit input encoding already exists) ## Allowed - Backpropagation of SIGNALS (non-gradient information flowing backward through layers) - Reinforcement learning (reward signal available from wave hit system) - Self-supervised learning - Unsupervised learning - Network structure modification during runtime ## Current Architecture ### Input Engineering (binary_encoding.nim) - 690-bit binary vector: 10 frames × 69 bits - Per frame: bearing sin/cos (16b), distance (7b), velocity (5b), heading sin/cos (16b), enemy X/Y position (14b), enemy energy (11b) - Gray-coded for Hamming distance smoothness - Temporal window: 10 most recent radar scans ### Feedback System (wave system in BNNBot.nim) - Every tick: 10 circular waves spawned at bot position - Powers: 0.1 to 3.0 (10 levels), speeds: 19.7 to 11.0 px/tick - When wave radius reaches enemy: records enemy state as 69-bit frame - Provides ground truth: "if you fired at power X, the enemy would be HERE when the bullet arrives" - ~95.6% hit rate in testing ### Current Predictor (predictor.nim) - Linear extrapolation: predicted = current_pos + velocity * ticks_to_arrival - Hebbian residual table: 8 heading sectors × 3 distance bands = 24 cells - Each cell stores (correction_x, correction_y), updated online with lr=0.2 - Backtest results: 14-21% MAE reduction over pure linear extrapolation - Converges within one battle (MAE 14.85 → 2.62, first 50 vs last 50 rows) ## Key Findings ### Data Analysis (analysis/report.txt) - Enemy movement is 97.8% constant-velocity straight lines - Acceleration is negligible (std 0.25-0.49 px/tick²) - Heading is very stable across 10-frame windows - Linear extrapolation MAE: 15-27px (1.5-2.7% of arena) - Distance to enemy is the main error driver - Scalar velocity alone is weak predictor (r=0.15); directional velocity from frame deltas is strong ### Backtest Results (analysis/backtest_report.txt) - P1 (linear): MAE 8.1-18.7 encoded units - P2 (weighted 4-frame): ~8% improvement, trivial cost - P3 (linear + Hebbian residual): 14-21% improvement, converges fast - Most residual table cells stay empty — only ~10/24 activate ### Encoding Insights - sin/cos angle encoding avoids wraparound discontinuity — worth the extra bits - Enemy X/Y position partially redundant with bearing+distance (encodes absolute position) - Wall distance → XY% compression saved 140 bits losslessly - Self-state removed (not needed for aiming) ## What We've Tried 1. ✅ Input engineering with Gray coding and temporal window — works well 2. ✅ Linear extrapolation — strong baseline, 15-27px error 3. ✅ Hebbian residual table — learns online, 14-21% improvement 4. ❌ Pure XOR layer stacking — collapses (associative, no non-linearity) 5. ❌ XOR + AND layers — AND with fixed mask is still linear over GF(2) 6. ✅ XOR + popcount + threshold = valid binary neuron (non-linear) ## Open Questions 1. Can we go deeper than the current shallow predictor while respecting the constraints? 2. What non-gradient learning rules can train multi-layer binary networks? 3. Can the temporal structure (10 frames) be exploited by the network architecture? 4. Is there a way to do credit assignment through depth without gradients? 5. Can the wave hit system provide richer learning signal than just miss distance? ## Architecture Philosophy - Input engineering IS the feature hierarchy (handcrafted, domain-informed) - Current approach is essentially reservoir computing: rich fixed features → simple learnable readout - Question: can we do better with a learnable feature extractor, or is the handcrafted one already near-optimal? ## Files - `src/BNNBot.nim` — main bot, wave system, integration - `src/binary_encoding.nim` — 690-bit input encoding - `src/predictor.nim` — linear extrapolation + Hebbian residual table - `analysis/correlations.py` — data analysis script - `analysis/backtest.py` — predictor comparison script - `analysis/report.txt` — correlation analysis results - `analysis/backtest_report.txt` — predictor backtest results - `data/` — CSV battle logs (enabled via BNNBOT_CSV=1)