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:
@@ -82,9 +82,10 @@
|
||||
## 10.0 / 15.0; the comment now says so.
|
||||
|
||||
import std/[math, random, os, strformat]
|
||||
from std/strutils import parseFloat, strip # selective: strutils.fromHex clashes with color.fromHex
|
||||
from std/strutils import parseFloat, strip, toLowerAscii # selective: strutils.fromHex clashes 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
|
||||
|
||||
@@ -128,6 +129,18 @@ proc getEnvFloat(name: string, default: float): float =
|
||||
except ValueError:
|
||||
result = default
|
||||
|
||||
proc getEnvBool(name: string, default: bool): bool =
|
||||
let s = getEnv(name, "").strip().toLowerAscii()
|
||||
if s.len == 0: return default
|
||||
s in ["1", "true", "on", "yes"]
|
||||
|
||||
## j134: the shared fire-detection correction (`TR_FIRE_FIX`, default on).
|
||||
## Off = the shipped `prev - energy` detector byte-for-byte.
|
||||
var TfilRingFireFix* = true
|
||||
proc loadTfilRingFireEnv*() =
|
||||
TfilRingFireFix = getEnvBool("TR_FIRE_FIX", true)
|
||||
loadTfilRingFireEnv()
|
||||
|
||||
const
|
||||
DefaultRangeLo = 100.0
|
||||
DefaultRangeHi = 200.0
|
||||
@@ -223,7 +236,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)
|
||||
@@ -241,7 +254,8 @@ type
|
||||
loggedOnce: bool
|
||||
|
||||
proc initTFILRing*(): TFILRingModule =
|
||||
TFILRingModule(debugGraphics: false, band: (lo: RangeLo, hi: RangeHi))
|
||||
TFILRingModule(debugGraphics: false, band: (lo: RangeLo, hi: RangeHi),
|
||||
fire: initFireTracker(TfilRingFireFix))
|
||||
|
||||
proc removeBulletNear*(m: var TFILRingModule, x, y: float) =
|
||||
## Mark the tracked bullet closest to (x,y) within GridSize tolerance as dead.
|
||||
@@ -255,17 +269,10 @@ proc removeBulletNear*(m: var TFILRingModule, x, y: float) =
|
||||
if bestIdx >= 0:
|
||||
m.bullets.del(bestIdx)
|
||||
|
||||
proc prevEnergyGet(m: TFILRingModule, id: int): float =
|
||||
for e in m.prevEnergy:
|
||||
if e.id == id: return e.energy
|
||||
100.0
|
||||
proc prevEnergyGet(m: TFILRingModule, id: int): float = m.fire.prevEnergyGet(id)
|
||||
|
||||
proc prevEnergySet(m: var TFILRingModule, 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 TFILRingModule) =
|
||||
## No-op: the SVG buffer is a module-level global cleared by the framework
|
||||
@@ -274,7 +281,7 @@ proc clearGraphics*(m: var TFILRingModule) =
|
||||
|
||||
proc resetRound*(m: var TFILRingModule) =
|
||||
m.bullets = @[]
|
||||
m.prevEnergy = @[]
|
||||
m.fire.reset()
|
||||
m.commitTicks = 0
|
||||
m.cachedHull = @[]
|
||||
m.cachedInsideTiles = @[]
|
||||
@@ -299,30 +306,42 @@ proc initGrid(m: var TFILRingModule, arenaWidth, arenaHeight: float) =
|
||||
m.arenaHeight = arenaHeight
|
||||
m.lava = newSeq[float](m.cols * m.rows) # all 0.0
|
||||
|
||||
proc spawnTrackedWave(m: var TFILRingModule, ws: WorldState, ei: EnemyInfo,
|
||||
power: float) =
|
||||
## One tracked bullet/wave for a confirmed fire of `power` (extracted from
|
||||
## `detectFires` 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 TFILRingModule, power: float) =
|
||||
## `onHitByBullet` -> the shooter's `3*power` bonus (no-op when off).
|
||||
m.fire.noteEnemyBulletHit(power)
|
||||
|
||||
proc noteDamageDealt*(m: var TFILRingModule, damage: float) =
|
||||
## `onBulletHit` -> our same-tick damage to the enemy (no-op when off).
|
||||
m.fire.noteDamageDealt(damage)
|
||||
|
||||
proc detectFires(m: var TFILRingModule, 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 TFILRingModule, selfX, selfY: float) =
|
||||
## Advance positions and reap bullets that are: passed us, out of bounds, or too old.
|
||||
@@ -456,9 +475,9 @@ proc computeMove*(m: var TFILRingModule, 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: catches gradual displacement that position threshold misses
|
||||
if (not jumped) and (m.callCount > 0) and (m.commitTicks > 0):
|
||||
|
||||
Reference in New Issue
Block a user