Files
SirRoboGarage/SNNBot_garage/research/existing-lead-code.md
T

5.8 KiB
Raw Blame History

Existing Lead-Targeting & Enemy Tracking Code

Scope: all garages in SirRoboGarage as of research/lead-targeting branch.


Summary

No lead-targeting (bullet-travel-time prediction, fire-ahead calculation) exists anywhere in the repo. What does exist is well-factored enemy tracking, lateral-speed measurement, and a bullet-speed constant — all the primitives needed to implement lead targeting.


1. Enemy Tracker (PPO_Bot_garage)

File: PPO_Bot_garage/src/PPO_Bot/enemy_tracker.nim

The richest tracker in the repo. Provides:

Feature Detail
EnemyState x, y, direction, speed, energy, ticksSinceLastScan, hasFired, lastFirePower
History ring array[5, (x, y, direction, speed)] — sliding window of last 5 scan positions
update() Called on ScannedBotEvent; detects enemy fire from energy delta in [0.1, 3.0]
deadReckon() Projects position forward one tick using last known speed+direction
getRadarTurnRate() Width-lock with overshoot arctan(36/dist)

No lead angle calculation. History gives velocity vectors; deadReckon gives 1-tick projection; but there is no travelTime = dist / bulletSpeed loop or atan2(lateral, forward) computation.


2. Bullet Speed Formula

Files: PPO_Bot_garage/src/PPO_Bot/state_vector.nim (line 109) and SAC_LSTM_Bot_garage/src/SAC_LSTM_Bot/state.nim (line 105)

Both independently define:

let bSpeed = 20.0 - 3.0 * b.power  # Tank Royale bullet speed formula

This is the authoritative formula. It appears in two garages but only for computing ticksToImpact from the bullet's current position for the state vector (dodge context), not for predicting where to aim before firing.


3. Lateral Speed Measurement (QBot_garage)

File: QBot_garage/src/QBot.nim (lines 100–105, 335–336)

# lateralSpeed: enemy velocity component perpendicular to our line of sight
let lateralSpeed = bot.enemySpeed * sin(degToRad(bot.enemyDir - bearingToEnemy))

QBot discretizes this into 4 bins (N_LAT_SPD = 4) as a state feature, then learns Q-values for aim offsets [-12, -6, -3, 0, 3, 6, 12] degrees. This is the closest thing to lead targeting in the repo: it captures why you'd lead, but the lead angle itself is picked by the Q-table, not calculated analytically.


4. In-Flight Bullet Tracking (PPO_Bot_garage)

File: PPO_Bot_garage/src/PPO_Bot.nim (lines 70–74, 215–258)

PPO_Bot tracks enemy bullets in flight using a fixed array[4, InFlightBullet] (no heap). Each bullet has (x, y, vx, vy, power) and is advanced each tick. Used to populate the dodge-context slots in the state vector. No lead-targeting use.


5. State Vectors with Enemy History

PPO_Bot (PPO_Bot_garage/src/PPO_Bot/state_vector.nim)

  • 57-float tensor
  • Indices 22–41: 5-tick history window (x, y, direction, speed per tick)
  • Indices 44–55: up to 3 enemy bullets (relX, relY, speed, ticksToImpact)

SAC_LSTM_Bot (SAC_LSTM_Bot_garage/src/SAC_LSTM_Bot/state.nim)

  • 35-float tensor
  • No explicit history window (LSTM handles temporal context)
  • Indices 22–33: up to 3 enemy bullets
  • Has prevSpeed, prevDirection on EnemyData for one-step acceleration/turn-rate

6. SNNBot (SNNBot_garage/src/SNNBot.nim)

Tracks only:

  • enemyBearing (absolute, from last ScannedBotEvent)
  • enemyDist
  • hasContact

No velocity, no history, no position tracking. The SNN input is population-coded relative bearing only. No lead targeting.


7. QBot (QBot_garage/src/QBot.nim)

Tracks enemyX, enemyY, enemyDir, enemySpeed, hasContact, ticksSinceScan. Uses a 5-slot array[BULLET_BUF_CAP, BulletRecord] ring buffer for associating Q-updates to bullet outcomes (hit/wall). This is a reward attribution ring buffer, not a position history.


8. OscillatorBot (garage + adversary copy)

Files: OscillatorBot_garage/src/OscillatorBot.nim, common_libs/test_framework/adversaries/OscillatorBot/src/OscillatorBot.nim

Head-on targeting only: aims gun directly at directionTo(myX, myY, e.x, e.y). No lead. Both files are identical.


9. Targeting Utilities

File: PPO_Bot_garage/src/PPO_Bot/controllers.nim

proc aimToTick*(targetX, targetY, botX, botY, gunDirection: float): float

Rotates gun toward a target point (clamped to ±MAX_GUN_TURN_RATE). Used by PPO_Bot via an (x,y) target the network chooses. No lead calculation inside — caller must provide the predicted impact point if desired.

File: common_libs/radar_lock/radar_lock.nim

proc doRadar*(currentRadarHeading, enemyBearing: float64): float64

Width-lock with configurable overshoot (DefaultOvershootDeg = 5.0). Used by QBot, SNNBot, and the PPO_Bot tracker's getRadarTurnRate.


10. Adversaries in common_libs/test_framework/adversaries/

Only two adversaries exist:

Bot Behavior
SittingDuck Does nothing (stationary target)
OscillatorBot Zigzag (±4°/tick turn, speed 7, reverses every 25 ticks), head-on gun

No wall-bot, no spinner, no circler adversary.


Reuse Opportunities for SNNBot Lead Targeting

Need Reuse from
Enemy velocity (x, y, speed, dir) EnemyTracker from PPO_Bot_garage/src/PPO_Bot/enemy_tracker.nim — drop-in, no bot API deps
Position history Same: 5-slot array, pre-filled on cold-start
Bullet speed formula bSpeed = 20.0 - 3.0 * power (inline constant, no import needed)
Radar lock common_libs/radar_lock/radar_lock.nim — already used by SNNBot
Gun turn to point aimToTick in PPO_Bot_garage/src/PPO_Bot/controllers.nim (or inline)

The missing piece — the iterative lead-angle solver (for t in 0..20: if dist(predicted_pos(t), bullet_pos(t)) < eps: break) — does not exist anywhere in the repo and would need to be written.