src/cplib/utils/game

  Source   Edit

Types

NextStates[T] = proc (state: T): seq[T] {.closure.}
  Source   Edit
NextStatesByTurn[T] = proc (state: T; is_first: bool): seq[T] {.closure.}
  Source   Edit

Procs

proc can_win[T](initial_state: T; nxt: NextStates[T];
                win_when_no_moves: bool = false): bool

Returns whether the player at initial_state can force a win.

nxt(state) returns all states reachable in one move. A state with no legal moves is winning exactly when win_when_no_moves is true. The reachable game graph must be finite and acyclic.

Example:

proc subtract(state: int): seq[int] =
    for take in 1..2:
        if take <= state:
            result.add(state - take)

assert can_win(3, subtract) == false
assert can_win(4, subtract) == true
assert can_win(1, subtract, win_when_no_moves = true) == false
  Source   Edit
proc can_win[T](initial_state: T; nxt: NextStatesByTurn[T];
                win_when_no_moves: bool = false): bool

Returns whether the first player can force a win.

nxt(state, is_first) returns all states reachable by the player whose turn it is. is_first is true on the initial turn and is flipped after every move. A state with no legal moves is winning for the player whose turn it is exactly when win_when_no_moves is true. The reachable game graph must be finite and acyclic.

Example:

proc subtract_by_turn(state: int, is_first: bool): seq[int] =
    let max_take = (if is_first: 1 else: 2)
    for take in 1..max_take:
        if take <= state:
            result.add(state - take)

assert can_win(1, subtract_by_turn) == true
assert can_win(2, subtract_by_turn) == false
  Source   Edit