diff --git a/main.nim b/main.nim index e8273ca..545207d 100644 --- a/main.nim +++ b/main.nim @@ -1,4 +1,4 @@ -import math, hashes, options, tables, sequtils, sets +import math, hashes, options, tables, sequtils, sets, sugar import combinators @@ -23,6 +23,7 @@ type Board = object squares: array[1..16, Square] camels: array[Color, range[1..16]] + diceRolled: array[Color, bool] leader: Option[Color] gameOver: bool @@ -110,11 +111,17 @@ proc advance(b: var Board, die: Die) = if endPos >= b.camels[b.leader.get]: b.leader = some(b[endPos].camels[^1]) break # breaking the outer loop here, not the inner - but only conditionally! gah! + b.diceRolled[color] = true -proc simulateLeg(b: Board, diceRemaining: seq[Color]): LegResults = +proc projectLeg(b: Board): LegResults = var scores: ScoreSet var endStates: HashSet[Board] + + let diceRemaining = collect(newSeq): + for i, c in b.diceRolled: + if not c: i + for future in possibleFutures(diceRemaining): var prediction = b # make a copy for dieRoll in future: @@ -125,31 +132,27 @@ proc simulateLeg(b: Board, diceRemaining: seq[Color]): LegResults = result = (scores, endStates) -proc simulateGame(b: Board, diceRemaining: seq[Color]): ScoreSet = - # currently just simulates two legs, not a full game - var (scores, startStates) = b.simulateLeg(diceRemaining) - var endStates: HashSet[Board] +proc projectOutcomes(b: Board, maxDepth = 1): ScoreSet = + var outcomeStack = @[ [b].toHashSet ] + for depth in 1..maxDepth: + var endStates: HashSet[Board] + for o in outcomeStack[^1]: + let projection = o.projectLeg + result.update(projection[0]) + endStates.incl(projection[1]) + stdout.write("simulated: " & $result.sum & "\r") - for s in startStates: - let (nextScores, nextStates) = s.simulateLeg(@[cRed, cGreen, cBlue, cYellow, cPurple]) - scores.update(nextScores) - endStates.incl(nextStates) - stdout.write("simulated: " & $scores.sum & "\r") - - echo "\nDistinct end states: ", endStates.len - result = scores + outcomeStack.add(endStates) + echo "\nDistinct end states: ", outcomeStack.mapIt(it.len).sum var b: Board b.display(1, 5) -b.setState({cGreen: 4, cYellow: 3, cPurple: 4, cBlue: 3, cRed: 2}, @[]) +b.setState({cGreen: 4, cYellow: 3, cPurple: 4, cBlue: 3, cRed: 4}, @[]) b.display(1, 5) -b.advance((cRed, 2)) -b.display(1, 5) - -let r = b.simulateGame(allDice) +let r = b.projectOutcomes(2) let total = r.sum for i, c in r: echo Color(i), ": ", (100 * c / total).round(2), "% (", c, " / ", total, ")"