j134 fire fix: share ONE fire_tracker across tfil/ring/strafe/learned/surf (TR_FIRE_FIX, default on); env-gated TR_FIRE_DIAG alignment trace
This commit is contained in:
@@ -50,6 +50,7 @@ import std/[math, os]
|
||||
from std/strutils import parseFloat, strip, toLowerAscii
|
||||
import gun_harness/gun_interface
|
||||
import movement_harness/movement_interface
|
||||
import movement_harness/fire_tracker
|
||||
|
||||
const
|
||||
WS_BINS = 31
|
||||
@@ -76,6 +77,9 @@ var
|
||||
SurfWallMargin* = DefaultWallMargin
|
||||
SurfRadialFrac* = DefaultRadialFrac
|
||||
SurfLog* = false
|
||||
## j134: the shared fire-detection correction (`TR_FIRE_FIX`, default on).
|
||||
## Off = the shipped `prev - energy` detector byte-for-byte.
|
||||
SurfFireFix* = true
|
||||
|
||||
proc getEnvFloat(name: string, default: float): float =
|
||||
let s = getEnv(name, "")
|
||||
@@ -83,6 +87,11 @@ proc getEnvFloat(name: string, default: float): float =
|
||||
try: result = parseFloat(s.strip())
|
||||
except ValueError: result = default
|
||||
|
||||
proc envOn(name: string, default = false): bool =
|
||||
let s = getEnv(name, "").strip().toLowerAscii()
|
||||
if s.len == 0: return default
|
||||
s notin ["0", "false", "no", "off"]
|
||||
|
||||
proc loadSurfEnv*() =
|
||||
## Read the surfer knobs; callable again after `putEnv` so a gate can
|
||||
## exercise arms in one process.
|
||||
@@ -91,6 +100,7 @@ proc loadSurfEnv*() =
|
||||
SurfWallMargin = max(0.0, getEnvFloat(SurfWallMarginEnv, DefaultWallMargin))
|
||||
SurfRadialFrac = clamp(getEnvFloat(SurfRadialFracEnv, DefaultRadialFrac), 0.0, 1.0)
|
||||
SurfLog = existsEnv(SurfLogEnv)
|
||||
SurfFireFix = envOn("TR_FIRE_FIX", true)
|
||||
|
||||
loadSurfEnv()
|
||||
|
||||
@@ -106,7 +116,7 @@ type
|
||||
WaveSurferModule* = object
|
||||
bins: array[WS_BINS, float64]
|
||||
waves: seq[WSWave]
|
||||
prevEnergy: seq[tuple[id: int, energy: float]]
|
||||
fire: FireTracker ## shared energy-drop detector (j134)
|
||||
strafeDir: float64 ## +1.0 or -1.0
|
||||
debugGraphics*: bool
|
||||
|
||||
@@ -114,12 +124,12 @@ proc resetRound*(m: var WaveSurferModule) =
|
||||
## Wipe per-round state. The danger histogram IS reset here (defect 2): it is
|
||||
## a per-round learner, not a battle-long static average.
|
||||
m.waves = @[]
|
||||
m.prevEnergy = @[]
|
||||
m.fire.reset()
|
||||
m.strafeDir = 1.0
|
||||
for i in 0..<WS_BINS: m.bins[i] = 1.0
|
||||
|
||||
proc initWaveSurfer*(): WaveSurferModule =
|
||||
var m = WaveSurferModule(debugGraphics: false)
|
||||
var m = WaveSurferModule(debugGraphics: false, fire: initFireTracker(SurfFireFix))
|
||||
m.resetRound()
|
||||
m
|
||||
|
||||
@@ -132,17 +142,18 @@ proc removeBulletNear*(m: var WaveSurferModule, x, y: float) {.inline.} =
|
||||
## No-op: the surfer tracks WAVES (energy drops), not bullet bodies.
|
||||
discard
|
||||
|
||||
proc prevEnergyGet(m: WaveSurferModule, id: int): float =
|
||||
for e in m.prevEnergy:
|
||||
if e.id == id: return e.energy
|
||||
100.0
|
||||
proc prevEnergyGet(m: WaveSurferModule, id: int): float = m.fire.prevEnergyGet(id)
|
||||
|
||||
proc prevEnergySet(m: var WaveSurferModule, id: int, energy: float) =
|
||||
for i in 0..<m.prevEnergy.len:
|
||||
if m.prevEnergy[i].id == id:
|
||||
m.prevEnergy[i].energy = energy
|
||||
return
|
||||
m.prevEnergy.add((id: id, energy: energy))
|
||||
m.fire.prevEnergySet(id, energy)
|
||||
|
||||
proc noteEnemyBulletHit*(m: var WaveSurferModule, power: float) =
|
||||
## `onHitByBullet` -> the shooter's `3*power` bonus (no-op when off).
|
||||
m.fire.noteEnemyBulletHit(power)
|
||||
|
||||
proc noteDamageDealt*(m: var WaveSurferModule, damage: float) =
|
||||
## `onBulletHit` -> our same-tick damage to the enemy (no-op when off).
|
||||
m.fire.noteDamageDealt(damage)
|
||||
|
||||
proc gfToBin(gf: float64): int {.inline.} =
|
||||
clamp(int(round((gf.clamp(-1.0, 1.0) + 1.0) * 0.5 * float64(WS_BINS - 1))),
|
||||
@@ -176,13 +187,12 @@ proc nearestWave(m: WaveSurferModule, botX, botY: float64): int =
|
||||
|
||||
proc detectFire(m: var WaveSurferModule, id: int, ex, ey, eenergy,
|
||||
botX, botY: float64) =
|
||||
## One enemy's energy sample: emit a wave iff its energy dropped by a
|
||||
## plausible firepower in one tick. `drop` is the firepower exactly.
|
||||
let prev = m.prevEnergyGet(id)
|
||||
let drop = prev - eenergy
|
||||
m.prevEnergySet(id, eenergy)
|
||||
if drop >= 0.1 and drop <= 3.0:
|
||||
let bspeed = 20.0 - 3.0 * drop
|
||||
## One enemy's energy sample: emit a wave per plausible firepower in the
|
||||
## (corrected) one-tick drop. `drop` IS the firepower. Window 0.1..3.0,
|
||||
## SURF's shipped window; the shared tracker corrects the delta and splits an
|
||||
## over-cap drop across several waves.
|
||||
for power in m.fire.detect(id, eenergy, 0.1, 3.0):
|
||||
let bspeed = 20.0 - 3.0 * power
|
||||
let bearing = arctan2(botY - ey, botX - ex)
|
||||
let d = hypot(botX - ex, botY - ey)
|
||||
m.waves.add WSWave(
|
||||
@@ -191,7 +201,7 @@ proc detectFire(m: var WaveSurferModule, id: int, ex, ey, eenergy,
|
||||
speed: bspeed,
|
||||
radius: 0.0,
|
||||
startDist: d,
|
||||
power: drop,
|
||||
power: power,
|
||||
)
|
||||
|
||||
proc computeMove*(m: var WaveSurferModule, ws: WorldState): MoveCommand =
|
||||
@@ -206,6 +216,7 @@ proc computeMove*(m: var WaveSurferModule, ws: WorldState): MoveCommand =
|
||||
if seen == 0 and (ws.enemyX != 0.0 or ws.enemyY != 0.0):
|
||||
# Fallback to the tracked target when `enemies` is empty.
|
||||
m.detectFire(-1, ws.enemyX, ws.enemyY, ws.enemyEnergy, botX, botY)
|
||||
m.fire.endScan()
|
||||
|
||||
# ── Advance waves; record the GF of each wave that reaches us ─────────────
|
||||
var i = 0
|
||||
|
||||
Reference in New Issue
Block a user