57a1915b10
Implements: - BattleResult type and JSON-lines parser (#127) - TR server lifecycle manager (#128) - Bot compiler using nim c (#129) - runBattle() orchestrator (#130) - Example test in OscillatorBot_garage (#131) - Framework usage guide (#132) - TestBattleRunner.java for external server (#133) - BattleRunner process lifecycle (#134) Fix: runner_process.nim was redefining TimeoutError locally; now uses std/net.TimeoutError consistently with server_manager.nim.
83 lines
2.8 KiB
Nim
83 lines
2.8 KiB
Nim
import std/[json, strutils, sequtils]
|
|
|
|
type
|
|
BotRoundResult* = object
|
|
name*: string
|
|
score*: int
|
|
rank*: int
|
|
survived*: bool
|
|
|
|
RoundResult* = object
|
|
round*: int
|
|
results*: seq[BotRoundResult]
|
|
|
|
BotResult* = object
|
|
name*: string
|
|
totalScore*: int
|
|
rank*: int
|
|
firstPlaces*: int
|
|
survivalCount*: int
|
|
|
|
BattleResult* = object
|
|
bots*: seq[string]
|
|
rounds*: seq[RoundResult]
|
|
results*: seq[BotResult]
|
|
winners*: seq[string] # bots with rank == 1
|
|
|
|
proc parseServerOutput*(stdout: string): BattleResult =
|
|
for line in stdout.splitLines():
|
|
let s = line.strip()
|
|
if s.len == 0 or s[0] != '{': continue
|
|
let node = parseJson(s)
|
|
case node["event"].getStr()
|
|
of "game_started":
|
|
result.bots = node["bots"].getElems().mapIt(it.getStr())
|
|
of "round_ended":
|
|
var rr = RoundResult(round: node["round"].getInt())
|
|
for r in node["results"].getElems():
|
|
rr.results.add BotRoundResult(
|
|
name: r["name"].getStr(),
|
|
score: r["score"].getInt(),
|
|
rank: r["rank"].getInt(),
|
|
survived: r["survived"].getBool()
|
|
)
|
|
result.rounds.add rr
|
|
of "battle_ended":
|
|
for r in node["results"].getElems():
|
|
result.results.add BotResult(
|
|
name: r["name"].getStr(),
|
|
totalScore: r["totalScore"].getInt(),
|
|
rank: r["rank"].getInt(),
|
|
firstPlaces: r["firstPlaces"].getInt(),
|
|
survivalCount: r["survivalCount"].getInt()
|
|
)
|
|
result.winners = result.results.filterIt(it.rank == 1).mapIt(it.name)
|
|
else: discard
|
|
|
|
when isMainModule:
|
|
const sample = """
|
|
{"event":"game_started","bots":["Alpha","Beta"]}
|
|
{"event":"round_ended","round":1,"results":[{"name":"Alpha","score":150,"rank":1,"survived":true},{"name":"Beta","score":80,"rank":2,"survived":false}]}
|
|
{"event":"round_ended","round":2,"results":[{"name":"Beta","score":200,"rank":1,"survived":true},{"name":"Alpha","score":60,"rank":2,"survived":false}]}
|
|
{"event":"battle_ended","results":[{"name":"Alpha","totalScore":500,"rank":1,"firstPlaces":3,"survivalCount":5},{"name":"Beta","totalScore":300,"rank":2,"firstPlaces":1,"survivalCount":2}]}
|
|
|
|
not json, should be ignored
|
|
"""
|
|
let br = parseServerOutput(sample)
|
|
assert br.bots == @["Alpha", "Beta"]
|
|
assert br.rounds.len == 2
|
|
assert br.rounds[0].round == 1
|
|
assert br.rounds[0].results[0].name == "Alpha"
|
|
assert br.rounds[0].results[0].score == 150
|
|
assert br.rounds[0].results[0].rank == 1
|
|
assert br.rounds[0].results[0].survived == true
|
|
assert br.rounds[1].results[0].name == "Beta"
|
|
assert br.rounds[1].results[1].survived == false
|
|
assert br.results.len == 2
|
|
assert br.results[0].name == "Alpha"
|
|
assert br.results[0].totalScore == 500
|
|
assert br.results[0].firstPlaces == 3
|
|
assert br.results[0].survivalCount == 5
|
|
assert br.winners == @["Alpha"]
|
|
echo "all assertions passed"
|