feat(ModularBot): wall-bounce gun, 8 guns total

- Wall-bounce gun: linear extrapolation with arena wall reflection
- Simulates enemy tick-by-tick, bouncing off walls (billiard-ball reflection)
- 4-iteration convergence on ticksToArrive like circular gun
- 8 guns: head-on, linear, circular, tsetlin, guess-factor, pattern, anti-surfer, wall-bounce
- Turret: #CCCCCC (silver), bullet: #EEEEEE (white)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-20 01:30:21 +02:00
parent ebe5b1b7f1
commit a3b4f26b69
2 changed files with 67 additions and 2 deletions
+11 -2
View File
@@ -17,12 +17,13 @@ import guns/tsetlin
import guns/guess_factor
import guns/pattern_matcher
import guns/anti_surfer
import guns/wall_bounce
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"]
const GunNames = ["HeadOn", "Linear", "Tsetlin", "Circular", "GuessFactor", "Pattern", "AntiSurf", "WallBounce"]
type
ModularBot = ref object of Bot
@@ -38,6 +39,7 @@ type
guessFactor: GFGun
patternMatcher: PatternMatcherGun
antiSurfer: AntiSurferGun
wallBounce: WallBounceGun
mover: PhantomMeteorModule
virtualHits: int
virtualMiss: int
@@ -75,6 +77,7 @@ method onScannedBot*(bot: ModularBot, e: ScannedBotEvent) =
var gfPreds: array[len(PowerBins), GunPrediction]
var pmPreds: array[len(PowerBins), GunPrediction]
var asPreds: array[len(PowerBins), GunPrediction]
var wbPreds: array[len(PowerBins), GunPrediction]
for i in 0..<len(PowerBins):
headsUp[i] = bot.headOn.predict(bot.lastState, bulletSpeed(PowerBins[i]))
linPreds[i] = bot.linear.predict(bot.lastState, bulletSpeed(PowerBins[i]))
@@ -83,6 +86,7 @@ method onScannedBot*(bot: ModularBot, e: ScannedBotEvent) =
gfPreds[i] = bot.guessFactor.predict(bot.lastState, bulletSpeed(PowerBins[i]))
pmPreds[i] = bot.patternMatcher.predict(bot.lastState, bulletSpeed(PowerBins[i]))
asPreds[i] = bot.antiSurfer.predict(bot.lastState, bulletSpeed(PowerBins[i]))
wbPreds[i] = bot.wallBounce.predict(bot.lastState, bulletSpeed(PowerBins[i]))
bot.tracker.spawnBullets(0, headsUp, bot.lastState)
bot.tracker.spawnBullets(1, linPreds, bot.lastState)
@@ -93,6 +97,7 @@ method onScannedBot*(bot: ModularBot, e: ScannedBotEvent) =
bot.tracker.spawnBullets(4, gfPreds, bot.lastState)
bot.tracker.spawnBullets(5, pmPreds, bot.lastState)
bot.tracker.spawnBullets(6, asPreds, bot.lastState)
bot.tracker.spawnBullets(7, wbPreds, bot.lastState)
# Resolve bullets that have travelled far enough
let st = bot.lastState
@@ -110,6 +115,7 @@ method onScannedBot*(bot: ModularBot, e: ScannedBotEvent) =
of 4: bot.guessFactor.onResult(fe)
of 5: bot.patternMatcher.onResult(fe)
of 6: bot.antiSurfer.onResult(fe)
of 7: bot.wallBounce.onResult(fe)
else: discard
if fe.hit: inc bot.virtualHits else: inc bot.virtualMiss
when DebugVBullets:
@@ -133,6 +139,7 @@ method onScannedBot*(bot: ModularBot, e: ScannedBotEvent) =
of 4: setTurretColor("#FFCC00"); setBulletColor("#FFE066") # GuessFactor: yellow
of 5: setTurretColor("#FF6600"); setBulletColor("#FF9944") # Pattern: orange
of 6: setTurretColor("#00CCFF"); setBulletColor("#66DDFF") # AntiSurf: cyan
of 7: setTurretColor("#CCCCCC"); setBulletColor("#EEEEEE") # WallBounce: silver/white
else: discard
let pred = case selectedGun
@@ -142,6 +149,7 @@ method onScannedBot*(bot: ModularBot, e: ScannedBotEvent) =
of 4: bot.guessFactor.predict(bot.lastState, bulletSpeed(power))
of 5: bot.patternMatcher.predict(bot.lastState, bulletSpeed(power))
of 6: bot.antiSurfer.predict(bot.lastState, bulletSpeed(power))
of 7: bot.wallBounce.predict(bot.lastState, bulletSpeed(power))
else: bot.headOn.predict(bot.lastState, bulletSpeed(power))
let target = aimAngle(getX(), getY(), pred.x, pred.y)
@@ -201,7 +209,7 @@ method run*(bot: ModularBot) =
when isMainModule:
var bot = ModularBot(
tracker: vb.initTracker(7), # 0: HeadOn, 1: Linear, 2: Tsetlin, 3: Circular, 4: GuessFactor, 5: Pattern, 6: AntiSurf
tracker: vb.initTracker(8), # 0: HeadOn, 1: Linear, 2: Tsetlin, 3: Circular, 4: GuessFactor, 5: Pattern, 6: AntiSurf, 7: WallBounce
headOn: HeadOnGun(),
linear: LinearGun(),
circular: CircularGun(),
@@ -209,6 +217,7 @@ when isMainModule:
guessFactor: initGFGun(),
patternMatcher: PatternMatcherGun(),
antiSurfer: initAntiSurferGun(),
wallBounce: initWallBounceGun(),
radar: RadarLockModule(),
mover: initPhantomMeteor(),
currentGun: -1,