diff --git a/ModularBot_garage/src/ModularBot.nim b/ModularBot_garage/src/ModularBot.nim index 57eabfc..cc8ba17 100644 --- a/ModularBot_garage/src/ModularBot.nim +++ b/ModularBot_garage/src/ModularBot.nim @@ -20,12 +20,13 @@ import guns/anti_surfer import guns/wall_bounce import guns/accel_predictor import guns/stop_shot +import guns/displacement import movements/phantom_meteor const botJsonPath = currentSourcePath().parentDir / "ModularBot.json" const DebugVBullets = false const DebugCircular = false -const GunNames = ["HeadOn", "Linear", "Tsetlin", "Circular", "GuessFactor", "Pattern", "AntiSurf", "WallBounce", "Accel", "StopShot"] +const GunNames = ["HeadOn", "Linear", "Tsetlin", "Circular", "GuessFactor", "Pattern", "AntiSurf", "WallBounce", "Accel", "StopShot", "Displace"] type ModularBot = ref object of Bot @@ -44,6 +45,7 @@ type wallBounce: WallBounceGun accelGun: AccelGun stopShot: StopShotGun + displace: DisplacementGun mover: PhantomMeteorModule virtualHits: int virtualMiss: int @@ -84,6 +86,7 @@ method onScannedBot*(bot: ModularBot, e: ScannedBotEvent) = var wbPreds: array[len(PowerBins), GunPrediction] var acPreds: array[len(PowerBins), GunPrediction] var ssPreds: array[len(PowerBins), GunPrediction] + var dsPreds: array[len(PowerBins), GunPrediction] for i in 0.. same prediction + if state.tick == g.lastTick and bulletSpeed == g.cacheSpeed: + return g.cachePred + + # Push current position into ring buffer + g.head = (g.head + 1) mod (WindowSize + 1) + g.posX[g.head] = state.enemyX + g.posY[g.head] = state.enemyY + if g.count < WindowSize + 1: + inc g.count + + g.lastTick = state.tick + g.cacheSpeed = bulletSpeed + + # Need at least N+1 frames; fall back to head-on if not enough + if g.count < WindowSize + 1: + g.cachePred = GunPrediction(x: state.enemyX, y: state.enemyY) + return g.cachePred + + # Oldest frame is (head + 1) mod (WindowSize + 1) + let oldest = (g.head + 1) mod (WindowSize + 1) + let dx = (state.enemyX - g.posX[oldest]) / WindowSize.float + let dy = (state.enemyY - g.posY[oldest]) / WindowSize.float + + # Iterate time estimate 5 times + let dist0 = hypot(state.enemyX - state.selfX, state.enemyY - state.selfY) + var ticks = dist0 / bulletSpeed + var px = state.enemyX + var py = state.enemyY + for _ in 0..4: + px = state.enemyX + dx * ticks + py = state.enemyY + dy * ticks + ticks = hypot(px - state.selfX, py - state.selfY) / bulletSpeed + + px = clamp(px, 0.0, state.arenaWidth) + py = clamp(py, 0.0, state.arenaHeight) + g.cachePred = GunPrediction(x: px, y: py) + g.cachePred + +proc onResult*(g: var DisplacementGun, e: FeedbackEvent) = + discard # analytical gun — no learning + +proc initDisplacementGun*(): DisplacementGun = + DisplacementGun(count: 0, head: 0, lastTick: -1)