Core game (src/core/)
Pure game logic with no I/O and no rendering. Every other layer depends on this one; this layer depends on nothing else in the package.
Types and constants (struct.jl)
Reversi.IN_PROGRESS — Constant
Result sentinel: game is still in progress (not yet finished).
Reversi.ZOBRIST_TABLE — Constant
ZOBRIST_TABLE128-entry table of random UInt64 values indexed by [row, col, color_idx] (color_idx 1 = BLACK, 2 = WHITE) used for incremental Zobrist hashing.
Reversi.Position — Type
PositionRepresents a position on the Reversi board (row, col). Supports construction from standard Reversi notation (e.g. "e4").
Reversi.Position — Method
Position(s::AbstractString) -> PositionParse a standard Reversi notation string (e.g. "e4") into a Position. Column letters a–h map to columns 1–8; row digits 1–8 map to rows 1–8.
Examples
Position("e4") # Position(4, 5)
Position("a1") # Position(1, 1)Reversi.ReversiGame — Type
ReversiGameRepresents the state of a Reversi game using two UInt64 bitboards.
Fields:
black::UInt64– bitmask of squares occupied by Blackwhite::UInt64– bitmask of squares occupied by Whitecurrent_player::Int–BLACKorWHITEpass_count::Int– consecutive passes (≥ 2 → game over)hash::UInt64– incremental Zobrist hash of the current position
Reversi.compute_full_hash — Method
compute_full_hash(game::ReversiGame) -> UInt64Compute the Zobrist hash of game from scratch. Useful for debugging.
Reversi.position_to_string — Method
position_to_string(pos::Position) -> StringConvert a Position to standard Reversi notation (e.g. Position(4, 5) → "e4").
Reversi.update_hash — Method
update_hash(current_hash, row, col, color) -> UInt64Toggle one piece of color at (row, col) in the hash (add or remove).
Rules and bitboard logic (rules.jl)
Reversi.board_to_matrix — Method
board_to_matrix(game::ReversiGame; flip_for_current=true) -> Array{Float32, 2}Encode the 8x8 board as a matrix of Float32. If flip_for_current=true, the current_player's pieces are 1.0f0 and the opponent's are -1.0f0. Empty squares are 0.0f0.
Reversi.compute_flips — Method
compute_flips(pos, player, opponent) -> UInt64Return a bitmask of opponent pieces that would be flipped when player places at the single-bit position pos.
Reversi.count_pieces — Method
count_pieces(game) -> (Int, Int)Return (black_count, white_count).
Reversi.get_piece — Method
get_piece(game, row, col) -> IntReturn BLACK, WHITE, or EMPTY for the given square.
Reversi.get_winner — Method
get_winner(game) -> IntReturn BLACK, WHITE, or EMPTY (draw) based on piece counts.
Reversi.is_game_over — Method
is_game_over(game) -> BoolReturn true when the game has ended (two consecutive passes, board full, or neither player has any legal move).
Reversi.is_valid_move — Function
is_valid_move(game, row, col[, player]) -> BoolCheck if placing a piece at (row, col) is legal for player.
Reversi.is_valid_position — Method
is_valid_position(row::Int, col::Int) -> BoolCheck if a position is within the board boundaries.
Reversi.legal_moves_bb — Method
legal_moves_bb(player, opponent) -> UInt64Return a bitmask of all squares where player can legally place a piece (Kogge-Stone Dumb7Fill in each of the 8 directions).
Reversi.make_move! — Method
make_move!(game, s) -> BoolMake a move specified in standard Reversi notation (e.g. "e4").
Reversi.make_move! — Method
make_move!(game, row, col) -> BoolPlace a piece at (row, col) for the current player. Updates the board and the Zobrist hash. Returns true on success, false if the move is illegal.
Reversi.make_move! — Method
make_move!(game, pos) -> BoolMake a move at the given Position.
Reversi.mobility — Function
mobility(game[, player]) -> IntReturn the number of legal moves available to player (defaults to game.current_player). A commonly used feature in evaluation.
Reversi.next_state — Method
next_state(game, move) -> ReversiGameReturn a new ReversiGame resulting from applying move to a copy of game. The original game is not modified.
Reversi.opponent — Method
opponent(player::Int) -> IntReturns the opponent's color.
Reversi.pass! — Method
pass!(game; force=false)Pass the turn to the opponent.
If force=false (default), throws ArgumentError when the current player still has at least one legal move — callers must only pass when genuinely stuck. Set force=true to skip the check (useful for replaying external records or tests).
Reversi.valid_moves — Function
valid_moves(game[, player]) -> Vector{Position}Return all valid moves for player (defaults to game.current_player).
Player interface (player.jl)
Reversi.GreedyPlayer — Type
GreedyPlayer <: PlayerA player that always picks the move that flips the most pieces.
Reversi.HumanPlayer — Type
HumanPlayer <: PlayerA human player that can receive moves from any interface (GUI, terminal, etc.) via its internal move_channel.
Use get_move(player, game) to wait for the next move.
Reversi.Player — Type
PlayerAbstract type for all player implementations. Subtype and implement get_move(player, game) to create a new player.
Reversi.RandomPlayer — Type
RandomPlayer <: PlayerA player that picks a random valid move each turn.
Reversi.get_move — Function
get_move(player::Player, game::ReversiGame) -> Union{Position, Nothing}Get the next move from a player. Returns nothing to indicate a pass.
Reversi.get_terminal_input — Method
get_terminal_input(game::ReversiGame; hints=true) -> Union{Position, Nothing}A helper for CLI frontends to get move input from the terminal using readline. Can be used to put! a move into a HumanPlayer's channel.
Classical AI players (ai_players.jl)
Five non-ML players built on the bitboard primitives:
HeuristicPlayer— static positional weight tableCornerPlayer— corner-first then positional fallbackMobilityPlayer— maximises own mobility minus opponent'sMinimaxPlayer(depth)— alpha-beta search on piece-count diffMCTSPlayer(iterations)— UCB1 + random rollout MCTS
Reversi.CornerPlayer — Type
CornerPlayer <: PlayerPicks any available corner move first, then falls back to HeuristicPlayer's positional weights.
Reversi.HeuristicPlayer — Type
HeuristicPlayer <: PlayerA player that picks the move with the highest positional weight. Corners are strongly preferred; corner-adjacent squares are penalised.
Reversi.MCTSPlayer — Type
MCTSPlayer(iterations::Int=200, c::Float64=1.414) <: PlayerMonte Carlo Tree Search with UCB1 selection and random rollouts. iterations controls the number of simulations per move.
Reversi.MinimaxPlayer — Type
MinimaxPlayer(depth::Int=3) <: PlayerAlpha-beta search using a piece-count difference evaluation. depth controls the search depth in plies.
Reversi.MobilityPlayer — Type
MobilityPlayer <: PlayerPicks the move that leaves the opponent with the fewest legal replies while keeping its own mobility high.
Notes
Bitboard layout
Bit index i = (row-1)*8 + (col-1) (0-based), so bit 0 = (1,1) (a1) and bit 63 = (8,8) (h8).
Hash invariant
After every make_move! or pass! call, game.hash == compute_full_hash(game) holds. Tests verify this property throughout random full games.
Copying game state
g2 = copy(game) # fast: copies 5 integer fields
g2 = deepcopy(game) # slower: avoid in hot loopspass! semantics
pass!(game) # throws if current player has legal moves
pass!(game; force=true) # always passes — use only in replay / tests