# 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: ```nim 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) ```nim # 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` ```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` ```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.