NAME

Game::Reversi::Bot - an opponent that does not simply grab discs

VERSION

Version 0.01

SYNOPSIS

my $bot = Game::Reversi::Bot->new(level => 3, seed => 42);
my $move = $bot->choose($game, $game->turn);
$game->play($game->turn, $move->square) if $move;

$bot->last_search;    # { nodes => 1502, depth => 5, value => 38 }

DESCRIPTION

Reversi is a perfect information game, so this is plain alpha beta. None of the determinisation a hidden information game needs, and none of the anti cheat gate that goes with it, because there is nothing here to peek at.

Maximising discs is the beginner's mistake

Games magazine, November 1982, issue 33, page 46, quoted by Wikipedia:

Although the goal is to finish with the most pieces of your color up, the best strategy, paradoxically, is usually to limit your opponent's options by flipping over as few of his discs as possible during the first two-thirds of the game.

Three things in one sentence, and all three are in the evaluation: disc count is the wrong objective, limiting the opponent's options is the right one, and the switch comes near the end rather than at the start.

The counters are not properties

nodes is incremented once per node, millions of times in a level five search, so the counters the search runs on are a plain hashref carried down the recursion. An accessor call apiece would be the whole cost of the bot, which is the same reason Game::Reversi::Board works on a raw array.

The budget is in nodes, never in seconds

A loaded machine must choose the same move as an idle one, or a bot game stops replaying. The budget is spent through iterative deepening, so running out always leaves a complete search of a shallower depth rather than half of a deeper one.

The numbers are small because the primitives are. legal_moves costs roughly 100 microseconds on the machine this was tuned on, which puts a search node at about the same, so ten thousand nodes is about a second. A host running this inside a web request wants level 3 or below.

The weight table is ours

It is not cited and no quotable source was found for it. What it encodes:

The four corners are worth most, and that part is not a matter of taste: a corner can never be turned. Turning a disc requires the played disc and a bounding disc of the same colour on opposite sides of it along a ray, and a corner has no square on the far side of any ray, so no line through it can ever be closed. The test suite proves that property directly rather than assuming it.

The squares next to a corner are worth least, the diagonal neighbour least of all, because playing there is what hands the corner over. Everything else is small: the middle of the board is nearly worthless in Reversi, which is the opposite of most board games and is why a table written from intuition would be wrong.

The opening is drawn from a seed, not searched

The historic opening places four discs that capture nothing, so the evaluation has almost nothing to say, and there is no book: every opening book ever written starts from the one fixed position Othello uses.

So the choice is drawn from a hash of the bot's own seed and the seat. The seat is not decoration. Without it both bots in a game are the same bot, open the same way every time, and a human reads the rule off two games. Game::Goofspiel on the same site shipped with exactly that fault and every bot game finished level.

Level 5 searches the opening instead, which is not obviously better and is at least different.

METHODS

new

level is 1 to 5 and defaults to 3. seed is the bot's own, and is combined with the seat before use.

level, levels, seed

The level this bot plays at, all of them, and the seed its opening is drawn from.

choose

A Game::Reversi::Move, or undef when the game is over, when it is not that seat's turn, or when there is nothing to play.

What the last call did: nodes, depth, value, and opening for a move that was drawn rather than searched.

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.