fix game state representation
This commit is contained in:
parent
0ea49d3534
commit
4995a9388b
@ -1,5 +1,4 @@
|
||||
--threads: on
|
||||
--d: release
|
||||
--d: lto
|
||||
--opt: speed
|
||||
--passC: -flto
|
||||
--passL: -flto
|
||||
|
3
cup.nim
3
cup.nim
@ -5,8 +5,7 @@ when isMainModule:
|
||||
let config = parseArgs()
|
||||
var b: Board
|
||||
b.init
|
||||
b.setState(config.state, [])
|
||||
b.diceRolled = config.diceRolled
|
||||
b.setState(config.state)
|
||||
|
||||
let legScores = b.getLegScores
|
||||
let gameScores = b.randomGames(1_000_000)
|
||||
|
@ -101,12 +101,16 @@ proc delete*(s: var FixedSeq, idx: Natural) =
|
||||
when not defined(danger):
|
||||
if idx > s.last:
|
||||
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
|
||||
s.data[idx] = -1
|
||||
s.data[idx] = -1 # do we even need this?
|
||||
dec s.last
|
||||
for i in typeof(s.last)(idx) .. s.last:
|
||||
swap(s.data[i], s.data[i + 1])
|
||||
|
||||
|
||||
proc clear*(s: var FixedSeq) =
|
||||
s.last = -1
|
||||
|
||||
|
||||
proc find*(s: FixedSeq, needle: FixedSeq.Contents): FixedSeq.Pointer =
|
||||
for i, v in s.data:
|
||||
if v == needle:
|
||||
@ -127,6 +131,9 @@ proc reverse*(s: var FixedSeq; first, last: Natural) =
|
||||
proc shuffle*(s: var FixedSeq, r: var Rand) =
|
||||
r.shuffle(s.data)
|
||||
|
||||
proc shuffle*(s: var FixedSeq) =
|
||||
shuffle(s.data)
|
||||
|
||||
|
||||
proc moveSubstack*(src, dst: var FixedSeq; start: Natural) =
|
||||
var count: typeof(src.last) = 0 # have to track this separately apparently
|
||||
|
45
game.nim
45
game.nim
@ -53,6 +53,11 @@ type
|
||||
camels*: ColorStack
|
||||
tile*: Option[Tile]
|
||||
|
||||
GameState* = object
|
||||
dice*: array[Color, bool]
|
||||
camels*: FixedSeq[5, tuple[c: Color, p: range[1..16]], int8]
|
||||
tiles*: FixedSeq[8, tuple[t: Tile, p: range[1..16]], int8] # max 8 players, so max 8 tiles
|
||||
|
||||
Board* = object
|
||||
squares*: array[1..16, Square]
|
||||
camels*: array[Color, range[1..16]]
|
||||
@ -62,6 +67,14 @@ type
|
||||
initialized: bool
|
||||
|
||||
|
||||
proc init*(state: var GameState) =
|
||||
state.camels.initFixedSeq
|
||||
state.tiles.initFixedSeq
|
||||
|
||||
proc newGameState*(): GameState =
|
||||
result.init
|
||||
|
||||
|
||||
# use a template here for better inlining
|
||||
template `[]`*[T](b: var Board, idx: T): var Square =
|
||||
b.squares[idx]
|
||||
@ -107,16 +120,38 @@ proc display*(b: Board, start, stop: int) =
|
||||
echo ""
|
||||
|
||||
|
||||
proc setState*(b: var Board;
|
||||
camels: openArray[tuple[c: Color, p: int]];
|
||||
tiles: openArray[tuple[t: Tile, p: int]]) =
|
||||
for (color, dest) in camels: # note that `camels` is ordered, as this determines stacking
|
||||
proc setState*(b: var Board; state: GameState) =
|
||||
for color, pos in b.camels:
|
||||
if pos > 0:
|
||||
b[pos].camels.clear()
|
||||
|
||||
for (color, dest) in state.camels: # note that `camels` is ordered, as this determines stacking
|
||||
b[dest].camels.add(color)
|
||||
b.camels[color] = dest
|
||||
|
||||
for (tile, dest) in tiles:
|
||||
for (tile, dest) in state.tiles:
|
||||
b[dest].tile = some(tile)
|
||||
|
||||
b.diceRolled = state.dice
|
||||
|
||||
|
||||
proc getState*(b: Board): GameState =
|
||||
result.init
|
||||
var camelCount = 0
|
||||
let start = min(b.camels)
|
||||
for pos in start .. b.squares.high:
|
||||
let sq = b[pos]
|
||||
for color in sq.camels:
|
||||
result.camels.add((c: color, p: pos))
|
||||
camelCount += 1
|
||||
|
||||
if sq.tile.isSome:
|
||||
result.tiles.add((t: sq.tile.get, p: pos))
|
||||
if camelCount >= 5:
|
||||
break
|
||||
|
||||
result.dice = b.diceRolled
|
||||
|
||||
|
||||
proc diceRemaining*(b: Board): ColorStack =
|
||||
result.initFixedSeq
|
||||
|
@ -43,11 +43,14 @@ iterator legEndStates(b: Board): Board =
|
||||
for i, c in b.diceRolled:
|
||||
if not c: diceRemaining.add(i)
|
||||
|
||||
let origState = b.getState
|
||||
var prediction = b
|
||||
for future in possibleFutures(diceRemaining):
|
||||
var prediction = b # make a copy so we can mutate
|
||||
# var prediction = b # make a copy so we can mutate
|
||||
for dieRoll in future:
|
||||
prediction.advance(dieRoll)
|
||||
yield prediction
|
||||
prediction.setState(origState)
|
||||
|
||||
|
||||
proc getLegScores*(b: Board): ScoreSet =
|
||||
|
13
test.nim
13
test.nim
@ -39,12 +39,15 @@ proc summarize(tr: TestResults, opname = "operations") =
|
||||
|
||||
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, [])
|
||||
|
||||
var state = newGameState()
|
||||
for i in 0 .. 4:
|
||||
let pos = rand(1..3)
|
||||
state.camels.add((c: Color(i), p: pos))
|
||||
state.camels.shuffle()
|
||||
|
||||
result.setState(state)
|
||||
|
||||
|
||||
template executionTime(body: untyped): Duration =
|
||||
|
17
ui.nim
17
ui.nim
@ -16,7 +16,7 @@ const help = block:
|
||||
|
||||
type
|
||||
CmdConfig* = object
|
||||
state*: seq[tuple[c: Color, p: int]]
|
||||
state*: GameState
|
||||
interactive*: bool
|
||||
diceRolled*: array[Color, bool]
|
||||
|
||||
@ -34,17 +34,18 @@ proc parseColor(c: char): Color =
|
||||
of 'P', 'p':
|
||||
return cPurple
|
||||
else:
|
||||
raise newException(ValueError, "Invalid camel color specified.")
|
||||
raise newException(ValueError, "Invalid camel color specified: " & c)
|
||||
|
||||
|
||||
proc parseArgs*(): CmdConfig =
|
||||
result.state.init()
|
||||
for p in os.commandLineParams():
|
||||
if p == "-h":
|
||||
echo help
|
||||
quit 0
|
||||
elif p == "-i":
|
||||
result.interactive = true
|
||||
elif result.state.len < 5:
|
||||
elif result.state.camels.len < 5:
|
||||
let splat = p.split(':')
|
||||
|
||||
let sq = splat[0]
|
||||
@ -53,11 +54,14 @@ proc parseArgs*(): CmdConfig =
|
||||
let colors = splat[1]
|
||||
for c in colors:
|
||||
let color = parseColor(c)
|
||||
result.state.add((color, square))
|
||||
result.state.camels.add((c: color, p: square))
|
||||
else:
|
||||
for c in p:
|
||||
let color = parseColor(c)
|
||||
result.diceRolled[color] = true
|
||||
result.state.dice[color] = true
|
||||
|
||||
if result.state.camels.len != 5:
|
||||
raise newException(ValueError, "Please specify positions for all camels.")
|
||||
|
||||
|
||||
# ==========================
|
||||
@ -98,7 +102,6 @@ proc showSpaces*(b: Board; start, stop: Natural): string =
|
||||
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
|
||||
@ -106,5 +109,5 @@ proc showPercents*(scores: ScoreSet): string =
|
||||
for i in 0 ..< barFill:
|
||||
bar[i] = '='
|
||||
|
||||
lines[int(color)] = fmt"{label}: [{bar}] {percentage}%"
|
||||
lines[int(color)] = fmt"{color:>7}: [{bar}] {percentage:5.2f}%"
|
||||
result = lines.join("\n")
|
||||
|
Loading…
x
Reference in New Issue
Block a user