feat(ModularBot): KNN gun, gunheat tracker, bullet shadows — inspired by DrussGT
New DrussGT-inspired modules: - KNNGun: K-nearest-neighbor statistical targeting using GF density peaks - GunheatTracker: dual-heat system (predicted + confirmed) for 1-2 tick lead - ShadowTracker: computes GF regions safe from in-flight bullets (enemy wave dodge) VirtualBodyTracker now integrates gunheat for earlier fire detection and shadows for safe-zone multiplier (90% reduction in danger zones). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
## Gunheat wave prediction — mirrors DrussGT's enemyGunHeat / imaginaryGunHeat pattern.
|
||||
## Tracks two heat values:
|
||||
## confirmedHeat — reset from actual energy-drop fire detections
|
||||
## predictedHeat — reset speculatively when enemy COULD fire (heat near 0)
|
||||
## This lets us create a "predicted" wave 1-2 ticks before energy drop confirms it.
|
||||
##
|
||||
## Gun cooling rate in Tank Royale: 0.1/tick.
|
||||
## Initial gun heat at round start: 3.0 → first possible fire at tick 30.
|
||||
|
||||
import std/math
|
||||
import gun_harness/gun_interface
|
||||
|
||||
const
|
||||
GunCoolingRate* = 0.1
|
||||
InitialGunHeat* = 3.0
|
||||
|
||||
type
|
||||
WaveEventKind* = enum
|
||||
wePredicted ## enemy CAN fire this tick (heat just reached 0)
|
||||
weConfirmed ## energy drop confirmed a fire last tick
|
||||
|
||||
WaveEvent* = object
|
||||
kind*: WaveEventKind
|
||||
fireX*, fireY*: float ## enemy position at (predicted/confirmed) fire time
|
||||
bulletPower*: float
|
||||
tick*: int
|
||||
|
||||
GunheatTracker* = object
|
||||
confirmedHeat*: float ## heat from last confirmed fire (energy drop)
|
||||
predictedHeat*: float ## heat from last predicted fire (imaginary wave)
|
||||
prevEnemyEnergy*: float
|
||||
canFireTick*: int ## tick when enemy next confirmed able to fire
|
||||
|
||||
proc initGunheatTracker*(): GunheatTracker =
|
||||
result.confirmedHeat = InitialGunHeat
|
||||
result.predictedHeat = InitialGunHeat
|
||||
result.prevEnemyEnergy = 100.0
|
||||
result.canFireTick = -1
|
||||
|
||||
proc resetRound*(gt: var GunheatTracker) =
|
||||
gt.confirmedHeat = InitialGunHeat
|
||||
gt.predictedHeat = InitialGunHeat
|
||||
gt.prevEnemyEnergy = 100.0
|
||||
gt.canFireTick = -1
|
||||
|
||||
proc tick*(gt: var GunheatTracker, state: WorldState): seq[WaveEvent] =
|
||||
## Call once per tick with current world state.
|
||||
## Returns any wave events created this tick (0, 1, or 2 entries).
|
||||
|
||||
# Cool both heat values
|
||||
gt.confirmedHeat = max(0.0, gt.confirmedHeat - GunCoolingRate)
|
||||
gt.predictedHeat = max(gt.confirmedHeat, gt.predictedHeat - GunCoolingRate)
|
||||
|
||||
# Check energy drop for confirmed fire (fired last tick)
|
||||
let drop = gt.prevEnemyEnergy - state.enemyEnergy
|
||||
gt.prevEnemyEnergy = state.enemyEnergy
|
||||
|
||||
if drop >= 0.1 and drop <= 3.0 and gt.confirmedHeat == 0.0:
|
||||
let power = drop
|
||||
# ponytail: subtract one coolingRate because they fired last tick, not this tick
|
||||
gt.confirmedHeat = 1.0 + power / 5.0 - GunCoolingRate
|
||||
gt.predictedHeat = gt.confirmedHeat
|
||||
gt.canFireTick = state.tick
|
||||
result.add WaveEvent(
|
||||
kind: weConfirmed,
|
||||
fireX: state.enemyX,
|
||||
fireY: state.enemyY,
|
||||
bulletPower: power,
|
||||
tick: state.tick,
|
||||
)
|
||||
|
||||
# Predicted wave: confirmedHeat just reached 0 AND no confirmed fire this tick
|
||||
elif gt.confirmedHeat == 0.0 and gt.predictedHeat == 0.0:
|
||||
# Enemy CAN fire. Guess power = 2.0 (sensible default, caller can override).
|
||||
# ponytail: flat prior on power; upgrade to BulletPowerPredictor if needed
|
||||
let guessedPower = 2.0
|
||||
gt.predictedHeat = 1.0 + guessedPower / 5.0 + GunCoolingRate # +cooling: fire next tick
|
||||
gt.canFireTick = state.tick
|
||||
result.add WaveEvent(
|
||||
kind: wePredicted,
|
||||
fireX: state.enemyX,
|
||||
fireY: state.enemyY,
|
||||
bulletPower: guessedPower,
|
||||
tick: state.tick,
|
||||
)
|
||||
Reference in New Issue
Block a user