add (very) basic CLI
This commit is contained in:
parent
b4c31a7a68
commit
6f694f99ed
@ -1,7 +1,52 @@
|
||||
import random, sugar
|
||||
import algorithm, random, sugar
|
||||
import fixedseq, game
|
||||
|
||||
|
||||
proc nextPermutation(x: var FixedSeq): bool =
|
||||
# copied shamelessly from std/algorithm.nim
|
||||
if x.len < 2:
|
||||
return false
|
||||
|
||||
var i = x.high
|
||||
while i > 0 and x[i - 1] >= x[i]:
|
||||
dec i
|
||||
|
||||
if i == 0:
|
||||
return false
|
||||
|
||||
var j = x.high
|
||||
while j >= i and x[j] <= x[i - 1]:
|
||||
dec j
|
||||
|
||||
swap x[j], x[i - 1]
|
||||
x.reverse(i, x.high)
|
||||
|
||||
result = true
|
||||
|
||||
|
||||
proc prevPermutation(x: var FixedSeq): bool =
|
||||
# copied shamelessly from std/algorithm.nim
|
||||
if x.len < 2:
|
||||
return false
|
||||
|
||||
var i = x.high
|
||||
while i > 0 and x[i - 1] <= x[i]:
|
||||
dec i
|
||||
|
||||
if i == 0:
|
||||
return false
|
||||
|
||||
x.reverse(i, x.high)
|
||||
|
||||
var j = x.high
|
||||
while j >= i and x[j - 1] < x[i - 1]:
|
||||
dec j
|
||||
|
||||
swap x[i - 1], x[j]
|
||||
|
||||
result = true
|
||||
|
||||
|
||||
iterator allPermutations*(x: FixedSeq): FixedSeq =
|
||||
# returns all permutations of a given seq. Order is wonky but we don't care.
|
||||
var workingCopy = x
|
||||
|
33
fixedseq.nim
33
fixedseq.nim
@ -1,4 +1,4 @@
|
||||
import algorithm, random
|
||||
import random
|
||||
|
||||
|
||||
type
|
||||
@ -16,11 +16,21 @@ proc initFixedSeq*(s: var FixedSeq) =
|
||||
s.last = -1
|
||||
|
||||
|
||||
proc `$`*(s: FixedSeq): string =
|
||||
result.add("FixedSeq[")
|
||||
for i, item in s:
|
||||
if i != 0:
|
||||
result.add(", ")
|
||||
result.add($item)
|
||||
result.add("]")
|
||||
|
||||
|
||||
proc `[]`*(s: FixedSeq, i: Natural): FixedSeq.Contents =
|
||||
if i > s.last:
|
||||
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
||||
s.data[i]
|
||||
|
||||
|
||||
proc `[]`*(s: var FixedSeq, i: Natural): var FixedSeq.Contents =
|
||||
if i > s.last:
|
||||
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
||||
@ -99,9 +109,15 @@ proc find*(s: FixedSeq, needle: FixedSeq.Contents): FixedSeq.Pointer =
|
||||
return -1
|
||||
|
||||
|
||||
proc nextPermutation*(s: var FixedSeq): bool = s.data.nextPermutation
|
||||
proc reverse*(s: var FixedSeq; first, last: Natural) =
|
||||
# copied shamelessly from std/algorithm.nim
|
||||
var x = first
|
||||
var y = last
|
||||
while x < y:
|
||||
swap(s[x], s[y])
|
||||
inc x
|
||||
dec y
|
||||
|
||||
proc prevPermutation*(s: var FixedSeq): bool = s.data.prevPermutation
|
||||
|
||||
proc shuffle*(s: var FixedSeq, r: var Rand) =
|
||||
r.shuffle(s.data)
|
||||
@ -128,14 +144,3 @@ proc moveSubstackPre*(src, dst: var FixedSeq; start: Natural) =
|
||||
|
||||
dst.last += ssLen
|
||||
src.last -= ssLen
|
||||
|
||||
|
||||
# proc display(s: ColorStack) =
|
||||
# var p: seq[string]
|
||||
# for i in s.pieces:
|
||||
# if i == -1:
|
||||
# p.add("none")
|
||||
# else:
|
||||
# p.add($Color(i))
|
||||
# echo "pieces: @[", p.join(", "), "], last: ", s.last
|
||||
# echo "len: ", s.len, "\n"
|
||||
|
12
game.nim
12
game.nim
@ -18,7 +18,13 @@ proc getAllColors: ColorStack =
|
||||
for c in Color.low .. Color.high:
|
||||
result[i] = c
|
||||
|
||||
const allColors* = getAllColors() # compile-time evaluation
|
||||
const allColors* = getAllColors()
|
||||
const colorNames: array[Color, string] =
|
||||
["Red", "Green", "Blue", "Yellow", "Purple"]
|
||||
|
||||
|
||||
proc `$`*(c: Color): string =
|
||||
result = colorNames[c]
|
||||
|
||||
|
||||
proc `$`*(s: ColorStack): string =
|
||||
@ -107,8 +113,8 @@ proc diceRemaining*(b: Board): ColorStack =
|
||||
|
||||
|
||||
proc resetDice*(b: var Board) =
|
||||
var d: array[Color, bool]
|
||||
b.diceRolled = d
|
||||
for c, rolled in b.diceRolled:
|
||||
b.diceRolled[c] = false
|
||||
|
||||
|
||||
proc advance*(b: var Board, die: Die) =
|
||||
|
58
main.nim
58
main.nim
@ -1,5 +1,5 @@
|
||||
import math, options, sequtils, random, sets
|
||||
import combinators, game, fixedseq
|
||||
import combinators, game, fixedseq, ui
|
||||
|
||||
|
||||
type
|
||||
@ -17,7 +17,13 @@ proc update*(scores: var ScoreSet, toAdd: ScoreSet) =
|
||||
scores[i] += s
|
||||
|
||||
|
||||
proc projectLeg(b: Board): LegResults =
|
||||
proc display*(scores: ScoreSet) =
|
||||
let total = scores.sum
|
||||
for color, score in scores:
|
||||
echo color, ": ", round(100 * scores[color] / total, 2), '%'
|
||||
|
||||
|
||||
proc projectLeg*(b: Board): LegResults =
|
||||
var scores: ScoreSet
|
||||
var endStates: HashSet[Board]
|
||||
|
||||
@ -93,42 +99,12 @@ proc randomSpread(b: Board, nTests: SomeInteger, nSamples: SomeInteger): ScoreSp
|
||||
result.hi[color] = pct
|
||||
|
||||
|
||||
var b: Board
|
||||
b.init
|
||||
|
||||
randomize()
|
||||
var r = initRand(rand(int64))
|
||||
|
||||
var rolls: array[5, tuple[c: Color, p: int]]
|
||||
for i, roll in randomFuture(b.diceRemaining, r):
|
||||
rolls[i] = (roll[0], roll[1] + 1)
|
||||
|
||||
b.setState(rolls, @[])
|
||||
echo "Starting state:"
|
||||
b.display(1, 5)
|
||||
|
||||
# block outer:
|
||||
# while true:
|
||||
# for roll in randomFuture(b.diceRemaining, r):
|
||||
# b.advance(roll)
|
||||
# if b.gameOver:
|
||||
# echo "last roll: ", roll
|
||||
# break outer
|
||||
# b.resetDice
|
||||
|
||||
# echo "winner: ", b.leader.get
|
||||
# b.display(min(b.camels) - 1, 16)
|
||||
|
||||
# let scores = b.randomGames(10_000_000)
|
||||
# let total = scores.sum
|
||||
# for i, c in scores:
|
||||
# echo Color(i), ": ", (100 * c / total).round(2), "% (", c, " / ", total, ")"
|
||||
|
||||
for i in 0..3:
|
||||
let samples = 10 ^ (i + 3)
|
||||
echo "Simulating ", samples, " games 100 times"
|
||||
let spread = b.randomSpread(100, samples)
|
||||
for color, lo in spread.lo:
|
||||
stdout.write($color & ": " & $lo.round(4) & "-" & $spread.hi[color].round(4) & ", ")
|
||||
stdout.flushFile
|
||||
echo "\n"
|
||||
when isMainModule:
|
||||
let config = parseArgs()
|
||||
var b: Board
|
||||
b.init
|
||||
b.setState(config.state, [])
|
||||
b.diceRolled = config.diceRolled
|
||||
b.display(1, 5)
|
||||
let scores = b.projectLeg()[0]
|
||||
scores.display
|
||||
|
65
ui.nim
Normal file
65
ui.nim
Normal file
@ -0,0 +1,65 @@
|
||||
import os, strutils
|
||||
import game
|
||||
|
||||
|
||||
const help =
|
||||
"""cup - Probability calculator for the board game CamelUp
|
||||
|
||||
Usage:
|
||||
cup [-i] SPACE:STACK [...SPACE:STACK] [DICE]
|
||||
|
||||
SPACE refers to a numbered board space (1-16).
|
||||
STACK refers to a stack of camel colors from bottom to top, e.g.
|
||||
YBR (Yellow, Blue, Red, with Red on top).
|
||||
DICE refers to the set of dice that have already been rolled,
|
||||
e.g. GPR (Green, Purple, Red)
|
||||
|
||||
Options:
|
||||
-i Interactive mode (currently unimplemented)
|
||||
-h Show this message and exit
|
||||
"""
|
||||
|
||||
type
|
||||
CmdConfig* = object
|
||||
state*: seq[tuple[c: Color, p: int]]
|
||||
interactive*: bool
|
||||
diceRolled*: array[Color, bool]
|
||||
|
||||
|
||||
proc parseColor(c: char): Color =
|
||||
case c:
|
||||
of 'R', 'r':
|
||||
return cRed
|
||||
of 'G', 'g':
|
||||
return cGreen
|
||||
of 'B', 'b':
|
||||
return cBlue
|
||||
of 'Y', 'y':
|
||||
return cYellow
|
||||
of 'P', 'p':
|
||||
return cPurple
|
||||
else:
|
||||
raise newException(ValueError, "Invalid camel color specified.")
|
||||
|
||||
|
||||
proc parseArgs*(): CmdConfig =
|
||||
for p in os.commandLineParams():
|
||||
if p == "-h":
|
||||
echo help
|
||||
quit 0
|
||||
elif p == "-i":
|
||||
result.interactive = true
|
||||
elif result.state.len < 5:
|
||||
let splat = p.split(':')
|
||||
|
||||
let sq = splat[0]
|
||||
let square = sq.parseInt
|
||||
|
||||
let colors = splat[1]
|
||||
for c in colors:
|
||||
let color = parseColor(c)
|
||||
result.state.add((color, square))
|
||||
else:
|
||||
for c in p:
|
||||
let color = parseColor(c)
|
||||
result.diceRolled[color] = true
|
Loading…
x
Reference in New Issue
Block a user