Files
SirRoboGarage/ModularBot_garage/tests/test_gauntlet_5bots.nim
T
SirStone 1e8f0d342a fix(adversaries): the launchers ran STALE binaries - this is why the earlier fix never took effect
P0. Three of the five launchers ran ./<Bot> (a tracked binary at the bot root)
while config.nims sets outdir=out and both the test framework's compileBots and
a manual 'nim c src/<Bot>.nim' write to out/. SittingDuck and OscillatorBot
correctly ran ./out/<Bot>; RandomMover, PatternMover and WaveSurfer did not.
cmp confirms the root and out binaries differed for all three.

Consequence: the previous session's adversary fixes were compiled into out/ and
never executed. Every gauntlet and every capture ran the OLD code. This is
almost certainly why the user's instinct that these bots were still bugged was
correct while the code claimed otherwise.

Fixed by pointing all five launchers at ./out/<Bot>, and by deleting the three
stale root binaries so the trap cannot recur. Verified end to end through the
booter: WaveSurfer went from standing still 96.2% of ticks with a 1398-tick
longest standstill, to rest 12.3% / mean speed 6.69 / longest zero run 18 /
perpendicular 0.845.

Also honours GUN_STATS_PATH in test_gauntlet_5bots.nim (same knob ModularBot
reads) so pooled gauntlet runs append to one file instead of clobbering the
default.

NOTE for a follow-up: the out/ binaries are still TRACKED build artifacts, which
is the same class of hazard that caused this. Untracking them (as was done for
ModularBot_garage/ModularBot) would remove the failure mode entirely.
2026-09-21 08:22:04 +02:00

70 lines
3.1 KiB
Nim

## Gun gauntlet: ModularBot vs all 5 adversaries, 10 rounds each.
## Dumps per-gun stats via ModularBot's onRoundEnded to /tmp/gun_stats.jsonl.
## nim c -r --path:../../common_libs tests/test_gauntlet_5bots.nim
import std/[os, strutils, strformat, tables]
import test_framework/server_manager
import test_framework/bot_compiler
import test_framework/runner_process
import test_framework/battle_result
const
modularBotDir = currentSourcePath().parentDir.parentDir
adversariesDir = "/home/davide/Projects/SirRoboGarage/common_libs/test_framework/adversaries"
serverJar = "/home/davide/Projects/tank-royale/server/build/libs/robocode-tankroyale-server-0.35.5-all.jar"
runnerJar = "/home/davide/Projects/tank-royale/runner/examples/lib/robocode-tankroyale-runner.jar"
if not fileExists(serverJar):
echo "SKIP: server JAR not found at " & serverJar
quit(0)
if not fileExists(runnerJar):
echo "SKIP: runner JAR not found at " & runnerJar
quit(0)
putEnv("TR_SERVER_JAR", serverJar)
putEnv("TR_BATTLE_RUNNER", runnerJar)
putEnv("TR_BATTLE_RUNNER_DIR", "/home/davide/Projects/SirRoboGarage/tools/battle_runner")
# Pre-compile ModularBot once
discard compileBots(@[modularBotDir])
echo "[gauntlet] ModularBot compiled OK"
proc runBattle(label, enemyName, enemyDir: string) =
let sep = "=".repeat(60)
echo "\n" & sep
echo " " & label
echo sep
let bots = @[modularBotDir, enemyDir]
discard compileBots(@[enemyDir]) # ensure adversary is compiled
# Write session marker so analysis can map rounds to enemy name.
# Honor GUN_STATS_PATH (same knob ModularBot reads) so repeated pooled runs
# can append to one dedicated file instead of clobbering the default.
let statsPath = getEnv("GUN_STATS_PATH", "/tmp/gun_stats.jsonl")
block:
let lf = open(statsPath, fmAppend)
lf.writeLine("{\"session_start\":\"" & enemyName & "\"}")
lf.close()
let raw = runBattleRunner(getServerUrl(), bots, 10, 300_000, true)
let r = parseServerOutput(raw)
var mbScore = 0; var enScore = 0
for b in r.results:
if b.name == "ModularBot": mbScore = b.totalScore
elif b.name == enemyName: enScore = b.totalScore
let winner = if mbScore >= enScore: "ModularBot" else: enemyName
echo fmt" ModularBot: {mbScore} {enemyName}: {enScore} -> {winner} wins"
echo fmt" Rounds played: {r.rounds.len}"
# Write summary line to gauntlet log
let logLine = fmt"[{label}] ModularBot={mbScore} {enemyName}={enScore} winner={winner} rounds={r.rounds.len}"
let lf = open("/tmp/gun_gauntlet_results.log", fmAppend)
lf.writeLine(logLine)
lf.close()
ensureServer()
runBattle("Battle 1/5: vs SittingDuck", "SittingDuck", adversariesDir / "SittingDuck")
runBattle("Battle 2/5: vs OscillatorBot","OscillatorBot", adversariesDir / "OscillatorBot")
runBattle("Battle 3/5: vs RandomMover", "RandomMover", adversariesDir / "RandomMover")
runBattle("Battle 4/5: vs PatternMover", "PatternMover", adversariesDir / "PatternMover")
runBattle("Battle 5/5: vs WaveSurfer", "WaveSurfer", adversariesDir / "WaveSurfer")
echo "\nGauntlet complete. Stats in " & getEnv("GUN_STATS_PATH", "/tmp/gun_stats.jsonl") & " and /tmp/gun_gauntlet_results.log"