feat(testing): gun rack gauntlet + analysis reports
- fix(ModularBot): onBulletHitBot → onBulletHit (real hits were never tracked) - feat(ModularBot): per-round gun stats dump to /tmp/gun_stats.jsonl - feat(ModularBot): gun selection counter per round - fix(tests): adversary paths _garage suffix removed from 7 test files - feat(tests): test_gauntlet_5bots.nim — 10-round gauntlet vs all 5 adversaries - feat(tests): analyze_gun_stats.nim — JSONL parser for gun performance tables - docs: gun_rack_analysis.md — full per-gun performance report - docs: gun_rack_summary.md — TL;DR verdict table (keep/drop/tune) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
## 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
|
||||
block:
|
||||
let lf = open("/tmp/gun_stats.jsonl", 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 /tmp/gun_stats.jsonl and /tmp/gun_gauntlet_results.log"
|
||||
Reference in New Issue
Block a user