import math, random, strformat, strutils, times, std/monotimes import cligen import fixedseq, game, simulation type TestResults = object scores: ScoreSet time: Duration proc ops(tr: TestResults): int = result = sum(tr.scores) proc formatNum(n: SomeNumber, decimals = 0): string = when n is SomeFloat: let s = $n.round(decimals) else: let s = $n var parts = s.split('.') result = parts[0].insertSep(',') if decimals > 0: result = result & '.' & parts[1] proc summarize(tr: TestResults, opname = "operations") = let secs = tr.time.inMilliseconds.float / 1000 stdout.write("Test completed:\n") stdout.write(&" {tr.ops.formatNum} {opname} in {secs.formatNum(2)} seconds\n") stdout.write(&" {(tr.ops.float / secs).formatNum} {opname} per second\n") stdout.flushFile() # proc getRand(): Rand = # randomize() # result = initRand(rand(int64)) proc newRandomGame(): Board = randomize() var dice: array[5, tuple[c: Color, p: int]] for i in 0 .. 4: dice[i] = (Color(i), rand(1..3)) result.init result.setState(dice, []) template executionTime(body: untyped): Duration = let start = getMonoTime() body getMonoTime() - start # template runTest(loops: Natural, opname = "operations", body: ScoreSet): TestResults = # var res: TestResults # for i in 1 .. loops: # let start = getMonoTime() # let s = body # res.time += (getMonoTime() - start) # res.scores.update(s) # res.summarize(opname) # proc games(runs, samples: Natural, parallel = true) = # let b = newRandomGame() # runTest(runs, "games"): # b.randomGames(samples, parallel = parallel) # proc legs(runs: Natural) = # let b = newRandomGame() # runTest(runs, "legs"): # b.getLegScores proc games(runs, samples: Natural, parallel = true) = var res: TestResults for i in 1 .. runs: let b = newRandomGame() let dur = executionTime: let s = b.randomGames(samples, parallel = parallel) res.scores.update(s) res.time += dur res.summarize("games") proc legs(runs: Natural) = var res: TestResults for i in 1 .. runs: let b = newRandomGame() let dur = executionTime: let s = b.getLegScores res.scores.update(s) res.time += dur res.summarize("legs") proc spread(runs, samples: Natural) = let b = newRandomGame() let spread = randomSpread(b, runs, samples) stdout.writeLine("Variance:") for c in Color: let variance = 100 * (spread.hi[c] - spread.lo[c]) stdout.writeLine(fmt"{c}: {round(variance, 2):.2f}%") let diff = 100 * (max(spread.hi) - min(spread.lo)) stdout.writeLine(fmt"Win percentage differential: {round(diff, 2):.2f}%") stdout.flushFile() const help_runs = "Number of times to run the test" const help_samples = "Number of iterations per run" const help_parallel = "Run test in parallel or single-threaded (default parallel)" proc bench() = dispatchMulti( [games, help = {"runs": help_runs, "samples": help_samples, "parallel": help_parallel}], [legs, help = {"runs": help_runs}], [spread, help = {"runs": help_runs, "samples": help_samples}] ) when isMainModule: bench()