## Reads /tmp/gun_stats.jsonl and produces per-gun performance summary. ## nim c -r --path:../../common_libs tests/analyze_gun_stats.nim ## Output: /tmp/gun_performance_summary.txt import std/[json, tables, strformat, strutils, sequtils, algorithm, os] const GunNames = ["HeadOn","Linear","Tsetlin","Circular","GuessFactor","Pattern","AntiSurf","WallBounce","Accel","StopShot","Displace","AvgLead","DecayGF","KNN"] type GunStats = object vShots, vHits, selected: int EnemyStats = object guns: array[14, GunStats] realShots, realHits, rounds: int name: string var byEnemy: Table[string, EnemyStats] var currentEnemy = "unknown" if not fileExists("/tmp/gun_stats.jsonl"): echo "No /tmp/gun_stats.jsonl found — run the gauntlet first." quit(1) for line in lines("/tmp/gun_stats.jsonl"): let s = line.strip() if s.len == 0: continue let j = parseJson(s) if j.hasKey("session_start"): currentEnemy = j["session_start"].getStr() if currentEnemy notin byEnemy: byEnemy[currentEnemy] = EnemyStats(name: currentEnemy) continue if not j.hasKey("round"): continue var es = addr byEnemy[currentEnemy] inc es.rounds es.realShots += j["realShots"].getInt() es.realHits += j["realHits"].getInt() for g in j["guns"].getElems(): let gid = g["id"].getInt() es.guns[gid].vShots += g["vShots"].getInt() es.guns[gid].vHits += g["vHits"].getInt() es.guns[gid].selected += g["selected"].getInt() var output: seq[string] output.add "Gun Performance Summary" output.add "Generated from /tmp/gun_stats.jsonl" output.add "" # Preserve insertion order via seq of names encountered var enemyOrder: seq[string] for line in lines("/tmp/gun_stats.jsonl"): let s = line.strip() if s.len == 0: continue let j = parseJson(s) if j.hasKey("session_start"): let n = j["session_start"].getStr() if n notin enemyOrder: enemyOrder.add n for ename in enemyOrder: if ename notin byEnemy: continue let es = byEnemy[ename] let realPct = if es.realShots > 0: es.realHits * 100 div es.realShots else: 0 output.add fmt"=== vs {es.name} ({es.rounds} rounds) ===" output.add fmt" Real shots: {es.realShots} Real hits: {es.realHits} Real hit%: {realPct}%" output.add "" output.add " " & alignLeft("Gun", 14) & align("vShots", 8) & align("vHits", 7) & align("vHit%", 7) & align("Selected", 9) output.add " " & "-".repeat(50) var ranked = toSeq(0..<14) ranked.sort(proc(a,b:int):int = es.guns[b].selected - es.guns[a].selected) for gid in ranked: let g = es.guns[gid] let rate = if g.vShots > 0: g.vHits * 100 div g.vShots else: 0 output.add fmt" {GunNames[gid]:<14} {g.vShots:>8} {g.vHits:>7} {rate:>6}% {g.selected:>9}" output.add "" let summary = output.join("\n") echo summary writeFile("/tmp/gun_performance_summary.txt", summary) echo "\nWrote /tmp/gun_performance_summary.txt"