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:
@@ -84,6 +84,7 @@ import std/[math, os]
|
||||
from std/strutils import parseFloat, parseInt, strip, toLowerAscii
|
||||
import gun_harness/gun_interface
|
||||
import movement_harness/movement_interface
|
||||
import movement_harness/fire_tracker
|
||||
import bitbrain/sbc
|
||||
|
||||
const
|
||||
@@ -163,6 +164,9 @@ var
|
||||
LearnedLabel* = llHistogram
|
||||
LearnedRealEvents* = false
|
||||
LearnedLog* = false
|
||||
## j134: the shared fire-detection correction (`TR_FIRE_FIX`, default on).
|
||||
## Off = the shipped `prev - energy` detector byte-for-byte.
|
||||
LearnedFireFix* = true
|
||||
|
||||
proc getEnvFloat(name: string, default: float): float =
|
||||
let s = getEnv(name, "")
|
||||
@@ -195,6 +199,7 @@ proc loadLearnedEnv*() =
|
||||
LearnedWallMargin = max(0.0, getEnvFloat(LearnedWallMarginEnv, 48.0))
|
||||
LearnedGlobal = envOn(LearnedGlobalEnv)
|
||||
LearnedRealEvents = envOn(LearnedRealEventsEnv)
|
||||
LearnedFireFix = envOn("TR_FIRE_FIX", true)
|
||||
LearnedLog = envOn(LearnedLogEnv)
|
||||
LearnedLabel =
|
||||
case getEnv(LearnedLabelEnv, "").strip().toLowerAscii()
|
||||
@@ -272,7 +277,7 @@ type
|
||||
missGlobal: int ## llOutcome: non-hits seen (for the prior)
|
||||
scores: seq[float]
|
||||
waves: seq[LSWave]
|
||||
prevEnergy: seq[tuple[id: int, energy: float]]
|
||||
fire: FireTracker ## shared energy-drop detector (j134)
|
||||
strafeDir: float64
|
||||
dir: float64 ## direction commanded last tick (+-1)
|
||||
prevX, prevY: float64 ## our position one tick ago
|
||||
@@ -290,7 +295,7 @@ proc resetRound*(m: var LearnedSurferModule) =
|
||||
## it survives a round boundary without becoming a battle-long static average
|
||||
## (the j115 defect). Use `resetBattle` for a hard wipe.
|
||||
m.waves = @[]
|
||||
m.prevEnergy = @[]
|
||||
m.fire.reset()
|
||||
m.strafeDir = 1.0
|
||||
m.dir = 1.0
|
||||
m.prevX = 0.0
|
||||
@@ -307,6 +312,7 @@ proc resetRound*(m: var LearnedSurferModule) =
|
||||
|
||||
proc initLearnedSurfer*(): LearnedSurferModule =
|
||||
result.debugGraphics = false
|
||||
result.fire = initFireTracker(LearnedFireFix)
|
||||
result.sbc = initCountedSbc(LS_NADE, LS_BINS,
|
||||
max(0, LearnedDecayEvery),
|
||||
max(0, LearnedDecayShift))
|
||||
@@ -485,58 +491,57 @@ proc predictState*(m: var LearnedSurferModule, row, col: int,
|
||||
|
||||
# ── fire detection + state ──────────────────────────────────────────────────
|
||||
|
||||
proc prevEnergyGet(m: LearnedSurferModule, id: int): float =
|
||||
for e in m.prevEnergy:
|
||||
if e.id == id: return e.energy
|
||||
100.0
|
||||
proc prevEnergyGet(m: LearnedSurferModule, id: int): float = m.fire.prevEnergyGet(id)
|
||||
|
||||
proc prevEnergySet(m: var LearnedSurferModule, 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 LearnedSurferModule, power: float) =
|
||||
## `onHitByBullet` -> the shooter's `3*power` bonus (no-op when off).
|
||||
m.fire.noteEnemyBulletHit(power)
|
||||
|
||||
proc noteDamageDealt*(m: var LearnedSurferModule, damage: float) =
|
||||
## `onBulletHit` -> our same-tick damage to the enemy (no-op when off).
|
||||
m.fire.noteDamageDealt(damage)
|
||||
|
||||
proc detectFire(m: var LearnedSurferModule, id: int, ex, ey, eenergy: float,
|
||||
ws: WorldState) =
|
||||
## One enemy's energy sample. A plausible one-tick firepower drop IS a wave;
|
||||
## the state is the wave-relative state at THIS tick (the fire tick).
|
||||
let prev = m.prevEnergyGet(id)
|
||||
let drop = prev - eenergy
|
||||
m.prevEnergySet(id, eenergy)
|
||||
if drop < 0.09 or drop > 3.01: return
|
||||
## One enemy's energy sample. A plausible (corrected) one-tick firepower
|
||||
## drop IS a wave; the state is the wave-relative state at THIS tick (the
|
||||
## fire tick). Window 0.09..3.01, LEARNED's shipped window; the shared
|
||||
## tracker corrects the delta and splits an over-cap drop across waves.
|
||||
for drop in m.fire.detect(id, eenergy, 0.09, 3.01):
|
||||
let botX = ws.selfX
|
||||
let botY = ws.selfY
|
||||
let bspeed = 20.0 - 3.0 * drop
|
||||
let d = hypot(botX - ex, botY - ey)
|
||||
let bearing = arctan2(botY - ey, botX - ex) # centre line
|
||||
let ux = cos(bearing)
|
||||
let uy = sin(bearing)
|
||||
|
||||
let botX = ws.selfX
|
||||
let botY = ws.selfY
|
||||
let bspeed = 20.0 - 3.0 * drop
|
||||
let d = hypot(botX - ex, botY - ey)
|
||||
let bearing = arctan2(botY - ey, botX - ex) # centre line
|
||||
let ux = cos(bearing)
|
||||
let uy = sin(bearing)
|
||||
# vlat: lateral velocity in the wave frame. The centre line passes through us
|
||||
# at this tick, so lat(now) == 0 and vlat == -lat(prev).
|
||||
let dxp = m.prevX - ex
|
||||
let dyp = m.prevY - ey
|
||||
var vlat = -(dxp * (-uy) + dyp * ux)
|
||||
if m.prevX == 0.0 and m.prevY == 0.0 and m.prevHeading == 0.0: vlat = 0.0
|
||||
let roomDx = if vlat >= 0.0: -uy else: uy
|
||||
let roomDy = if vlat >= 0.0: ux else: -ux
|
||||
let room = roomToWall(botX, botY, roomDx, roomDy, ws.arenaWidth, ws.arenaHeight)
|
||||
let turn = wrap180(float(ws.selfHeading) - float(m.prevHeading))
|
||||
|
||||
# vlat: lateral velocity in the wave frame. The centre line passes through us
|
||||
# at this tick, so lat(now) == 0 and vlat == -lat(prev).
|
||||
let dxp = m.prevX - ex
|
||||
let dyp = m.prevY - ey
|
||||
var vlat = -(dxp * (-uy) + dyp * ux)
|
||||
if m.prevX == 0.0 and m.prevY == 0.0 and m.prevHeading == 0.0: vlat = 0.0
|
||||
let roomDx = if vlat >= 0.0: -uy else: uy
|
||||
let roomDy = if vlat >= 0.0: ux else: -ux
|
||||
let room = roomToWall(botX, botY, roomDx, roomDy, ws.arenaWidth, ws.arenaHeight)
|
||||
let turn = wrap180(float(ws.selfHeading) - float(m.prevHeading))
|
||||
let row = code(vlat, VlatEdges) * LS_Q + code(d, DistEdges)
|
||||
let col = code(room, RoomEdges) * LS_Q + code(turn, TurnEdges)
|
||||
|
||||
let row = code(vlat, VlatEdges) * LS_Q + code(d, DistEdges)
|
||||
let col = code(room, RoomEdges) * LS_Q + code(turn, TurnEdges)
|
||||
|
||||
m.waves.add LSWave(
|
||||
ownerId: id, fireTick: ws.tick,
|
||||
originX: ex, originY: ey, bearing: bearing, speed: bspeed,
|
||||
startDist: d, power: drop,
|
||||
ticksLeft: max(1, int(ceil(d / max(bspeed, 1e-9)))),
|
||||
fresh: true,
|
||||
selfEnergyAtFire: ws.selfEnergy,
|
||||
stateRow: row, stateCol: col,
|
||||
)
|
||||
m.waves.add LSWave(
|
||||
ownerId: id, fireTick: ws.tick,
|
||||
originX: ex, originY: ey, bearing: bearing, speed: bspeed,
|
||||
startDist: d, power: drop,
|
||||
ticksLeft: max(1, int(ceil(d / max(bspeed, 1e-9)))),
|
||||
fresh: true,
|
||||
selfEnergyAtFire: ws.selfEnergy,
|
||||
stateRow: row, stateCol: col,
|
||||
)
|
||||
|
||||
# ── the mover ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -551,6 +556,7 @@ proc computeMove*(m: var LearnedSurferModule, ws: WorldState): MoveCommand =
|
||||
m.detectFire(ei.id, ei.x, ei.y, ei.energy, ws)
|
||||
if seen == 0 and (ws.enemyX != 0.0 or ws.enemyY != 0.0):
|
||||
m.detectFire(-1, ws.enemyX, ws.enemyY, ws.enemyEnergy, ws)
|
||||
m.fire.endScan()
|
||||
|
||||
# ── 2. advance + resolve waves; every resolution is a training sample ────
|
||||
var i = 0
|
||||
|
||||
Reference in New Issue
Block a user