From ffa277e31df52a6804b76ce0b48dbce5baa2163f Mon Sep 17 00:00:00 2001 From: Davide Cappellini Date: Wed, 16 Sep 2026 08:41:25 +0200 Subject: [PATCH] feat(SNNBot): add bullet economy test against WallsBot Add --max-speed flag to TestBattleRunner (sets defaultTurnsPerSecond=-1 for unlimited TPS). Add SNNBot_garage/tests/test_bullet_economy.nim: 10-round vs WallsBot, prints per-round and summary stats for tuning. Co-Authored-By: Claude Sonnet 4.6 --- SNNBot_garage/tests/test_bullet_economy.nim | 49 +++++++++++++++++++++ tools/battle_runner/TestBattleRunner.java | 9 +++- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 SNNBot_garage/tests/test_bullet_economy.nim diff --git a/SNNBot_garage/tests/test_bullet_economy.nim b/SNNBot_garage/tests/test_bullet_economy.nim new file mode 100644 index 0000000..766ed15 --- /dev/null +++ b/SNNBot_garage/tests/test_bullet_economy.nim @@ -0,0 +1,49 @@ +## Bullet economy test: SNNBot vs WallsBot. +## Prints per-round and summary stats for tuning. No hard pass/fail. +## Requires TR server JARs (set TR_SERVER_JAR / TR_BATTLE_RUNNER env vars). + +import std/[os, strformat] +import test_framework/battle_result + +const + DefaultServerJar = "/home/davide/Projects/tank-royale/server/build/libs/robocode-tankroyale-server-0.35.5-all.jar" + DefaultRunnerJar = "/home/davide/Projects/tank-royale/runner/examples/lib/robocode-tankroyale-runner.jar" + +let serverJar = getEnv("TR_SERVER_JAR", DefaultServerJar) +let runnerJar = getEnv("TR_BATTLE_RUNNER", DefaultRunnerJar) +if not fileExists(serverJar) or not fileExists(runnerJar): + echo "Skipping: JAR files not found (set TR_SERVER_JAR / TR_BATTLE_RUNNER to override)" + quit(0) + +import test_framework/test_framework + +const + snnbotDir = currentSourcePath().parentDir.parentDir + wallsbotDir = currentSourcePath().parentDir.parentDir.parentDir / + "common_libs" / "test_framework" / "adversaries" / "WallsBot" + +let r = runBattle(@[snnbotDir, wallsbotDir], rounds = 10) + +# Per-round stats +echo "=== Per-round results ===" +var snnWins, wallsWins: int +for rnd in r.rounds: + var snn, walls: BotRoundResult + for br in rnd.results: + if br.name == "SNNBot": snn = br + if br.name == "WallsBot": walls = br + let winner = if snn.rank < walls.rank: "SNNBot" else: "WallsBot" + if winner == "SNNBot": inc snnWins else: inc wallsWins + echo fmt"Round {rnd.round:2}: {winner} wins | SNNBot score={snn.score} survived={snn.survived} | WallsBot score={walls.score} survived={walls.survived}" + +# Summary +echo "" +echo "=== Summary (10 rounds) ===" +var snnFinal, wallsFinal: BotResult +for b in r.results: + if b.name == "SNNBot": snnFinal = b + if b.name == "WallsBot": wallsFinal = b + +echo fmt"SNNBot : wins={snnWins}/10 totalScore={snnFinal.totalScore} survivalRounds={snnFinal.survivalCount} firstPlaces={snnFinal.firstPlaces}" +echo fmt"WallsBot : wins={wallsWins}/10 totalScore={wallsFinal.totalScore} survivalRounds={wallsFinal.survivalCount} firstPlaces={wallsFinal.firstPlaces}" +echo fmt"Win rate : {snnWins * 100 div 10}%" diff --git a/tools/battle_runner/TestBattleRunner.java b/tools/battle_runner/TestBattleRunner.java index 1d719b9..01b65d1 100644 --- a/tools/battle_runner/TestBattleRunner.java +++ b/tools/battle_runner/TestBattleRunner.java @@ -19,6 +19,7 @@ public class TestBattleRunner { String serverUrl = null; int rounds = 1; + boolean maxSpeed = false; List botDirs = List.of(); for (int i = 0; i < args.length; i++) { @@ -26,6 +27,7 @@ public class TestBattleRunner { case "--server-url" -> serverUrl = args[++i]; case "--rounds" -> rounds = Integer.parseInt(args[++i]); case "--bot-dirs" -> botDirs = Arrays.asList(args[++i].split(",")); + case "--max-speed" -> maxSpeed = true; default -> { System.err.println("Unknown arg: " + args[i]); System.exit(1); } } } @@ -36,7 +38,12 @@ public class TestBattleRunner { final String url = serverUrl; final List bots = botDirs.stream().map(BotEntry::of).collect(Collectors.toList()); final int numRounds = rounds; - final var setup = BattleSetup.classic(s -> s.setNumberOfRounds(numRounds)); + final boolean runMaxSpeed = maxSpeed; + // -1 = max TPS (no speed limit); see ServerCli.kt: "where -1 means maximum TPS" + final var setup = BattleSetup.classic(s -> { + s.setNumberOfRounds(numRounds); + if (runMaxSpeed) s.setDefaultTurnsPerSecond(-1); + }); // Debug: check what JSON files the runner will find for each bot dir for (String dir : botDirs) {