NAME
Game::Reversi::Board - the 64 squares, the eight rays, and what outflanks what
VERSION
Version 0.01
SYNOPSIS
use Game::Reversi::Board;
my $board = Game::Reversi::Board->empty;
$board->[ Game::Reversi::Board->square_of('d', 5) ] = 'b';
my @flips = Game::Reversi::Board->flips_for($board, $square, 'b');
my @moves = Game::Reversi::Board->legal_moves($board, 'b');
my $after = Game::Reversi::Board->apply($board, $square, 'b');
DESCRIPTION
The position and nothing above it. Whose turn it is, when a turn is forfeited and when the game ends are rules, and they live in Game::Reversi::Rules.
A board is an arrayref, not an object
Sixty four cells, index row * 8 + col, row 0 being rank 8 and column 0 being file a. So a8 is 0, h1 is 63, and the index reads in the order the board is drawn.
These are class methods taking a board rather than methods on a board object, because the bot's search calls "flips_for" millions of times and an object allocation per node is the difference between a level that searches and a level that gives up. A board holds no invariants, so there is nothing for an object to protect.
A cell holds undef, 'b' or 'w'
Not 0, 1 and 2. Index 0 is a real square and 0 is a plausible spelling of a colour, so a numeric encoding lets if ($board->[$sq]) mean "not black" by accident.
The rays are walked by row and column
Both bounds checked, never by adding a stride to a flat index. A strided walk stays within 0 .. 63 while stepping off the right hand edge of one rank and onto the left hand edge of the next, so a range check on the index cannot see it, and the result is a move that flips discs along a line no player can see.
METHODS
empty
A new board with all 64 cells empty.
clone
A copy of a board.
rays
The eight directions as [drow, dcol] pairs, in the order "flips_for" returns its squares.
other
The opposite colour.
square_of
An index from a file letter and a rank digit. undef for anything off the board.
name_of
The algebraic name of an index, d5 and so on.
flips_for
The squares a disc played at $square by $colour would turn, in ray order. Empty for a square that is already occupied and for a move that outflanks nothing.
legal_moves
Every square where "flips_for" returns something.
has_move
True if legal_moves would return anything, without building the list. The forced pass asks this once per turn, so it is worth not paying for the list.
apply
A new board with the disc placed and every outflanked disc turned. Dies on a move that outflanks nothing, which is a fault in the caller rather than a player's mistake.
count
A hashref of b and w counts. This is not the final score: a game that ends with squares still empty awards them to the winner, which is Game::Reversi::Scoring.
empties
How many squares are still empty.
AUTHOR
LNATION <email@lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under the Artistic License 2.0.