From 23bdf8acd60243d5ec4a8734b8ed5ade8859c39c Mon Sep 17 00:00:00 2001 From: Davide Cappellini Date: Sun, 13 Sep 2026 20:30:10 +0200 Subject: [PATCH] research(SNNBot): survey existing lead-targeting and enemy tracking code Co-Authored-By: Claude Sonnet 4.6 --- SNNBot_garage/research/existing-lead-code.md | 169 +++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 SNNBot_garage/research/existing-lead-code.md diff --git a/SNNBot_garage/research/existing-lead-code.md b/SNNBot_garage/research/existing-lead-code.md new file mode 100644 index 0000000..823b63f --- /dev/null +++ b/SNNBot_garage/research/existing-lead-code.md @@ -0,0 +1,169 @@ +# 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.