From a0a384098067832776c13a672d2c49be9f2252df Mon Sep 17 00:00:00 2001 From: Davide Cappellini Date: Thu, 20 Aug 2026 23:37:50 +0200 Subject: [PATCH] feat(SAC_LSTM_Bot): skeleton bot with radar lock and colors (#40) Co-Authored-By: Claude Sonnet 4.6 --- SAC_LSTM_Bot/config.nims | 1 + SAC_LSTM_Bot/src/SAC_LSTM_Bot.json | 11 ++++++ SAC_LSTM_Bot/src/SAC_LSTM_Bot.nim | 62 ++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 SAC_LSTM_Bot/src/SAC_LSTM_Bot.json diff --git a/SAC_LSTM_Bot/config.nims b/SAC_LSTM_Bot/config.nims index 6bc4f18..678d11a 100644 --- a/SAC_LSTM_Bot/config.nims +++ b/SAC_LSTM_Bot/config.nims @@ -9,3 +9,4 @@ when withDir(thisDir(), system.fileExists("nimble.paths")): # Use the repo-vendored Tank Royale bot API (libs/) instead of the nimble pkg. # Must come AFTER the nimble.paths include: later --path wins the import search. switch("path", thisDir() & "/../libs/tankroyale_botapi") +switch("path", thisDir() & "/../libs/radar_lock") diff --git a/SAC_LSTM_Bot/src/SAC_LSTM_Bot.json b/SAC_LSTM_Bot/src/SAC_LSTM_Bot.json new file mode 100644 index 0000000..166cd4e --- /dev/null +++ b/SAC_LSTM_Bot/src/SAC_LSTM_Bot.json @@ -0,0 +1,11 @@ +{ + "name": "Recurrent Royalty", + "version": "0.1.0", + "authors": ["Davide Cappellini"], + "description": "SAC+LSTM Tank Royale bot — skeleton with radar lock", + "homepage": "", + "countryCodes": ["IT"], + "gameTypes": ["classic", "melee", "1v1"], + "platform": "Nim", + "programmingLang": "Nim" +} diff --git a/SAC_LSTM_Bot/src/SAC_LSTM_Bot.nim b/SAC_LSTM_Bot/src/SAC_LSTM_Bot.nim index c6636f2..69f3bb8 100644 --- a/SAC_LSTM_Bot/src/SAC_LSTM_Bot.nim +++ b/SAC_LSTM_Bot/src/SAC_LSTM_Bot.nim @@ -1,4 +1,60 @@ -## SAC_LSTM_Bot — placeholder main module. -## SAC (Soft Actor-Critic) + LSTM Tank Royale bot. +## SAC_LSTM_Bot — skeleton: radar lock + "Recurrent Royalty" color scheme. +## No RL yet. Connects, sets colors, locks radar onto enemy. -echo "SAC_LSTM_Bot scaffold" +import std/os +import tankroyale_botapi +import radar_lock + +const botJsonPath = currentSourcePath().parentDir / "SAC_LSTM_Bot.json" + +# ── Colors (Recurrent Royalty palette) ─────────────────────────────────────── +const + ColBody = fromHex("#7B2FBE") + ColTurret = fromHex("#FFD700") + ColGun = fromHex("#4A0E6B") + ColRadar = fromHex("#FFD700") + ColScan = fromHex("#FFB000") + ColBullet = fromHex("#FFC125") + ColTracks = fromHex("#2C2C34") + +proc applyColors() = + setBodyColor(ColBody) + setTurretColor(ColTurret) + setGunColor(ColGun) + setRadarColor(ColRadar) + setScanColor(ColScan) + setBulletColor(ColBullet) + setTracksColor(ColTracks) + +# ── Bot type ────────────────────────────────────────────────────────────────── + +type SacBot = ref object of Bot + enemyBearing: float # last known absolute bearing to enemy + +# ── Event handlers ──────────────────────────────────────────────────────────── + +method onRoundStarted*(bot: SacBot, e: RoundStartedEvent) = + setAdjustRadarForBodyTurn(true) + setAdjustRadarForGunTurn(true) + radar_lock.init() + applyColors() + +method onScannedBot*(bot: SacBot, e: ScannedBotEvent) = + bot.enemyBearing = directionTo(getX(), getY(), e.x, e.y) + # Same-tick radar lock: apply turn rate immediately so it takes effect this tick. + setRadarTurnRate(radar_lock.doRadar(getRadarDirection(), bot.enemyBearing)) + +# ── Run loop ────────────────────────────────────────────────────────────────── + +method run(bot: SacBot) = + while isRunning(): + # Spin radar when no enemy is visible (full sweep). + if bot.enemyBearing == 0.0: + setRadarTurnRate(45.0) + go() + +# ── Entry point ─────────────────────────────────────────────────────────────── + +when isMainModule: + var bot = SacBot() + start(bot, botJsonPath)