track length instead of last index for fixedseq
This commit is contained in:
parent
63df46eee6
commit
8715e5e354
@ -60,8 +60,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, int, int8]
|
var digits: FixedSeq[5, int]
|
||||||
digits.initFixedSeq
|
|
||||||
for i in 0 ..< size:
|
for i in 0 ..< size:
|
||||||
digits.add(lo)
|
digits.add(lo)
|
||||||
|
|
||||||
@ -78,12 +77,12 @@ iterator allDigits*(lo, hi, size: Natural): auto =
|
|||||||
digits[i] = lo
|
digits[i] = lo
|
||||||
|
|
||||||
|
|
||||||
iterator possibleFutures*(dice: FixedSeq): auto =
|
iterator possibleFutures*(dice: ColorStack): 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 digits in allDigits(1, 3, dice.len):
|
for digits in allDigits(1, 3, dice.len):
|
||||||
var f = initFixedSeq(5, Die, int8)
|
var f: FixedSeq[5, Die]
|
||||||
for i in 0 .. dice.high:
|
for i in 0'u8 .. dice.high:
|
||||||
f.add((perm[i], digits[i]))
|
f.add((color: perm[i], value: digits[i]))
|
||||||
yield f
|
yield f
|
||||||
|
1
cup.nim
1
cup.nim
@ -4,7 +4,6 @@ import game, simulation, ui
|
|||||||
when isMainModule:
|
when isMainModule:
|
||||||
let config = parseArgs()
|
let config = parseArgs()
|
||||||
var b: Board
|
var b: Board
|
||||||
b.init
|
|
||||||
b.setState(config.state)
|
b.setState(config.state)
|
||||||
|
|
||||||
let legScores = b.getLegScores
|
let legScores = b.getLegScores
|
||||||
|
111
fixedseq.nim
111
fixedseq.nim
@ -2,18 +2,9 @@ import random
|
|||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
FixedSeq*[Idx: static int; Contents; Pointer: SomeSignedInt] = object
|
FixedSeq*[Size: static range[0..255], Content] = object
|
||||||
data: array[Idx, Contents]
|
data: array[Size, Content]
|
||||||
last: Pointer
|
len*: uint8
|
||||||
|
|
||||||
|
|
||||||
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: FixedSeq): string =
|
proc `$`*(s: FixedSeq): string =
|
||||||
@ -25,55 +16,51 @@ proc `$`*(s: FixedSeq): string =
|
|||||||
result.add("]")
|
result.add("]")
|
||||||
|
|
||||||
|
|
||||||
proc `[]`*(s: FixedSeq, i: Natural): FixedSeq.Contents =
|
proc `[]`*(s: FixedSeq, idx: Natural): FixedSeq.Content =
|
||||||
when not defined(danger):
|
when not defined(danger):
|
||||||
if i > s.last:
|
if idx.uint8 >= s.len:
|
||||||
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
|
||||||
s.data[i]
|
s.data[idx]
|
||||||
|
|
||||||
|
|
||||||
proc `[]`*(s: var FixedSeq, i: Natural): var FixedSeq.Contents =
|
proc `[]`*(s: var FixedSeq, idx: Natural): var FixedSeq.Content =
|
||||||
when not defined(danger):
|
when not defined(danger):
|
||||||
if i > s.last:
|
if idx.uint8 >= s.len:
|
||||||
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
|
||||||
s.data[i]
|
s.data[idx]
|
||||||
|
|
||||||
|
|
||||||
proc `[]`*(s: FixedSeq, i: BackwardsIndex): auto =
|
proc `[]`*(s: FixedSeq, idx: BackwardsIndex): auto =
|
||||||
when not defined(danger):
|
when not defined(danger):
|
||||||
if s.last == -1:
|
if s.len == 0:
|
||||||
raise newException(IndexDefect, "index out of bounds, the container is empty.") # matching stdlib again
|
raise newException(IndexDefect, "index out of bounds, the container is empty.") # matching stdlib again
|
||||||
s.data[s.last - typeof(s.last)(i) + 1]
|
s.data[s.len - idx.uint8]
|
||||||
|
|
||||||
|
|
||||||
proc `[]=`*(s: var FixedSeq, i: Natural, v: FixedSeq.Contents) =
|
proc `[]=`*(s: var FixedSeq, idx: Natural, v: FixedSeq.Content) =
|
||||||
when not defined(danger):
|
when not defined(danger):
|
||||||
if i > s.last:
|
if idx.uint8 >= s.len:
|
||||||
raise newException(IndexDefect, "index " & $i & " is out of bounds.")
|
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
|
||||||
s.data[i] = v
|
s.data[idx] = v
|
||||||
|
|
||||||
|
|
||||||
proc high*(s: FixedSeq): auto =
|
proc high*(s: FixedSeq): auto =
|
||||||
result = s.last
|
result = s.len - 1
|
||||||
|
|
||||||
|
|
||||||
proc low*(s: FixedSeq): auto =
|
proc low*(s: FixedSeq): auto =
|
||||||
result = case s.last
|
result = case s.len
|
||||||
of -1: 0 # a bit weird but it's how the stdlib seq works
|
of 0: 0 # a bit weird but it's how the stdlib seq works
|
||||||
else: s.last
|
else: s.len - 1
|
||||||
|
|
||||||
|
|
||||||
proc len*(s: FixedSeq): auto =
|
|
||||||
result = s.last + 1
|
|
||||||
|
|
||||||
|
|
||||||
iterator items*(s: FixedSeq): auto =
|
iterator items*(s: FixedSeq): auto =
|
||||||
for i in 0 .. s.last:
|
for i in 0'u8 ..< s.len:
|
||||||
yield s.data[i]
|
yield s.data[i]
|
||||||
|
|
||||||
|
|
||||||
iterator asInt*(s: FixedSeq): int8 =
|
iterator asInt*(s: FixedSeq): int8 =
|
||||||
for i in 0 .. s.last:
|
for i in 0'u8 ..< s.len:
|
||||||
yield int8(s.data[i]) # now we do have to convert
|
yield int8(s.data[i]) # now we do have to convert
|
||||||
|
|
||||||
|
|
||||||
@ -84,34 +71,32 @@ iterator pairs*(s: FixedSeq): auto =
|
|||||||
inc count
|
inc count
|
||||||
|
|
||||||
|
|
||||||
proc add*(s: var FixedSeq, v: FixedSeq.Contents) =
|
proc add*(s: var FixedSeq, v: FixedSeq.Content) =
|
||||||
let i = s.last + 1
|
s.data[s.len] = v # will raise exception if out of bounds
|
||||||
s.data[i] = v # will raise exception if out of bounds
|
inc s.len
|
||||||
s.last = i
|
|
||||||
|
|
||||||
|
|
||||||
proc insert*(s: var FixedSeq, v: FixedSeq.Contents, idx: Natural = 0) =
|
proc insert*(s: var FixedSeq, v: FixedSeq.Content, idx: Natural = 0) =
|
||||||
for i in countdown(s.last, typeof(s.last)(idx)):
|
for i in countdown(s.len - 1, idx.uint8):
|
||||||
swap(s.data[i], s.data[i + 1]) # will also raise exception if out of bounds
|
swap(s.data[i], s.data[i + 1]) # will also raise exception if out of bounds
|
||||||
s.data[idx] = v
|
s.data[idx] = v
|
||||||
inc s.last
|
inc s.len
|
||||||
|
|
||||||
|
|
||||||
proc delete*(s: var FixedSeq, idx: Natural) =
|
proc delete*(s: var FixedSeq, idx: Natural) =
|
||||||
when not defined(danger):
|
when not defined(danger):
|
||||||
if idx > s.last:
|
if idx.uint8 >= s.len:
|
||||||
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
|
raise newException(IndexDefect, "index " & $idx & " is out of bounds.")
|
||||||
s.data[idx] = -1 # do we even need this?
|
dec s.len
|
||||||
dec s.last
|
for i in idx.uint8 ..< s.len:
|
||||||
for i in typeof(s.last)(idx) .. s.last:
|
|
||||||
swap(s.data[i], s.data[i + 1])
|
swap(s.data[i], s.data[i + 1])
|
||||||
|
|
||||||
|
|
||||||
proc clear*(s: var FixedSeq) =
|
proc clear*(s: var FixedSeq) =
|
||||||
s.last = -1
|
s.len = 0
|
||||||
|
|
||||||
|
|
||||||
proc find*(s: FixedSeq, needle: FixedSeq.Contents): FixedSeq.Pointer =
|
proc find*(s: FixedSeq, needle: FixedSeq.Content): int =
|
||||||
for i, v in s.data:
|
for i, v in s.data:
|
||||||
if v == needle:
|
if v == needle:
|
||||||
return i
|
return i
|
||||||
@ -129,30 +114,36 @@ proc reverse*(s: var FixedSeq; first, last: Natural) =
|
|||||||
|
|
||||||
|
|
||||||
proc shuffle*(s: var FixedSeq, r: var Rand) =
|
proc shuffle*(s: var FixedSeq, r: var Rand) =
|
||||||
|
when not defined(danger):
|
||||||
|
if s.len < s.data.len.uint8:
|
||||||
|
raise newException(IndexDefect, "Cannot shuffle a partially-full FixedSeq")
|
||||||
r.shuffle(s.data)
|
r.shuffle(s.data)
|
||||||
|
|
||||||
proc shuffle*(s: var FixedSeq) =
|
proc shuffle*(s: var FixedSeq) =
|
||||||
|
when not defined(danger):
|
||||||
|
if s.len < s.data.len.uint8:
|
||||||
|
raise newException(IndexDefect, "Cannot shuffle a partially-full FixedSeq")
|
||||||
shuffle(s.data)
|
shuffle(s.data)
|
||||||
|
|
||||||
|
|
||||||
proc moveSubstack*(src, dst: var FixedSeq; start: Natural) =
|
proc moveSubstack*(src, dst: var FixedSeq; start: Natural) =
|
||||||
var count: typeof(src.last) = 0 # have to track this separately apparently
|
var count = 0'u8 # have to track this separately apparently
|
||||||
for idx in start .. src.last:
|
for idx in start ..< src.len:
|
||||||
swap(src.data[idx], dst.data[dst.last + 1 + count])
|
swap(src.data[idx], dst.data[dst.len + count])
|
||||||
inc count
|
inc count
|
||||||
dst.last += count
|
dst.len += count
|
||||||
src.last -= count
|
src.len -= count
|
||||||
|
|
||||||
|
|
||||||
proc moveSubstackPre*(src, dst: var FixedSeq; start: Natural) =
|
proc moveSubstackPre*(src, dst: var FixedSeq; start: Natural) =
|
||||||
let ssLen = typeof(src.last)(src.last - start + 1) # length of substack
|
let ssLen = src.len - start.uint8 # length of substack
|
||||||
for i in countdown(dst.last, 0):
|
for i in countdown(dst.len - 1, 0):
|
||||||
swap(dst.data[i], dst.data[i + ssLen])
|
swap(dst.data[i], dst.data[i + ssLen])
|
||||||
|
|
||||||
var count = 0
|
var count = 0
|
||||||
for i in start .. src.last:
|
for i in start ..< src.len:
|
||||||
swap(src.data[i], dst.data[count])
|
swap(src.data[i], dst.data[count])
|
||||||
inc count
|
inc count
|
||||||
|
|
||||||
dst.last += ssLen
|
dst.len += ssLen
|
||||||
src.last -= ssLen
|
src.len -= ssLen
|
||||||
|
42
game.nim
42
game.nim
@ -6,20 +6,9 @@ type
|
|||||||
Color* = enum
|
Color* = enum
|
||||||
cRed, cGreen, cBlue, cYellow, cPurple
|
cRed, cGreen, cBlue, cYellow, cPurple
|
||||||
|
|
||||||
ColorStack* = FixedSeq[5, Color, int8]
|
ColorStack* = FixedSeq[5, Color]
|
||||||
|
|
||||||
|
const
|
||||||
proc initColorStack*: ColorStack =
|
|
||||||
result.initFixedSeq
|
|
||||||
|
|
||||||
|
|
||||||
proc getAllColors: ColorStack =
|
|
||||||
var i = 0
|
|
||||||
for c in Color.low .. Color.high:
|
|
||||||
result[i] = c
|
|
||||||
|
|
||||||
const
|
|
||||||
allColors* = getAllColors()
|
|
||||||
colorNames: array[Color, string] =
|
colorNames: array[Color, string] =
|
||||||
["Red", "Green", "Blue", "Yellow", "Purple"]
|
["Red", "Green", "Blue", "Yellow", "Purple"]
|
||||||
colorAbbrevs: array[Color, char] = ['R', 'G', 'B', 'Y', 'P']
|
colorAbbrevs: array[Color, char] = ['R', 'G', 'B', 'Y', 'P']
|
||||||
@ -37,7 +26,7 @@ proc `$`*(s: ColorStack): string =
|
|||||||
result.add("St@[")
|
result.add("St@[")
|
||||||
for i, color in s:
|
for i, color in s:
|
||||||
result.add($color)
|
result.add($color)
|
||||||
if i < s.high:
|
if i.uint8 < s.high:
|
||||||
result.add(", ")
|
result.add(", ")
|
||||||
result.add("]")
|
result.add("]")
|
||||||
|
|
||||||
@ -55,8 +44,8 @@ type
|
|||||||
|
|
||||||
GameState* = object
|
GameState* = object
|
||||||
dice*: array[Color, bool]
|
dice*: array[Color, bool]
|
||||||
camels*: FixedSeq[5, tuple[c: Color, p: range[1..16]], int8]
|
camels*: FixedSeq[5, tuple[c: Color, p: range[1..16]]]
|
||||||
tiles*: FixedSeq[8, tuple[t: Tile, p: range[1..16]], int8] # max 8 players, so max 8 tiles
|
tiles*: FixedSeq[8, tuple[t: Tile, p: range[1..16]]] # max 8 players, so max 8 tiles
|
||||||
|
|
||||||
Board* = object
|
Board* = object
|
||||||
squares*: array[1..16, Square]
|
squares*: array[1..16, Square]
|
||||||
@ -64,15 +53,6 @@ type
|
|||||||
diceRolled*: array[Color, bool]
|
diceRolled*: array[Color, bool]
|
||||||
winner*: Option[Color]
|
winner*: Option[Color]
|
||||||
gameOver*: bool
|
gameOver*: bool
|
||||||
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
|
# use a template here for better inlining
|
||||||
@ -98,12 +78,6 @@ proc hash*(b: Board): Hash =
|
|||||||
result = !$h
|
result = !$h
|
||||||
|
|
||||||
|
|
||||||
proc init*(b: var Board) =
|
|
||||||
for sq in b.squares.mitems:
|
|
||||||
sq.camels.initFixedSeq
|
|
||||||
b.initialized = true
|
|
||||||
|
|
||||||
|
|
||||||
proc leader*(b: Board): Color =
|
proc leader*(b: Board): Color =
|
||||||
let leadSquare = max(b.camels)
|
let leadSquare = max(b.camels)
|
||||||
result = b[leadSquare].camels[^1]
|
result = b[leadSquare].camels[^1]
|
||||||
@ -138,7 +112,6 @@ proc setState*(b: var Board; state: GameState) =
|
|||||||
|
|
||||||
|
|
||||||
proc getState*(b: Board): GameState =
|
proc getState*(b: Board): GameState =
|
||||||
result.init
|
|
||||||
var camelCount = 0
|
var camelCount = 0
|
||||||
let start = min(b.camels)
|
let start = min(b.camels)
|
||||||
for pos in start .. b.squares.high:
|
for pos in start .. b.squares.high:
|
||||||
@ -156,7 +129,6 @@ proc getState*(b: Board): GameState =
|
|||||||
|
|
||||||
|
|
||||||
proc diceRemaining*(b: Board): ColorStack =
|
proc diceRemaining*(b: Board): ColorStack =
|
||||||
result.initFixedSeq
|
|
||||||
for color, isRolled in b.diceRolled:
|
for color, isRolled in b.diceRolled:
|
||||||
if not isRolled: result.add(color)
|
if not isRolled: result.add(color)
|
||||||
|
|
||||||
@ -183,11 +155,11 @@ proc advance*(b: var Board, die: Die) =
|
|||||||
endPos += int(t)
|
endPos += int(t)
|
||||||
if t == tBackward: prepend = true
|
if t == tBackward: prepend = true
|
||||||
|
|
||||||
let stackStart = b[startPos].camels.find(color)
|
let stackStart = cast[uint8](b[startPos].camels.find(color)) # cast is safe here, as long as b.camels is valid
|
||||||
if prepend:
|
if prepend:
|
||||||
b[startPos].camels.moveSubstackPre(b[endPos].camels, stackStart)
|
b[startPos].camels.moveSubstackPre(b[endPos].camels, stackStart)
|
||||||
let stackLen = b[startPos].camels.len - stackStart
|
let stackLen = b[startPos].camels.len - stackStart
|
||||||
for i in 0 ..< stackLen:
|
for i in 0'u8 ..< stackLen:
|
||||||
# we know how many camels we added to the bottom, so set the position for each of those
|
# 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
|
b.camels[b[endPos].camels[i]] = endPos
|
||||||
else:
|
else:
|
||||||
|
@ -39,7 +39,6 @@ proc percents*(scores: ScoreSet): WinPercents =
|
|||||||
|
|
||||||
iterator legEndStates(b: Board): Board =
|
iterator legEndStates(b: Board): Board =
|
||||||
var diceRemaining: ColorStack
|
var diceRemaining: ColorStack
|
||||||
diceRemaining.initFixedSeq
|
|
||||||
for i, c in b.diceRolled:
|
for i, c in b.diceRolled:
|
||||||
if not c: diceRemaining.add(i)
|
if not c: diceRemaining.add(i)
|
||||||
|
|
||||||
|
8
test.nim
8
test.nim
@ -32,16 +32,10 @@ proc summarize(tr: TestResults, opname = "operations") =
|
|||||||
stdout.flushFile()
|
stdout.flushFile()
|
||||||
|
|
||||||
|
|
||||||
# proc getRand(): Rand =
|
|
||||||
# randomize()
|
|
||||||
# result = initRand(rand(int64))
|
|
||||||
|
|
||||||
|
|
||||||
proc newRandomGame(): Board =
|
proc newRandomGame(): Board =
|
||||||
randomize()
|
randomize()
|
||||||
result.init
|
|
||||||
|
|
||||||
var state = newGameState()
|
var state: GameState
|
||||||
for i in 0 .. 4:
|
for i in 0 .. 4:
|
||||||
let pos = rand(1..3)
|
let pos = rand(1..3)
|
||||||
state.camels.add((c: Color(i), p: pos))
|
state.camels.add((c: Color(i), p: pos))
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
--threads: on
|
--threads: on
|
||||||
--d: danger
|
--d: danger
|
||||||
--d: lto
|
--d: lto
|
||||||
--opt: speed
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user