///|
/// Jump indices refer to holes, not grid offsets.
pub(all) struct Jump {
from : Int
over : Int
to : Int
} derive(Debug, Eq)
///|
fn cell_index(cells : Array[Cell], x : Int, y : Int) -> Int? {
for i = 0; i < cells.length(); i = i + 1 {
if cells[i] == { x, y } {
return Some(i)
}
}
None
}
///|
fn compile_jumps(cells : Array[Cell], lattice : Lattice) -> Array[Jump] {
let jumps : Array[Jump] = []
for i = 0; i < cells.length(); i = i + 1 {
let c = cells[i]
for d in lattice.directions() {
match
(
cell_index(cells, c.x + d.0, c.y + d.1),
cell_index(cells, c.x + 2 * d.0, c.y + 2 * d.1),
) {
(Some(over), Some(to)) => jumps.push({ from: i, over, to })
_ => ()
}
}
}
jumps
}
///|
pub fn Board::jumps(self : Board) -> Array[Jump] {
self.jumps.copy()
}
///|
fn enabled(bits : UInt64, j : Jump) -> Bool {
(bits & bit(j.from)) != 0UL &&
(bits & bit(j.over)) != 0UL &&
(bits & bit(j.to)) == 0UL
}
///|
fn transition(bits : UInt64, j : Jump) -> UInt64 {
bits ^ bit(j.from) ^ bit(j.over) ^ bit(j.to)
}
///|
/// Invalid moves never modify their input position.
pub fn Board::play(
self : Board,
pos : Position,
move_id : Int,
) -> Position raise PegError {
self.validate(pos)
if move_id < 0 || move_id >= self.jumps.length() {
raise InvalidMove(move_id)
}
let j = self.jumps[move_id]
if !enabled(pos.bits, j) {
raise InvalidMove(move_id)
}
{ bits: transition(pos.bits, j) }
}
///|
pub fn Board::legal_moves(
self : Board,
pos : Position,
) -> Array[Int] raise PegError {
self.validate(pos)
let moves = []
for i = 0; i < self.jumps.length(); i = i + 1 {
if enabled(pos.bits, self.jumps[i]) {
moves.push(i)
}
}
moves
}