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:
@@ -6,6 +6,7 @@ import std/os
|
||||
import std/strutils except fromHex # `fromHex` would clash with color.fromHex
|
||||
import gun_harness/gun_interface
|
||||
import movement_harness/movement_interface
|
||||
import movement_harness/fire_tracker
|
||||
import robocode_tankroyale_botapi/graphics
|
||||
import robocode_tankroyale_botapi/color
|
||||
|
||||
@@ -104,6 +105,9 @@ var
|
||||
TfilCommitTicks*: int = DefaultTfilCommitTicks
|
||||
TfilNoRev*: bool = false
|
||||
TfilCommitLogPath*: string = ""
|
||||
## j134: the shared fire-detection correction (`TR_FIRE_FIX`, default on).
|
||||
## Off = the shipped `prev - energy` detector byte-for-byte.
|
||||
TfilFireFix*: bool = true
|
||||
|
||||
proc getEnvInt(name: string, default: int): int =
|
||||
let s = getEnv(name, "")
|
||||
@@ -132,6 +136,7 @@ proc loadTfilCommitEnv*() =
|
||||
TfilCommitTicks = max(1, getEnvInt("TR_TFIL_COMMIT_TICKS", DefaultTfilCommitTicks))
|
||||
TfilNoRev = getEnvBool("TR_TFIL_NO_REV", false)
|
||||
TfilCommitLogPath = getEnv("TR_TFIL_COMMIT_LOG", "")
|
||||
TfilFireFix = getEnvBool("TR_FIRE_FIX", true)
|
||||
|
||||
loadTfilCommitEnv()
|
||||
|
||||
@@ -243,7 +248,7 @@ type
|
||||
arenaWidth, arenaHeight: float
|
||||
lava: seq[float] # flat row-major, index = row*cols + col
|
||||
bullets: seq[TrackedBullet]
|
||||
prevEnergy: seq[tuple[id: int, energy: float]] # enemy id -> last known energy
|
||||
fire: FireTracker ## shared energy-drop detector (j134)
|
||||
commitTarget: tuple[x, y: float] ## world coords of committed dodge point
|
||||
commitTicks: int ## ticks remaining on commitment
|
||||
commitLava: float ## lava at commit time (for spike detection)
|
||||
@@ -258,7 +263,7 @@ type
|
||||
lastPickCall: int ## callCount at the last pick (log only)
|
||||
picks: int ## number of picks this round (log only)
|
||||
|
||||
proc initTFIL*(): TFILModule = TFILModule(debugGraphics: false)
|
||||
proc initTFIL*(): TFILModule = TFILModule(debugGraphics: false, fire: initFireTracker(TfilFireFix))
|
||||
|
||||
proc removeBulletNear*(m: var TFILModule, x, y: float) =
|
||||
## Mark the tracked bullet closest to (x,y) within GridSize tolerance as dead.
|
||||
@@ -272,17 +277,10 @@ proc removeBulletNear*(m: var TFILModule, x, y: float) =
|
||||
if bestIdx >= 0:
|
||||
m.bullets.del(bestIdx)
|
||||
|
||||
proc prevEnergyGet(m: TFILModule, id: int): float =
|
||||
for e in m.prevEnergy:
|
||||
if e.id == id: return e.energy
|
||||
100.0
|
||||
proc prevEnergyGet(m: TFILModule, id: int): float = m.fire.prevEnergyGet(id)
|
||||
|
||||
proc prevEnergySet(m: var TFILModule, 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 clearGraphics*(m: var TFILModule) =
|
||||
## No-op: the SVG buffer is a module-level global cleared by the framework
|
||||
@@ -291,7 +289,7 @@ proc clearGraphics*(m: var TFILModule) =
|
||||
|
||||
proc resetRound*(m: var TFILModule) =
|
||||
m.bullets = @[]
|
||||
m.prevEnergy = @[]
|
||||
m.fire.reset()
|
||||
m.commitTicks = 0
|
||||
m.cachedHull = @[]
|
||||
m.cachedInsideTiles = @[]
|
||||
@@ -349,30 +347,43 @@ proc initGrid(m: var TFILModule, arenaWidth, arenaHeight: float) =
|
||||
m.arenaHeight = arenaHeight
|
||||
m.lava = newSeq[float](m.cols * m.rows) # all 0.0
|
||||
|
||||
proc spawnTrackedWave(m: var TFILModule, ws: WorldState, ei: EnemyInfo,
|
||||
power: float) =
|
||||
## One tracked bullet/wave for a confirmed fire of `power`: linear prediction
|
||||
## of our position at arrival becomes the aim heading. (Was inlined in
|
||||
## `detectFires`; extracted so the shared split can spawn several.)
|
||||
let speed = 20.0 - 3.0 * power
|
||||
let dist = sqrt((ws.selfX - ei.x)^2 + (ws.selfY - ei.y)^2)
|
||||
let travelTime = dist / speed
|
||||
let predX = ws.selfX + ws.selfSpeed * cos(ws.selfHeading * PI / 180.0) * travelTime
|
||||
let predY = ws.selfY + ws.selfSpeed * sin(ws.selfHeading * PI / 180.0) * travelTime
|
||||
let heading = arctan2(predY - ei.y, predX - ei.x)
|
||||
if m.bullets.len >= MaxTrackedBullets:
|
||||
m.bullets.del(0) # ponytail: drop oldest; fine for 20-bullet cap
|
||||
m.bullets.add TrackedBullet(
|
||||
originX: ei.x, originY: ei.y,
|
||||
x: ei.x, y: ei.y,
|
||||
velX: speed * cos(heading),
|
||||
velY: speed * sin(heading),
|
||||
power: power,
|
||||
alive: true,
|
||||
age: 0)
|
||||
|
||||
proc noteEnemyBulletHit*(m: var TFILModule, power: float) =
|
||||
## `onHitByBullet` -> the shooter's `3*power` bonus (no-op when off).
|
||||
m.fire.noteEnemyBulletHit(power)
|
||||
|
||||
proc noteDamageDealt*(m: var TFILModule, damage: float) =
|
||||
## `onBulletHit` -> our same-tick damage to the enemy (no-op when off).
|
||||
m.fire.noteDamageDealt(damage)
|
||||
|
||||
proc detectFires(m: var TFILModule, ws: WorldState) =
|
||||
## Check all enemies for energy drops; spawn a tracked bullet per confirmed fire.
|
||||
## Check all enemies for energy drops; spawn a tracked bullet per confirmed
|
||||
## fire. The shared tracker corrects the delta and splits over-cap drops.
|
||||
for ei in ws.enemies:
|
||||
let prev = m.prevEnergyGet(ei.id)
|
||||
let drop = prev - ei.energy
|
||||
m.prevEnergySet(ei.id, ei.energy)
|
||||
if drop >= 0.09 and drop <= 3.01:
|
||||
let speed = 20.0 - 3.0 * drop
|
||||
# Linear prediction: aim at where we will be when the bullet arrives
|
||||
let dist = sqrt((ws.selfX - ei.x)^2 + (ws.selfY - ei.y)^2)
|
||||
let travelTime = dist / speed
|
||||
let predX = ws.selfX + ws.selfSpeed * cos(ws.selfHeading * PI / 180.0) * travelTime
|
||||
let predY = ws.selfY + ws.selfSpeed * sin(ws.selfHeading * PI / 180.0) * travelTime
|
||||
let heading = arctan2(predY - ei.y, predX - ei.x)
|
||||
if m.bullets.len >= MaxTrackedBullets:
|
||||
m.bullets.del(0) # ponytail: drop oldest; fine for 20-bullet cap
|
||||
m.bullets.add TrackedBullet(
|
||||
originX: ei.x, originY: ei.y,
|
||||
x: ei.x, y: ei.y,
|
||||
velX: speed * cos(heading),
|
||||
velY: speed * sin(heading),
|
||||
power: drop,
|
||||
alive: true,
|
||||
age: 0)
|
||||
for p in m.fire.detect(ei.id, ei.energy, 0.09, 3.01):
|
||||
m.spawnTrackedWave(ws, ei, p)
|
||||
m.fire.endScan()
|
||||
|
||||
proc advanceBullets(m: var TFILModule, selfX, selfY: float) =
|
||||
## Advance positions and reap bullets that are: passed us, out of bounds, or too old.
|
||||
@@ -519,9 +530,9 @@ proc computeMove*(m: var TFILModule, ws: WorldState): MoveCommand =
|
||||
m.bullets = @[] # bullet positions are hopelessly stale
|
||||
m.blockedTile = (col: 0, row: 0, active: false)
|
||||
# Re-snapshot prevEnergy so energy changes during ramming aren't misread as fires
|
||||
m.prevEnergy = @[]
|
||||
m.fire.prevEnergy = @[]
|
||||
for ei in ws.enemies:
|
||||
m.prevEnergySet(ei.id, ei.energy)
|
||||
m.fire.prevEnergySet(ei.id, ei.energy)
|
||||
|
||||
# Tile-change replan — see the knob rationale at the top of the file.
|
||||
if (not jumped) and (m.callCount > 0) and (m.commitTicks > 0):
|
||||
|
||||
Reference in New Issue
Block a user