diff --git a/common_libs/guns/guess_factor.nim b/common_libs/guns/guess_factor.nim index 43fac7d..93dee1d 100644 --- a/common_libs/guns/guess_factor.nim +++ b/common_libs/guns/guess_factor.nim @@ -2,18 +2,19 @@ ## Bins: 31, ranging GF -1 (max CW escape) to +1 (max CCW escape). ## Learns from virtual bullet outcomes; caches wave state per-tick. -import std/math +import std/[math, strformat] import gun_harness/gun_interface const - GFBins = 31 - GFPrior = 0.1 + GFBins = 31 + GFPrior = 0.1 + DebugGF* = false type Wave = object fireX, fireY: float fireBearing: float # atan2(enemyY-selfY, enemyX-selfX) at fire tick (rad) - mea: float # max escape angle (rad) + # mea not stored — recomputed from FeedbackEvent.bulletPower at resolution time GFGun* = object bins: array[GFBins, float] @@ -24,8 +25,12 @@ type proc initGFGun*(): GFGun = result.cachedTick = -1 + # Seed with a head-on prior: triangular bump at bin 15 (GF=0). + # Prevents the cold-start tie-break to GF=-1 (bin 0) that poisons early fitness. + let center = (GFBins - 1) div 2 # = 15 for i in 0.. PI: bearingDelta -= 2.0*PI while bearingDelta < -PI: bearingDelta += 2.0*PI - let gf = if w.mea > 1e-10: clamp(bearingDelta / w.mea, -1.0, 1.0) else: 0.0 + let gf = if mea > 1e-10: clamp(bearingDelta / mea, -1.0, 1.0) else: 0.0 let centerIdx = gfToIndex(gf) + when DebugGF: + echo fmt"[gf-dbg] onResult: fireBearing={radToDeg(w.fireBearing):.1f}° actualBearing={radToDeg(actualBearing):.1f}° delta={radToDeg(bearingDelta):.1f}° MEA={radToDeg(mea):.1f}° GF={gf:.2f} peakBin={centerIdx}" + # Triangular smoothing kernel over adjacent bins for i in 0..