refactor and start shifting to FixedSeq (currently broken)
This commit is contained in:
parent
59fc6b961b
commit
2256b6d9bf
139
colors.nim
139
colors.nim
@ -1,139 +0,0 @@
|
|||||||
import strutils
|
|
||||||
|
|
||||||
|
|
||||||
type
|
|
||||||
Color* = enum
|
|
||||||
cRed, cGreen, cBlue, cYellow, cPurple
|
|
||||||
|
|
||||||
ColorStack* = object
|
|
||||||
pieces: array[5, int8]
|
|
||||||
last: int8
|
|
||||||
|
|
||||||
|
|
||||||
proc init*(s: var ColorStack) =
|
|
||||||
for i in 0..4:
|
|
||||||
s.pieces[i] = -1
|
|
||||||
s.last = -1
|
|
||||||
|
|
||||||
|
|
||||||
proc `[]`*(s: ColorStack, i: Natural): Color =
|
|
||||||
if i > s.last:
|
|
||||||
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
|
||||||
result = Color(s.pieces[i])
|
|
||||||
|
|
||||||
|
|
||||||
proc `[]`*(s: ColorStack, i: BackwardsIndex): Color =
|
|
||||||
if s.last == -1:
|
|
||||||
raise newException(IndexDefect, "index out of bounds, the container is empty.") # matching stdlib again
|
|
||||||
result = Color(s.pieces[s.last - int8(i) + 1])
|
|
||||||
|
|
||||||
|
|
||||||
proc `[]=`*(s: var ColorStack, i: Natural, v: Color) =
|
|
||||||
if i > s.last:
|
|
||||||
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
|
||||||
s.pieces[i] = int8(v)
|
|
||||||
|
|
||||||
|
|
||||||
proc `$`*(s: ColorStack): string =
|
|
||||||
result.add("St@[")
|
|
||||||
for i in 0 .. s.last:
|
|
||||||
let c = Color(s.pieces[i])
|
|
||||||
result.add($c)
|
|
||||||
if i < s.last:
|
|
||||||
result.add(", ")
|
|
||||||
result.add("]")
|
|
||||||
|
|
||||||
|
|
||||||
proc high*(s: ColorStack): int8 =
|
|
||||||
result = s.last
|
|
||||||
|
|
||||||
|
|
||||||
proc low*(s: ColorStack): int8 =
|
|
||||||
result = case s.last
|
|
||||||
of -1: 0 # a bit weird but it's how the stdlib seq works
|
|
||||||
else: s.last
|
|
||||||
|
|
||||||
|
|
||||||
proc len*(s: ColorStack): int8 =
|
|
||||||
result = s.last + 1
|
|
||||||
|
|
||||||
|
|
||||||
iterator items*(s: ColorStack): Color =
|
|
||||||
for i in 0 .. s.last:
|
|
||||||
yield Color(s.pieces[i])
|
|
||||||
|
|
||||||
|
|
||||||
iterator asInt*(s: ColorStack): int8 =
|
|
||||||
for i in 0 .. s.last:
|
|
||||||
yield s.pieces[i] # no conversion, should speed up hashing? maybe
|
|
||||||
|
|
||||||
|
|
||||||
iterator pairs*(s: ColorStack): auto =
|
|
||||||
var count = 0
|
|
||||||
for c in s:
|
|
||||||
yield (count, c)
|
|
||||||
inc count
|
|
||||||
|
|
||||||
|
|
||||||
proc add*(s: var ColorStack, c: Color) =
|
|
||||||
let i = s.last + 1
|
|
||||||
s.pieces[i] = int8(c) # will raise exception if out of bounds
|
|
||||||
s.last = i
|
|
||||||
|
|
||||||
|
|
||||||
proc insert*(s: var ColorStack, c: Color, idx: Natural = 0) =
|
|
||||||
for i in countdown(s.last, int8(idx)):
|
|
||||||
swap(s.pieces[i], s.pieces[i + 1]) # will also raise exception if out of bounds
|
|
||||||
s.pieces[idx] = int8(c)
|
|
||||||
inc s.last
|
|
||||||
|
|
||||||
|
|
||||||
proc delete*(s: var ColorStack, idx: Natural) =
|
|
||||||
if idx > s.last:
|
|
||||||
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
|
|
||||||
s.pieces[idx] = -1
|
|
||||||
dec s.last
|
|
||||||
for i in int8(idx) .. s.last:
|
|
||||||
swap(s.pieces[i], s.pieces[i + 1])
|
|
||||||
|
|
||||||
|
|
||||||
proc find(s: ColorStack, c: Color): int8 =
|
|
||||||
let needle = int(c)
|
|
||||||
for i, v in s.pieces:
|
|
||||||
if v == needle:
|
|
||||||
return i
|
|
||||||
return -1
|
|
||||||
|
|
||||||
|
|
||||||
proc moveSubstack*(src, dst: var ColorStack; start: Natural) =
|
|
||||||
var count = 0 # have to track this separately apparently
|
|
||||||
for idx in (int8(start) .. src.last):
|
|
||||||
swap(src.pieces[idx], dst.pieces[dst.last + 1 + count])
|
|
||||||
inc count
|
|
||||||
dst.last += int8(count)
|
|
||||||
src.last -= int8(count)
|
|
||||||
|
|
||||||
|
|
||||||
proc moveSubstackPre*(src, dst: var ColorStack; start: Natural) =
|
|
||||||
let ssLen = src.last - start + 1 # length of substack
|
|
||||||
for i in countdown(dst.last, 0):
|
|
||||||
swap(dst.pieces[i], dst.pieces[i + ssLen])
|
|
||||||
|
|
||||||
var count = 0
|
|
||||||
for i in start .. src.last:
|
|
||||||
swap(src.pieces[i], dst.pieces[count])
|
|
||||||
inc count
|
|
||||||
|
|
||||||
dst.last += int8(ssLen)
|
|
||||||
src.last -= int8(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"
|
|
@ -1,7 +1,8 @@
|
|||||||
import algorithm, sequtils
|
import sequtils
|
||||||
|
import fixedseq, game
|
||||||
|
|
||||||
|
|
||||||
iterator allPermutations*[T](x: seq[T]): seq[T] =
|
iterator allPermutations*(x: FixedSeq): FixedSeq =
|
||||||
# returns all permutations of a given seq. Order is wonky but we don't care.
|
# returns all permutations of a given seq. Order is wonky but we don't care.
|
||||||
var workingCopy = x
|
var workingCopy = x
|
||||||
yield workingCopy
|
yield workingCopy
|
||||||
@ -12,12 +13,12 @@ iterator allPermutations*[T](x: seq[T]): seq[T] =
|
|||||||
yield workingCopy
|
yield workingCopy
|
||||||
|
|
||||||
|
|
||||||
iterator allDigits*(lo, hi, size: Natural): seq[int] =
|
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
|
||||||
# we use uninitialized since we will initialize it below, but not necessarily with 0s
|
var digits: FixedSeq[5, int8, int8]
|
||||||
var digits = newSeqUninitialized[int](size)
|
digits.initFixedSeq
|
||||||
for i in 0 .. digits.high:
|
for i in 0 ..< size:
|
||||||
digits[i] = lo
|
digits.add(lo)
|
||||||
|
|
||||||
var complete = false
|
var complete = false
|
||||||
while not complete:
|
while not complete:
|
||||||
@ -32,9 +33,12 @@ iterator allDigits*(lo, hi, size: Natural): seq[int] =
|
|||||||
digits[i] = lo
|
digits[i] = lo
|
||||||
|
|
||||||
|
|
||||||
iterator possibleFutures*[C](dice: seq[C]): seq[tuple[color: C, value: int]] =
|
iterator possibleFutures*(dice: FixedSeq): auto =
|
||||||
# iterate over all possible sequences of die rolls. Each outcome
|
# iterate over all possible sequences of die rolls. Each outcome
|
||||||
# is returned as a 5-sequence of (color, number) tuples.
|
# is returned as a 5-sequence of (color, number) tuples.
|
||||||
for perm in dice.allPermutations:
|
for perm in dice.allPermutations:
|
||||||
for d in allDigits(1, 3, dice.len):
|
for digits in allDigits(1, 3, dice.len):
|
||||||
yield zip(perm, d)
|
var f = initFixedSeq(5, Die, int8)
|
||||||
|
for i in 0 .. dice.high:
|
||||||
|
f.add((perm[i], digits[i]))
|
||||||
|
yield f
|
135
fixedseq.nim
Normal file
135
fixedseq.nim
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import algorithm
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
FixedSeq*[Idx: static int; Contents; Pointer: SomeSignedInt] = object
|
||||||
|
data: array[Idx, Contents]
|
||||||
|
last: Pointer
|
||||||
|
|
||||||
|
|
||||||
|
proc initFixedSeq*(size: static Natural; cType: typedesc; pType: typedesc[SomeSignedInt]): auto =
|
||||||
|
var s: FixedSeq[size, cType, pType]
|
||||||
|
s.last = -1
|
||||||
|
result = s
|
||||||
|
|
||||||
|
proc initFixedSeq*(s: var FixedSeq) =
|
||||||
|
s.last = -1
|
||||||
|
|
||||||
|
|
||||||
|
proc `[]`*(s: var FixedSeq, i: Natural): var FixedSeq.Contents =
|
||||||
|
if i > s.last:
|
||||||
|
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
||||||
|
s.data[i]
|
||||||
|
|
||||||
|
|
||||||
|
proc `[]`*(s: FixedSeq, i: BackwardsIndex): auto =
|
||||||
|
if s.last == -1:
|
||||||
|
raise newException(IndexDefect, "index out of bounds, the container is empty.") # matching stdlib again
|
||||||
|
s.data[s.last - typeof(s.last)(i) + 1]
|
||||||
|
|
||||||
|
|
||||||
|
proc `[]=`*(s: var FixedSeq, i: Natural, v: FixedSeq.Contents) =
|
||||||
|
if i > s.last:
|
||||||
|
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
||||||
|
s.data[i] = v
|
||||||
|
|
||||||
|
|
||||||
|
proc high*(s: FixedSeq): auto =
|
||||||
|
result = s.last
|
||||||
|
|
||||||
|
|
||||||
|
proc low*(s: FixedSeq): auto =
|
||||||
|
result = case s.last
|
||||||
|
of -1: 0 # a bit weird but it's how the stdlib seq works
|
||||||
|
else: s.last
|
||||||
|
|
||||||
|
|
||||||
|
proc len*(s: FixedSeq): auto =
|
||||||
|
result = s.last + 1
|
||||||
|
|
||||||
|
|
||||||
|
iterator items*(s: FixedSeq): auto =
|
||||||
|
for i in 0 .. s.last:
|
||||||
|
yield s.data[i]
|
||||||
|
|
||||||
|
|
||||||
|
iterator asInt*(s: FixedSeq): int8 =
|
||||||
|
for i in 0 .. s.last:
|
||||||
|
yield int8(s.data[i]) # now we do have to convert
|
||||||
|
|
||||||
|
|
||||||
|
iterator pairs*(s: FixedSeq): auto =
|
||||||
|
var count = 0
|
||||||
|
for c in s:
|
||||||
|
yield (count, c)
|
||||||
|
inc count
|
||||||
|
|
||||||
|
|
||||||
|
proc add*(s: var FixedSeq, v: FixedSeq.Contents) =
|
||||||
|
let i = s.last + 1
|
||||||
|
s.data[i] = v # will raise exception if out of bounds
|
||||||
|
s.last = i
|
||||||
|
|
||||||
|
|
||||||
|
proc insert*(s: var FixedSeq, v: FixedSeq.Contents, idx: Natural = 0) =
|
||||||
|
for i in countdown(s.last, typeof(s.last)(idx)):
|
||||||
|
swap(s.data[i], s.data[i + 1]) # will also raise exception if out of bounds
|
||||||
|
s.data[idx] = v
|
||||||
|
inc s.last
|
||||||
|
|
||||||
|
|
||||||
|
proc delete*(s: var FixedSeq, idx: Natural) =
|
||||||
|
if idx > s.last:
|
||||||
|
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
|
||||||
|
s.data[idx] = -1
|
||||||
|
dec s.last
|
||||||
|
for i in typeof(s.last)(idx) .. s.last:
|
||||||
|
swap(s.data[i], s.data[i + 1])
|
||||||
|
|
||||||
|
|
||||||
|
proc find*(s: FixedSeq, needle: FixedSeq.Contents): FixedSeq.Pointer =
|
||||||
|
for i, v in s.data:
|
||||||
|
if v == needle:
|
||||||
|
return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
proc nextPermutation*(s: var FixedSeq): bool = s.data.nextPermutation
|
||||||
|
|
||||||
|
proc prevPermutation*(s: var FixedSeq): bool = s.data.prevPermutation
|
||||||
|
|
||||||
|
proc maxSize*(s: FixedSeq): FixedSeq.Pointer = s.data.len
|
||||||
|
|
||||||
|
|
||||||
|
proc moveSubstack*(src, dst: var FixedSeq; start: Natural) =
|
||||||
|
var count: typeof(src.last) = 0 # have to track this separately apparently
|
||||||
|
for idx in start .. src.last:
|
||||||
|
swap(src.data[idx], dst.data[dst.last + 1 + count])
|
||||||
|
inc count
|
||||||
|
dst.last += count
|
||||||
|
src.last -= count
|
||||||
|
|
||||||
|
|
||||||
|
proc moveSubstackPre*(src, dst: var FixedSeq; start: Natural) =
|
||||||
|
let ssLen = typeof(src.last)(src.last - start + 1) # length of substack
|
||||||
|
for i in countdown(dst.last, 0):
|
||||||
|
swap(dst.data[i], dst.data[i + ssLen])
|
||||||
|
|
||||||
|
var count = 0
|
||||||
|
for i in start .. src.last:
|
||||||
|
swap(src.data[i], dst.data[count])
|
||||||
|
inc count
|
||||||
|
|
||||||
|
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"
|
133
game.nim
Normal file
133
game.nim
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import hashes, options
|
||||||
|
import fixedseq
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
Color* = enum
|
||||||
|
cRed, cGreen, cBlue, cYellow, cPurple
|
||||||
|
|
||||||
|
ColorStack* = FixedSeq[5, Color, int8]
|
||||||
|
|
||||||
|
|
||||||
|
proc `$`*(s: ColorStack): string =
|
||||||
|
result.add("St@[")
|
||||||
|
for i, color in s:
|
||||||
|
result.add($color)
|
||||||
|
if i < s.high:
|
||||||
|
result.add(", ")
|
||||||
|
result.add("]")
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
Die* = tuple[color: Color, value: int]
|
||||||
|
|
||||||
|
Tile* = enum
|
||||||
|
tBackward = -1,
|
||||||
|
tForward = 1
|
||||||
|
|
||||||
|
Square* = object
|
||||||
|
camels: ColorStack
|
||||||
|
tile: Option[Tile]
|
||||||
|
|
||||||
|
Board* = object
|
||||||
|
squares*: array[1..16, Square]
|
||||||
|
camels*: array[Color, range[1..16]]
|
||||||
|
diceRolled*: array[Color, bool]
|
||||||
|
leader*: Option[Color]
|
||||||
|
gameOver*: bool
|
||||||
|
initialized: bool
|
||||||
|
|
||||||
|
|
||||||
|
const allDice = @[cRed, cGreen, cBlue, cYellow, cPurple]
|
||||||
|
|
||||||
|
|
||||||
|
proc `[]`*[T](b: var Board, idx: T): var Square =
|
||||||
|
b.squares[idx]
|
||||||
|
|
||||||
|
|
||||||
|
proc hash*(b: Board): Hash =
|
||||||
|
var h: Hash = 0
|
||||||
|
# there could be a tile anywhere so we have to check all squares
|
||||||
|
for i, sq in b.squares:
|
||||||
|
if sq.camels.len > 0 or sq.tile.isSome:
|
||||||
|
h = h !& i
|
||||||
|
if sq.tile.isSome:
|
||||||
|
h = h !& int(sq.tile.get) * 10 # so it isn't confused with a camel
|
||||||
|
else:
|
||||||
|
for c in sq.camels.asInt:
|
||||||
|
h = h !& c
|
||||||
|
result = !$h
|
||||||
|
|
||||||
|
|
||||||
|
proc init*(b: var Board) =
|
||||||
|
for sq in b.squares.mitems:
|
||||||
|
sq.camels.initFixedSeq
|
||||||
|
b.initialized = true
|
||||||
|
|
||||||
|
|
||||||
|
proc display*(b: Board, start, stop: int) =
|
||||||
|
for i in start..stop:
|
||||||
|
let sq = b.squares[i]
|
||||||
|
let lead = $i & ": "
|
||||||
|
if sq.tile.isSome:
|
||||||
|
echo lead, sq.tile.get
|
||||||
|
else:
|
||||||
|
echo lead, sq.camels
|
||||||
|
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
|
||||||
|
b[dest].camels.add(color)
|
||||||
|
b.camels[color] = dest
|
||||||
|
|
||||||
|
for (tile, dest) in tiles:
|
||||||
|
b[dest].tile = some(tile)
|
||||||
|
|
||||||
|
let leadCamel = b[max(b.camels)].camels[^1] # top camel in the last currently-occupied space
|
||||||
|
b.leader = some(leadCamel)
|
||||||
|
|
||||||
|
|
||||||
|
proc resetDice*(b: var Board) =
|
||||||
|
var d: array[Color, bool]
|
||||||
|
b.diceRolled = d
|
||||||
|
|
||||||
|
|
||||||
|
proc advance*(b: var Board, die: Die) =
|
||||||
|
let
|
||||||
|
(color, roll) = die
|
||||||
|
startPos = b.camels[color]
|
||||||
|
var endPos = startPos + roll
|
||||||
|
|
||||||
|
if endPos > 16: # camel has passed the finish line
|
||||||
|
b.leader = some(b[startPos].camels[^1])
|
||||||
|
b.gameOver = true
|
||||||
|
return
|
||||||
|
|
||||||
|
var prepend = false
|
||||||
|
if b[endPos].tile.isSome: # adjust position (and possibly stacking) to account for tile
|
||||||
|
let t = b[endPos].tile.get
|
||||||
|
endPos += int(t)
|
||||||
|
if t == tBackward: prepend = true
|
||||||
|
|
||||||
|
let stackStart = b[startPos].camels.find(color)
|
||||||
|
if prepend:
|
||||||
|
b[startPos].camels.moveSubstackPre(b[endPos].camels, stackStart)
|
||||||
|
let stackLen = b[startPos].camels.len - stackStart
|
||||||
|
for i in 0 ..< stackLen:
|
||||||
|
# we know how many camels we added to the bottom, so set the position for each of those
|
||||||
|
b.camels[b[endPos].camels[i]] = endPos
|
||||||
|
else:
|
||||||
|
let dstPrevHigh = b[endPos].camels.high
|
||||||
|
b[startPos].camels.moveSubstack(b[endPos].camels, stackStart)
|
||||||
|
# the camels that have moved start immediately after the previous high camel
|
||||||
|
for i in (dstPrevHigh + 1) .. b[endPos].camels.high:
|
||||||
|
b.camels[b[endPos].camels[i]] = endPos
|
||||||
|
|
||||||
|
# if we are stacking on or moving past the previous leader
|
||||||
|
if endPos >= b.camels[b.leader.get]:
|
||||||
|
b.leader = some(b[endPos].camels[^1])
|
||||||
|
|
||||||
|
b.diceRolled[color] = true
|
130
main.nim
130
main.nim
@ -1,29 +1,8 @@
|
|||||||
import math, hashes, options, tables, sequtils, sets, sugar
|
import math, options, sequtils, sets, sugar
|
||||||
import combinators, colors
|
import combinators, game, fixedseq
|
||||||
|
|
||||||
|
|
||||||
const allDice = @[cRed, cGreen, cBlue, cYellow, cPurple]
|
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Die* = tuple[color: Color, value: int]
|
|
||||||
|
|
||||||
Tile* = enum
|
|
||||||
tBackward = -1,
|
|
||||||
tForward = 1
|
|
||||||
|
|
||||||
Square* = object
|
|
||||||
camels: ColorStack
|
|
||||||
tile: Option[Tile]
|
|
||||||
|
|
||||||
Board* = object
|
|
||||||
squares: array[1..16, Square]
|
|
||||||
camels: array[Color, range[1..16]]
|
|
||||||
diceRolled: array[Color, bool]
|
|
||||||
leader: Option[Color]
|
|
||||||
gameOver: bool
|
|
||||||
initialized: bool
|
|
||||||
|
|
||||||
ScoreSet* = array[Color, int]
|
ScoreSet* = array[Color, int]
|
||||||
|
|
||||||
LegResults* = tuple[scores: ScoreSet, endStates: HashSet[Board]]
|
LegResults* = tuple[scores: ScoreSet, endStates: HashSet[Board]]
|
||||||
@ -34,105 +13,14 @@ proc update*(scores: var ScoreSet, toAdd: ScoreSet) =
|
|||||||
scores[i] += s
|
scores[i] += s
|
||||||
|
|
||||||
|
|
||||||
proc `[]`*[T](b: var Board, idx: T): var Square =
|
|
||||||
b.squares[idx]
|
|
||||||
|
|
||||||
|
|
||||||
proc hash*(b: Board): Hash =
|
|
||||||
var h: Hash = 0
|
|
||||||
# there could be a tile anywhere so we have to check all squares
|
|
||||||
for i, sq in b.squares:
|
|
||||||
if sq.camels.len > 0 or sq.tile.isSome:
|
|
||||||
h = h !& i
|
|
||||||
if sq.tile.isSome:
|
|
||||||
h = h !& int(sq.tile.get) * 10 # so it isn't confused with a camel
|
|
||||||
else:
|
|
||||||
for c in sq.camels.asInt:
|
|
||||||
h = h !& c
|
|
||||||
result = !$h
|
|
||||||
|
|
||||||
|
|
||||||
proc init*(b: var Board) =
|
|
||||||
for sq in b.squares.mitems:
|
|
||||||
sq.camels.init
|
|
||||||
b.initialized = true
|
|
||||||
|
|
||||||
|
|
||||||
proc display(b: Board, start, stop: int) =
|
|
||||||
for i in start..stop:
|
|
||||||
let sq = b.squares[i]
|
|
||||||
let lead = $i & ": "
|
|
||||||
if sq.tile.isSome:
|
|
||||||
echo lead, sq.tile.get
|
|
||||||
else:
|
|
||||||
echo lead, sq.camels
|
|
||||||
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
|
|
||||||
b[dest].camels.add(color)
|
|
||||||
b.camels[color] = dest
|
|
||||||
|
|
||||||
for (tile, dest) in tiles:
|
|
||||||
b[dest].tile = some(tile)
|
|
||||||
|
|
||||||
let leadCamel = b[max(b.camels)].camels[^1] # top camel in the last currently-occupied space
|
|
||||||
b.leader = some(leadCamel)
|
|
||||||
|
|
||||||
|
|
||||||
proc resetDice(b: var Board) =
|
|
||||||
var d: array[Color, bool]
|
|
||||||
b.diceRolled = d
|
|
||||||
|
|
||||||
|
|
||||||
proc advance(b: var Board, die: Die) =
|
|
||||||
let
|
|
||||||
(color, roll) = die
|
|
||||||
startPos = b.camels[color]
|
|
||||||
var endPos = startPos + roll
|
|
||||||
|
|
||||||
if endPos > 16: # camel has passed the finish line
|
|
||||||
b.leader = some(b[startPos].camels[^1])
|
|
||||||
b.gameOver = true
|
|
||||||
return
|
|
||||||
|
|
||||||
var prepend = false
|
|
||||||
if b[endPos].tile.isSome: # adjust position (and possibly stacking) to account for tile
|
|
||||||
let t = b[endPos].tile.get
|
|
||||||
endPos += int(t)
|
|
||||||
if t == tBackward: prepend = true
|
|
||||||
|
|
||||||
let stackStart = b[startPos].camels.find(color)
|
|
||||||
if prepend:
|
|
||||||
b[startPos].camels.moveSubstackPre(b[endPos].camels, stackStart)
|
|
||||||
let stackLen = b[startPos].camels.len - stackStart
|
|
||||||
for i in 0 ..< stackLen:
|
|
||||||
# we know how many camels we added to the bottom, so set the position for each of those
|
|
||||||
b.camels[b[endPos].camels[i]] = endPos
|
|
||||||
else:
|
|
||||||
let dstPrevHigh = b[endPos].camels.high
|
|
||||||
b[startPos].camels.moveSubstack(b[endPos].camels, stackStart)
|
|
||||||
# the camels that have moved start immediately after the previous high camel
|
|
||||||
for i in (dstPrevHigh + 1) .. b[endPos].camels.high:
|
|
||||||
b.camels[b[endPos].camels[i]] = endPos
|
|
||||||
|
|
||||||
# if we are stacking on or moving past the previous leader
|
|
||||||
if endPos >= b.camels[b.leader.get]:
|
|
||||||
b.leader = some(b[endPos].camels[^1])
|
|
||||||
|
|
||||||
b.diceRolled[color] = true
|
|
||||||
|
|
||||||
|
|
||||||
proc projectLeg(b: Board): LegResults =
|
proc projectLeg(b: Board): LegResults =
|
||||||
var scores: ScoreSet
|
var scores: ScoreSet
|
||||||
var endStates: HashSet[Board]
|
var endStates: HashSet[Board]
|
||||||
|
|
||||||
let diceRemaining = collect(newSeq):
|
var diceRemaining: ColorStack
|
||||||
|
diceRemaining.initFixedSeq
|
||||||
for i, c in b.diceRolled:
|
for i, c in b.diceRolled:
|
||||||
if not c: i
|
if not c: diceRemaining.add(i)
|
||||||
|
|
||||||
for future in possibleFutures(diceRemaining):
|
for future in possibleFutures(diceRemaining):
|
||||||
var prediction = b # make a copy
|
var prediction = b # make a copy
|
||||||
@ -174,6 +62,14 @@ b.display(1, 5)
|
|||||||
# b.advance((cRed, 1))
|
# b.advance((cRed, 1))
|
||||||
# b.display(1, 5)
|
# b.display(1, 5)
|
||||||
|
|
||||||
|
# var s: ColorStack
|
||||||
|
# s.initFixedSeq
|
||||||
|
# for i in 0..4:
|
||||||
|
# s.add(Color(i))
|
||||||
|
|
||||||
|
# echo s
|
||||||
|
# echo s[2]
|
||||||
|
|
||||||
let r = b.projectOutcomes(2)
|
let r = b.projectOutcomes(2)
|
||||||
let total = r.sum
|
let total = r.sum
|
||||||
for i, c in r:
|
for i, c in r:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user