stochastic modeling for full games
This commit is contained in:
parent
2256b6d9bf
commit
f05ab2cfa2
@ -1,4 +1,4 @@
|
|||||||
import sequtils
|
import random, sugar
|
||||||
import fixedseq, game
|
import fixedseq, game
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ iterator allPermutations*(x: FixedSeq): FixedSeq =
|
|||||||
|
|
||||||
iterator allDigits*(lo, hi, size: Natural): auto =
|
iterator allDigits*(lo, hi, size: Natural): auto =
|
||||||
if size > 0: # otherwise we get an infinite loop
|
if size > 0: # otherwise we get an infinite loop
|
||||||
var digits: FixedSeq[5, int8, int8]
|
var digits: FixedSeq[5, int, int8]
|
||||||
digits.initFixedSeq
|
digits.initFixedSeq
|
||||||
for i in 0 ..< size:
|
for i in 0 ..< size:
|
||||||
digits.add(lo)
|
digits.add(lo)
|
||||||
@ -42,3 +42,10 @@ iterator possibleFutures*(dice: FixedSeq): auto =
|
|||||||
for i in 0 .. dice.high:
|
for i in 0 .. dice.high:
|
||||||
f.add((perm[i], digits[i]))
|
f.add((perm[i], digits[i]))
|
||||||
yield f
|
yield f
|
||||||
|
|
||||||
|
|
||||||
|
proc randomFuture*(dice: FixedSeq, r: var Rand): FixedSeq[5, Die, int8] =
|
||||||
|
result.initFixedSeq
|
||||||
|
let order = dice.dup(shuffle(r))
|
||||||
|
for i, color in order:
|
||||||
|
result.add((color, r.rand(1..3)))
|
||||||
|
10
fixedseq.nim
10
fixedseq.nim
@ -1,4 +1,4 @@
|
|||||||
import algorithm
|
import algorithm, random
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -16,6 +16,11 @@ proc initFixedSeq*(s: var FixedSeq) =
|
|||||||
s.last = -1
|
s.last = -1
|
||||||
|
|
||||||
|
|
||||||
|
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 =
|
proc `[]`*(s: var FixedSeq, i: Natural): var FixedSeq.Contents =
|
||||||
if i > s.last:
|
if i > s.last:
|
||||||
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
||||||
@ -98,7 +103,8 @@ proc nextPermutation*(s: var FixedSeq): bool = s.data.nextPermutation
|
|||||||
|
|
||||||
proc prevPermutation*(s: var FixedSeq): bool = s.data.prevPermutation
|
proc prevPermutation*(s: var FixedSeq): bool = s.data.prevPermutation
|
||||||
|
|
||||||
proc maxSize*(s: FixedSeq): FixedSeq.Pointer = s.data.len
|
proc shuffle*(s: var FixedSeq, r: var Rand) =
|
||||||
|
r.shuffle(s.data)
|
||||||
|
|
||||||
|
|
||||||
proc moveSubstack*(src, dst: var FixedSeq; start: Natural) =
|
proc moveSubstack*(src, dst: var FixedSeq; start: Natural) =
|
||||||
|
21
game.nim
21
game.nim
@ -9,6 +9,18 @@ type
|
|||||||
ColorStack* = FixedSeq[5, Color, int8]
|
ColorStack* = FixedSeq[5, Color, int8]
|
||||||
|
|
||||||
|
|
||||||
|
proc initColorStack: ColorStack =
|
||||||
|
result.initFixedSeq
|
||||||
|
|
||||||
|
|
||||||
|
proc getAllColors: ColorStack =
|
||||||
|
var i = 0
|
||||||
|
for c in Color.low .. Color.high:
|
||||||
|
result[i] = c
|
||||||
|
|
||||||
|
const allColors = getAllColors() # compile-time evaluation
|
||||||
|
|
||||||
|
|
||||||
proc `$`*(s: ColorStack): string =
|
proc `$`*(s: ColorStack): string =
|
||||||
result.add("St@[")
|
result.add("St@[")
|
||||||
for i, color in s:
|
for i, color in s:
|
||||||
@ -38,9 +50,6 @@ type
|
|||||||
initialized: bool
|
initialized: bool
|
||||||
|
|
||||||
|
|
||||||
const allDice = @[cRed, cGreen, cBlue, cYellow, cPurple]
|
|
||||||
|
|
||||||
|
|
||||||
proc `[]`*[T](b: var Board, idx: T): var Square =
|
proc `[]`*[T](b: var Board, idx: T): var Square =
|
||||||
b.squares[idx]
|
b.squares[idx]
|
||||||
|
|
||||||
@ -90,6 +99,12 @@ proc setState*(b: var Board;
|
|||||||
b.leader = some(leadCamel)
|
b.leader = some(leadCamel)
|
||||||
|
|
||||||
|
|
||||||
|
proc diceRemaining*(b: Board): ColorStack =
|
||||||
|
result.initFixedSeq
|
||||||
|
for color, isRolled in b.diceRolled:
|
||||||
|
if not isRolled: result.add(color)
|
||||||
|
|
||||||
|
|
||||||
proc resetDice*(b: var Board) =
|
proc resetDice*(b: var Board) =
|
||||||
var d: array[Color, bool]
|
var d: array[Color, bool]
|
||||||
b.diceRolled = d
|
b.diceRolled = d
|
||||||
|
28
main.nim
28
main.nim
@ -1,4 +1,4 @@
|
|||||||
import math, options, sequtils, sets, sugar
|
import math, options, sequtils, random, sets
|
||||||
import combinators, game, fixedseq
|
import combinators, game, fixedseq
|
||||||
|
|
||||||
|
|
||||||
@ -41,6 +41,7 @@ proc projectOutcomes(b: Board, maxDepth = 1): ScoreSet =
|
|||||||
|
|
||||||
for o in outcomeStack[^1]:
|
for o in outcomeStack[^1]:
|
||||||
var o = o # make it mutable
|
var o = o # make it mutable
|
||||||
|
if outcomeStack.len > 1:
|
||||||
o.resetDice # o was describina an end-of-leg state, so dice were exhausted
|
o.resetDice # o was describina an end-of-leg state, so dice were exhausted
|
||||||
|
|
||||||
let projection = o.projectLeg
|
let projection = o.projectLeg
|
||||||
@ -52,11 +53,32 @@ proc projectOutcomes(b: Board, maxDepth = 1): ScoreSet =
|
|||||||
echo "\nDistinct end states: ", outcomeStack.mapIt(it.len).sum
|
echo "\nDistinct end states: ", outcomeStack.mapIt(it.len).sum
|
||||||
|
|
||||||
|
|
||||||
|
proc randomGame(b: Board, r: var Rand): Color =
|
||||||
|
var projection = b
|
||||||
|
while true:
|
||||||
|
for roll in randomFuture(projection.diceRemaining, r):
|
||||||
|
projection.advance(roll)
|
||||||
|
if projection.gameOver:
|
||||||
|
return projection.leader.get
|
||||||
|
projection.resetDice
|
||||||
|
|
||||||
|
|
||||||
|
proc randomGames(b: Board, count: SomeInteger): ScoreSet =
|
||||||
|
randomize()
|
||||||
|
var r = initRand(rand(int64))
|
||||||
|
for i in 0 ..< count:
|
||||||
|
let winner = b.randomGame(r)
|
||||||
|
inc result[winner]
|
||||||
|
if i mod 100_000 == 0:
|
||||||
|
stdout.write("simulated: " & $i & "\r")
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
|
||||||
var b: Board
|
var b: Board
|
||||||
b.init
|
b.init
|
||||||
b.display(1, 5)
|
b.display(1, 5)
|
||||||
|
|
||||||
b.setState({cGreen: 4, cYellow: 3, cPurple: 4, cBlue: 3, cRed: 4}, @[])
|
b.setState({cGreen: 4, cYellow: 3, cPurple: 4, cBlue: 3, cRed: 5}, @[])
|
||||||
b.display(1, 5)
|
b.display(1, 5)
|
||||||
|
|
||||||
# b.advance((cRed, 1))
|
# b.advance((cRed, 1))
|
||||||
@ -70,7 +92,7 @@ b.display(1, 5)
|
|||||||
# echo s
|
# echo s
|
||||||
# echo s[2]
|
# echo s[2]
|
||||||
|
|
||||||
let r = b.projectOutcomes(2)
|
let r = b.randomGames(10_000_000)
|
||||||
let total = r.sum
|
let total = r.sum
|
||||||
for i, c in r:
|
for i, c in r:
|
||||||
echo Color(i), ": ", (100 * c / total).round(2), "% (", c, " / ", total, ")"
|
echo Color(i), ": ", (100 * c / total).round(2), "% (", c, " / ", total, ")"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user