fix mask selection
This commit is contained in:
		@@ -29,7 +29,7 @@ const
 | 
				
			|||||||
template offset(s: ColorStack, idx: Natural): uint8 =
 | 
					template offset(s: ColorStack, idx: Natural): uint8 =
 | 
				
			||||||
  # Compute the bit offset for a given index. 
 | 
					  # Compute the bit offset for a given index. 
 | 
				
			||||||
  # Dependent on the stack's length.
 | 
					  # Dependent on the stack's length.
 | 
				
			||||||
  (s.len - 1 - cast[uint8](idx)) * 3
 | 
					  (s.len - 1 - idx.uint8) * 3
 | 
				
			||||||
  # items are stored from left to right but right-aligned, so we
 | 
					  # items are stored from left to right but right-aligned, so we
 | 
				
			||||||
  # need to shift right to access anything other than the last
 | 
					  # need to shift right to access anything other than the last
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,7 +37,7 @@ template offset(s: ColorStack, idx: Natural): uint8 =
 | 
				
			|||||||
template offset(s: ColorStack, idx: BackwardsIndex): uint8 =
 | 
					template offset(s: ColorStack, idx: BackwardsIndex): uint8 =
 | 
				
			||||||
  # for backwards index, we are still shifting right but
 | 
					  # for backwards index, we are still shifting right but
 | 
				
			||||||
  # the lower the index the less we have to shift
 | 
					  # the lower the index the less we have to shift
 | 
				
			||||||
  (cast[uint8](idx) - 1) * 3
 | 
					  (idx.uint8 - 1) * 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc add*(s: var ColorStack, c: Color) =
 | 
					proc add*(s: var ColorStack, c: Color) =
 | 
				
			||||||
