NAME

Game::Oware::Terminal - a playable game on two filehandles

VERSION

Version 0.01

SYNOPSIS

use Game::Oware::Terminal;

my $terminal = Game::Oware::Terminal->new(level => 3, seat => 'p1');
my $result = $terminal->start;

DESCRIPTION

It is separate from the engine on purpose

Game::Cribbage is about a thousand lines of escape codes in its top level namespace module, so that only its ::Board was ever reusable by anything else. This is a consumer of the engine exactly as a web adapter would be, and the suite asserts that loading Game::Oware does not pull this in.

in and out are properties

Defaulting to STDIN and STDOUT. That is what makes a terminal testable: the suite drives a whole game in process against in-memory handles, with no pipe, no fork, and no subprocess writing into the TAP stream.

start returns, and never exits

A module that calls exit cannot be tested and cannot be embedded. The exit status belongs to bin/oware, which is the only part that knows it is a program.

Every option is validated in the constructor

An unknown variant, an unknown level or a seat that does not exist all die from BUILD, before a game is built and before anything is printed. Game::Reversi validated its variant three calls deeper and shipped a --variant draughts that died with a raw Perl message and an exit status of 255.

Counts, not glyphs

Oware is a game about numbers and a pile of dots is unreadable past four, so the board shows the seed count in each house. Two things follow.

The letters are the interface, so they are printed above and below the board and the prompt takes one, matching Game::Oware::Notation exactly. A terminal that invented its own numbering would give the distribution two notations.

And there is no alternative glyph set to write for --ascii, unlike the board games in this author's tree, because there are no glyphs. --ascii still picks the plain box drawing, and NO_COLOR still beats everything.

The board is turned round for whoever is looking

Your own six houses are always the bottom row, because the whole spatial vocabulary of this game is "your row" and "their row". The letters do not move: A to F is p1's side and a to f is p2's, in both views and in every line of narration, so two people looking at one game can never disagree about where a house is.

Four moments have to be said in words

Oware's failure mode on a terminal is that the board changes in ways the player cannot account for, so each of these gets a sentence rather than being left to be inferred:

  • a forfeited slam. A capturing move captures nothing. Unexplained, that is a bug report.

  • a sow of twelve or more, which skipped its own house on the way past, so the counts do not add up by eye and the player will count them again.

  • the feeding rule, when it has pruned the move list. The refusal message exists, but a player who never tries the illegal move never sees it.

  • the cycle ending, named as a house rule with the count that triggered it, because a game ending on a rule no book contains has to say so.

The failed-feed ending is a fifth: a seat that cannot move takes its own seeds, which reads backwards to anybody who knows chess.

PROPERTIES

in

The handle to read from. Defaults to STDIN.

out

The handle to write to. Defaults to STDOUT.

level

The bot's level, 1 to 5.

variant

abapa or awari.

seat

Which seat the human plays, p1 or p2.

seed

Passed to the game and, with a suffix, to the bot.

quiet

Suppress the narration and the banner.

ascii

Plain box drawing.

game

The Game::Oware being played. Built by BUILD unless one is supplied, which is how the suite starts from a constructed position.

bot

The Game::Oware::Bot playing the other seat.

METHODS

ansi

Whether to emit escapes. NO_COLOR wins over everything; an explicit ansi option beats the tty check; otherwise it follows whether out is a terminal.

Colour carries no information here: strip every escape and the board reads exactly the same.

rows_for

The house indices of the top and bottom rows, from a seat's point of view.

board_text

The board as a list of lines, from a seat's point of view.

command

One line of input as an instruction: quit, help, board, again for an empty line, or the text itself.

There is no single-letter shortcut for board. b and B are houses, and the first draft of this module accepted b as the command, so typing a perfectly ordinary move redrew the board instead of playing it. q and h are safe because no house is called either.

start

Plays the game and returns its Game::Oware::Result, or undef if the player quit.

SEE ALSO

Game::Oware, Game::Oware::Bot, Game::Oware::Notation

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.