prettier displays for game board and win probabilities

This commit is contained in:
Joseph Montanaro 2021-07-14 21:49:10 -07:00
parent b58aafc61f
commit 20d6022828
4 changed files with 93 additions and 9 deletions

View File

@ -18,15 +18,21 @@ proc getAllColors: ColorStack =
for c in Color.low .. Color.high: for c in Color.low .. Color.high:
result[i] = c result[i] = c
const allColors* = getAllColors() const
const colorNames: array[Color, string] = allColors* = getAllColors()
["Red", "Green", "Blue", "Yellow", "Purple"] colorNames: array[Color, string] =
["Red", "Green", "Blue", "Yellow", "Purple"]
colorAbbrevs: array[Color, char] = ['R', 'G', 'B', 'Y', 'P']
proc `$`*(c: Color): string = proc `$`*(c: Color): string =
result = colorNames[c] result = colorNames[c]
proc abbrev*(c: Color): char =
result = colorAbbrevs[c]
proc `$`*(s: ColorStack): string = proc `$`*(s: ColorStack): string =
result.add("St@[") result.add("St@[")
for i, color in s: for i, color in s:
@ -44,8 +50,8 @@ type
tForward = 1 tForward = 1
Square* = object Square* = object
camels: ColorStack camels*: ColorStack
tile: Option[Tile] tile*: Option[Tile]
Board* = object Board* = object
squares*: array[1..16, Square] squares*: array[1..16, Square]

View File

@ -4,6 +4,7 @@ import combinators, game, fixedseq
type type
ScoreSet* = array[Color, int] ScoreSet* = array[Color, int]
WinPercents* = array[Color, float]
ScoreSpread = object ScoreSpread = object
lo*: array[Color, float] lo*: array[Color, float]
@ -26,6 +27,12 @@ proc display*(scores: ScoreSet) =
# echo color, ": ", round(100 * scores[color] / total, 2), '%' # echo color, ": ", round(100 * scores[color] / total, 2), '%'
proc percents*(scores: ScoreSet): WinPercents =
let total = scores.sum
for c, score in scores:
result[c] = score / total
# ====================== # ======================
# Single-leg simulations # Single-leg simulations
# ====================== # ======================

View File

@ -1,5 +1,5 @@
import math, random, strformat, times import math, random, strformat, times
import fixedseq, game, simulation import fixedseq, game, simulation, ui
proc randomDice(r: var Rand): seq[tuple[c: Color, p: int]] = proc randomDice(r: var Rand): seq[tuple[c: Color, p: int]] =
@ -9,6 +9,15 @@ proc randomDice(r: var Rand): seq[tuple[c: Color, p: int]] =
result.shuffle result.shuffle
proc newRandomGame(r: var Rand): Board =
var dice: array[5, tuple[c: Color, p: int]]
for i in 0 .. 4:
dice[i] = (Color(i), r.rand(1..3))
result.init
result.setState(dice, [])
proc testGames(n: SomeInteger = 100): auto = proc testGames(n: SomeInteger = 100): auto =
var r = initRand(rand(int64)) var r = initRand(rand(int64))
let dice = randomDice(r) let dice = randomDice(r)
@ -64,6 +73,13 @@ proc testSpread(nTests, nSamples: Natural) =
when isMainModule: when isMainModule:
randomize() randomize()
var r = initRand(rand(int64))
let b = newRandomGame(r)
b.display(1, 5)
echo b.showSpaces(1, 16)
let scores = b.getLegScores
echo scores.showPercents
# let start_states = 2_000 # let start_states = 2_000
# let executionTime = testLegs(start_states) # let executionTime = testLegs(start_states)
# echo "Execution time: ", executionTime # echo "Execution time: ", executionTime
@ -76,4 +92,4 @@ when isMainModule:
# echo "Full-game simulations per second: ", float(num_games) / executionTime # echo "Full-game simulations per second: ", float(num_games) / executionTime
# echo "" # echo ""
testSpread(100, 1_000_000) # testSpread(100, 1_000_000)

59
ui.nim
View File

@ -1,5 +1,5 @@
import os, strutils import os, math, strutils, strformat
import game import fixedseq, game, simulation
const help = const help =
@ -19,6 +19,11 @@ Options:
-h Show this message and exit -h Show this message and exit
""" """
# =============================
# User input parsing/validation
# =============================
type type
CmdConfig* = object CmdConfig* = object
state*: seq[tuple[c: Color, p: int]] state*: seq[tuple[c: Color, p: int]]
@ -63,3 +68,53 @@ proc parseArgs*(): CmdConfig =
for c in p: for c in p:
let color = parseColor(c) let color = parseColor(c)
result.diceRolled[color] = true result.diceRolled[color] = true
# ==========================
# Game state representations
# ==========================
proc showSpaces*(b: Board; start, stop: Natural): string =
let numSpaces = stop - start + 1
let width = 4 * numSpaces - 1
var lines: array[7, string]
# start by building up an empty board
for i in 0 .. 6: # gotta initialize the strings
lines[i] = newString(width)
for c in lines[i].mitems:
c = ' '
# fill in the dividers
lines[5] = repeat("=== ", numSpaces - 1)
lines[5].add("===")
# now populate the board
for sp in 0 ..< numSpaces:
# fill in the square numbers
let squareNum = sp + start
let cellMid = 4 * sp + 1
for i, chr in $squareNum:
lines[6][cellMid + i] = chr
# fill in the camel stacks
for i, color in b.squares[squareNum].camels:
let lineNum = 4 - i # lines go to 6, but bottom 2 are reserved
let repr = '|' & color.abbrev & '|'
for j, chr in repr:
lines[lineNum][cellMid - 1 + j] = chr
result = lines.join("\n")
proc showPercents*(scores: ScoreSet): string =
var lines: array[5, string]
for color, pct in scores.percents:
let label = align($color, 7) # e.g. " Green"
var bar = repeat(" ", 20)
let percentage = round(pct * 100, 2)
# populate the progress bar
let barFill = int(round(pct * 100 / 20))
for i in 0 ..< barFill:
bar[i] = '='
lines[int(color)] = fmt"{label}: [{bar}] {percentage}%"
result = lines.join("\n")