@@ -57,21 +57,21 @@ proc low*(s: ColorStack): uint8 = 0 # just... always 0, I guess
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
proc `[]`*(s: ColorStack, i: uint8 | BackwardsIndex): Color =
 | 
					proc `[]`*(s: ColorStack, i: uint8 | BackwardsIndex): Color =
 | 
				
			||||||
  # shift, then mask everything but the three rightmost bits
 | 
					  # shift, then mask everything but the three rightmost bits
 | 
				
			||||||
  result = cast[Color](
 | 
					  result = Color(
 | 
				
			||||||
    (s.data shr s.offset(i)) and masks[1]
 | 
					    (s.data shr s.offset(i)) and masks[1]
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc `[]=`*(s: var ColorStack, i: uint8 | BackwardsIndex, c: Color) =
 | 
					proc `[]=`*(s: var ColorStack, i: uint8 | BackwardsIndex, c: Color) =
 | 
				
			||||||
  let offset = s.offset(i)
 | 
					  let offset = s.offset(i)
 | 
				
			||||||
  s.data = (s.data and bitnot(masks[1] shl offset)) or (cast[uint16](c) shl offset)
 | 
					  s.data = (s.data and bitnot(masks[1] shl offset)) or (c.uint16 shl offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
iterator items*(s: ColorStack): Color =
 | 
					iterator items*(s: ColorStack): Color =
 | 
				
			||||||
  # s.len is unsigned so it will wrap around if we do s.len - 1 in that case
 | 
					  # s.len is unsigned so it will wrap around if we do s.len - 1 in that case
 | 
				
			||||||
  if s.len != 0:
 | 
					  if s.len != 0:
 | 
				
			||||||
    for i in countdown(s.len - 1, 0'u8):
 | 
					    for i in countdown(s.len - 1, 0'u8):
 | 
				
			||||||
      yield cast[Color]((s.data shr (i * 3)) and masks[1])
 | 
					      yield Color((s.data shr (i * 3)) and masks[1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
iterator pairs*(s: ColorStack): (uint8, Color) =
 | 
					iterator pairs*(s: ColorStack): (uint8, Color) =
 | 
				
			||||||
@@ -81,13 +81,16 @@ iterator pairs*(s: ColorStack): (uint8, Color) =
 | 
				
			|||||||
    inc count
 | 
					    inc count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc find*(s: ColorStack, needle: Color): uint8 =
 | 
					proc find*(s: ColorStack, needle: Color): int8 =
 | 
				
			||||||
  for i in 0'u8 .. s.high:
 | 
					  for i in 0'u8 .. s.high:
 | 
				
			||||||
    if s[i] == needle:
 | 
					    if s[i] == needle:
 | 
				
			||||||
      return i
 | 
					      return i.int8
 | 
				
			||||||
 | 
					  return -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc moveSubstack*(src, dst: var ColorStack, startIdx: uint8) =
 | 
					proc moveSubstack*(src, dst: var ColorStack, startIdx: uint8) =
 | 
				
			||||||
 | 
					  if startIdx >= src.len:
 | 
				
			||||||
 | 
					    raise newException(IndexDefect, "index " & $startIdx & " is out of bounds.")
 | 
				
			||||||
  # Moves a sub-stack from the top of src to the top of dst
 | 
					  # Moves a sub-stack from the top of src to the top of dst
 | 
				
			||||||
  # shift the dst stack by the length of the substack to make room
 | 
					  # shift the dst stack by the length of the substack to make room
 | 
				
			||||||
  let nToMove = src.len - startIdx
 | 
					  let nToMove = src.len - startIdx
 | 
				
			||||||
@@ -95,9 +98,7 @@ proc moveSubstack*(src, dst: var ColorStack, startIdx: uint8) =
 | 
				
			|||||||
  dst.data = dst.data shl shift
 | 
					  dst.data = dst.data shl shift
 | 
				
			||||||
  # then we mask the source data to present only the items 
 | 
					  # then we mask the source data to present only the items 
 | 
				
			||||||
  # being moved, and OR that with the shifted dst data
 | 
					  # being moved, and OR that with the shifted dst data
 | 
				
			||||||
  if src.len > 5:
 | 
					  dst.data = dst.data or (src.data and masks[nToMove])
 | 
				
			||||||
    echo src.len
 | 
					 | 
				
			||||||
  dst.data = dst.data or (src.data and masks[src.len])
 | 
					 | 
				
			||||||
  dst.len += nToMove
 | 
					  dst.len += nToMove
 | 
				
			||||||
  # then we shift the source to get rid of the moved items
 | 
					  # then we shift the source to get rid of the moved items
 | 
				
			||||||
  src.data = src.data shr shift
 | 
					  src.data = src.data shr shift
 | 
				
			||||||
@@ -105,13 +106,16 @@ proc moveSubstack*(src, dst: var ColorStack, startIdx: uint8) =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc moveSubstackPre*(src, dst: var ColorStack, startIdx: uint8) =
 | 
					proc moveSubstackPre*(src, dst: var ColorStack, startIdx: uint8) =
 | 
				
			||||||
 | 
					  if startIdx >= src.len:
 | 
				
			||||||
 | 
					    raise newException(IndexDefect, "index " & $startIdx & " is out of bounds.")
 | 
				
			||||||
  # Moves a sub-stack from the top of src to the bottom of dst
 | 
					  # Moves a sub-stack from the top of src to the bottom of dst
 | 
				
			||||||
  let nToMove = src.len - startIdx
 | 
					  let nToMove = src.len - startIdx
 | 
				
			||||||
  # shift src stack to position substack above its destination,
 | 
					  # shift src to position the substack above its destination,
 | 
				
			||||||
  # get rid of everything to the left of the substack,
 | 
					  # get rid of everything to the left of the substack,
 | 
				
			||||||
  # and OR that with the existing dst data
 | 
					  # and OR that with the existing dst data
 | 
				
			||||||
  dst.data = dst.data or ( (src.data shl (dst.len * 3)) and masks[src.len])
 | 
					  let newLen = dst.len + nToMove
 | 
				
			||||||
  dst.len += nToMove
 | 
					  dst.data = dst.data or ( (src.data shl (dst.len * 3)) and masks[newLen] )
 | 
				
			||||||
 | 
					  dst.len = newLen
 | 
				
			||||||
  # get rid of the substack we just moved
 | 
					  # get rid of the substack we just moved
 | 
				
			||||||
  src.data = src.data shr (nToMove * 3)
 | 
					  src.data = src.data shr (nToMove * 3)
 | 
				
			||||||
  src.len -= nToMove
 | 
					  src.len -= nToMove
 | 
				
			||||||
@@ -142,7 +146,7 @@ proc swap*(s: var ColorStack, i1, i2: uint8) =
 | 
				
			|||||||
proc shuffle*(r: var Rand, s: var ColorStack) =
 | 
					proc shuffle*(r: var Rand, s: var ColorStack) =
 | 
				
			||||||
  # Fisher-Yates shuffle
 | 
					  # Fisher-Yates shuffle
 | 
				
			||||||
  for i in countdown(s.high, 1'u8):
 | 
					  for i in countdown(s.high, 1'u8):
 | 
				
			||||||
    let j = cast[uint8](r.rand(i))
 | 
					    let j = r.rand(i).uint8
 | 
				
			||||||
    if j != i:
 | 
					    if j != i:
 | 
				
			||||||
      s.swap(i, j)
 | 
					      s.swap(i, j)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -170,17 +174,31 @@ proc `$`*(s: ColorStack): string =
 | 
				
			|||||||
  result.add("]")
 | 
					  result.add("]")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var one: ColorStack
 | 
					proc check(s: ColorStack) =
 | 
				
			||||||
one.add(cRed)
 | 
					  # ensure length is accurate
 | 
				
			||||||
one.add(cGreen)
 | 
					  var d = s.data
 | 
				
			||||||
one.add(cBlue)
 | 
					  for i in 0'u8 .. 4'u8:
 | 
				
			||||||
one.add(cYellow)
 | 
					    if (d and masks[1]) > 4:
 | 
				
			||||||
one.add(cPurple)
 | 
					      raise newException(RangeDefect, "Value out of range.")
 | 
				
			||||||
 | 
					    if d > 0 and i >= s.len:
 | 
				
			||||||
 | 
					      raise newException(RangeDefect, "Invalid length.")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					      d = d shr 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var two: ColorStack
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
one.moveSubstack(two, 2)
 | 
					when isMainModule:
 | 
				
			||||||
two.moveSubstackPre(one, 1)
 | 
					  var one: ColorStack
 | 
				
			||||||
 | 
					  one.add(cRed)
 | 
				
			||||||
 | 
					  one.add(cGreen)
 | 
				
			||||||
 | 
					  one.add(cBlue)
 | 
				
			||||||
 | 
					  one.add(cYellow)
 | 
				
			||||||
 | 
					  one.add(cPurple)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo one, " ", one.len
 | 
					  var two: ColorStack
 | 
				
			||||||
echo two, " ", two.len
 | 
					
 | 
				
			||||||
 | 
					  one.moveSubstack(two, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  echo one, " ", one.len
 | 
				
			||||||
 | 
					  echo two, " ", two.len
 | 
				
			||||||
 | 
					  echo two.find(cRed)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								game.nim
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								game.nim
									
									
									
									
									
								
							@@ -141,7 +141,7 @@ 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 = b[startPos].camels.find(color).uint8
 | 
				
			||||||
  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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import cpuinfo, math, options, random, tables
 | 
					import cpuinfo, math, options, random, tables
 | 
				
			||||||
import combinators, game, fixedseq
 | 
					import combinators, game, faststack, fixedseq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type
 | 
					type
 | 
				
			||||||
@@ -59,6 +59,39 @@ proc getLegScores*(b: Board): ScoreSet =
 | 
				
			|||||||
# Full-game simulations
 | 
					# Full-game simulations
 | 
				
			||||||
# =====================
 | 
					# =====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# get rid of this later
 | 
				
			||||||
 | 
					import strutils
 | 
				
			||||||
 | 
					proc showSpaces*(b: Board; start, stop: Natural): string =
 | 
				
			||||||
 | 
					  let numSpaces = stop - start + 1
 | 
				
			||||||
 | 
					  let width = 4 * numSpaces - 1
 | 
				
			||||||
 | 
					  var lines: array[7, string]
 | 
				
			||||||
 | 
					  # start by building up an empty board
 | 
				
			||||||
 | 
					  for i in 0 .. 6: # gotta initialize the strings
 | 
				
			||||||
 | 
					    lines[i] = newString(width)
 | 
				
			||||||
 | 
					    for c in lines[i].mitems:
 | 
				
			||||||
 | 
					      c = ' '
 | 
				
			||||||
 | 
					  # fill in the dividers
 | 
				
			||||||
 | 
					  lines[5] = repeat("=== ", numSpaces - 1)
 | 
				
			||||||
 | 
					  lines[5].add("===")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # now populate the board
 | 
				
			||||||
 | 
					  for sp in 0 ..< numSpaces:
 | 
				
			||||||
 | 
					    # fill in the square numbers
 | 
				
			||||||
 | 
					    let squareNum = sp + start
 | 
				
			||||||
 | 
					    let cellMid = 4 * sp + 1
 | 
				
			||||||
 | 
					    for i, chr in $squareNum:
 | 
				
			||||||
 | 
					      lines[6][cellMid + i] = chr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # fill in the camel stacks
 | 
				
			||||||
 | 
					    for i, color in b.squares[squareNum].camels:
 | 
				
			||||||
 | 
					      let lineNum = 4 - i # lines go to 6, but bottom 2 are reserved
 | 
				
			||||||
 | 
					      let repr = '|' & color.abbrev & '|'
 | 
				
			||||||
 | 
					      for j, chr in repr:
 | 
				
			||||||
 | 
					        lines[lineNum][cellMid - 1 + j] = chr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  result = lines.join("\n")
 | 
				
			||||||
 | 
					# get rid of this later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc randomGame*(b: Board, r: var Rand): Color =
 | 
					proc randomGame*(b: Board, r: var Rand): Color =
 | 
				
			||||||
  var projection = b
 | 
					  var projection = b
 | 
				
			||||||
  while true:
 | 
					  while true:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								test.nim
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								test.nim
									
									
									
									
									
								
							@@ -43,13 +43,13 @@ proc newRandomGame(r: var Rand): Board =
 | 
				
			|||||||
  result.setState(dice, [])
 | 
					  result.setState(dice, [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc games(nTests, nSamples: SomeInteger): TestResults =
 | 
					proc games(nTests, nSamples: SomeInteger, parallel = true): TestResults =
 | 
				
			||||||
  var r = getRand()
 | 
					  var r = getRand()
 | 
				
			||||||
  var scores: ScoreSet
 | 
					  var scores: ScoreSet
 | 
				
			||||||
  for i in 1 .. nTests:
 | 
					  for i in 1 .. nTests:
 | 
				
			||||||
    let b = newRandomGame(r)
 | 
					    let b = newRandomGame(r)
 | 
				
			||||||
    let dur = executionTime:
 | 
					    let dur = executionTime:
 | 
				
			||||||
      let s = b.randomGames(nSamples)
 | 
					        let s = b.randomGames(nSamples, parallel = parallel)
 | 
				
			||||||
    result.ops += s.sum()
 | 
					    result.ops += s.sum()
 | 
				
			||||||
    result.time += dur
 | 
					    result.time += dur
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,17 +94,4 @@ proc testSpread(nTests, nSamples: Natural) =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
when isMainModule:
 | 
					when isMainModule:
 | 
				
			||||||
  games(10, 1_000_000).summarize()
 | 
					  games(10, 10_000_000).summarize()
 | 
				
			||||||
  # let start_states = 2_000
 | 
					 | 
				
			||||||
  # let executionTime = testLegs(start_states)
 | 
					 | 
				
			||||||
  # echo "Execution time: ", executionTime
 | 
					 | 
				
			||||||
  # echo "Leg simulations per second: ", float(start_states * 29_160) / executionTime
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # for i in 1 .. 1:
 | 
					 | 
				
			||||||
  #   let num_games = 100_000_005
 | 
					 | 
				
			||||||
  #   let executionTime = testGames(num_games)
 | 
					 | 
				
			||||||
  #   echo "Execution time: ", executionTime
 | 
					 | 
				
			||||||
  #   echo "Full-game simulations per second: ", float(num_games) / executionTime
 | 
					 | 
				
			||||||
  #   echo ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # testSpread(100, 1_000_000)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user