NAME

Game::Fanorona::Terminal - fanorona in a terminal, by arrow key or by typed move

VERSION

Version 0.03

SYNOPSIS

use Game::Fanorona::Terminal;

exit Game::Fanorona::Terminal->new(human => 'black', level => 4)->start;

Most people want the program, fanorona, which is this with options.

DESCRIPTION

A game of Game::Fanorona played against Game::Fanorona::Bot, between two people at one keyboard, or by the program against itself.

It plays in one of two ways. On a terminal whose keys it can read one at a time, a move is built on the board with the arrow keys. Anywhere else, and whenever it is asked to, it reads a line at a time: a move written out, or a command. The second way needs nothing but two filehandles, so a whole game can be played through a pipe.

The board

5  X---X---X---X---X---X---X---X---X    Black X  22 left  taken 0
   | \ | / | \ | / | \ | / | \ | / |
4  X---X---X---X---X---X---X---X---X
   | / | \ | / | \ | / | \ | / | \ |
3  X---O---X---O---+---X---O---X---O
   | \ | / | \ | / | \ | / | \ | / |
2  O---O---O---O---O---O---O---O---O
   | / | \ | / | \ | / | \ | / | \ |
1  O---O---O---O---O---O---O---O---O    White O  22 left  taken 0
   a   b   c   d   e   f   g   h   i

Every line a stone can step along is drawn. A point with a diagonal running into it is one a stone can leave diagonally; a point with none is not.

The two sides differ in shape as well as in colour: O and X in letters, a ring and a disc otherwise. A mark is a pair of brackets round the point, and with colour a ground behind it as well, so that no mark depends on colour:

[O]   the cursor
<O>   the stone that is moving
(+)   a point it may step to
{*}   a stone this move takes, shown where it stood
:O:   the last move: where the stone went, and :*: what it took
{a}   what a step would take by approach
{w}   what the same step would take by withdrawal

Beside the board are the stones each side has left and has taken, and, once half the limit has gone by, how many moves running have taken nothing.

Choosing a move with the keys

The cursor walks over the stones that can move and over no others. The arrow keys move it to the nearest such stone that way; Tab goes round them in the order they are drawn. Enter picks the stone up.

With a stone picked up, the arrow keys move a second cursor over the points it may step to, and Enter steps it there. Every point is reached that way, the diagonal ones too: up and then right for the point up and to the right. A step can also be made with one key: y, b and n are up-left, down-left and down-right, and the numeric pad has all eight, 9 for up-right. The board then shows the position as it would be: the stone where it has got to and the stones it has taken gone, each marked where it stood. The counts beside the board are of that position too.

When one step could take either the row ahead of the stone or the row behind it, the board marks both rows and waits for a or w. Nothing is chosen for the player.

After a step that has taken, the stone may go on to take again. With the cursor on no point, Enter plays the move as it stands, which is how a player stops; a move is never played until that Enter is pressed, even when only one move is possible. Backspace takes the cursor off a point, and then takes back one step; Escape takes back all of them. The space bar does whatever Enter would. What the other side last played stays written above the board the whole time.

h shows the move the program would play, built on the board and waiting for Enter or Escape. ? lists the keys, R gives the rules, : takes a command and q stops.

u takes back your last move and the program's reply to it; between two people at one keyboard it takes back one move. r plays again what u took back, until another move is made. Both work on the board and once the game is over, where u takes back the move that ended it. With nothing to take back or play again, a line above the board says so and nothing changes; with the program playing both sides there is never anything. The line under the board names whichever of the two would do something.

Typed moves and commands

A move is the points the stone stands on, joined by hyphens, with A or W after each step that takes: d2-e3A, h3-g3W-h4W. The letter may be left off a move of one step when that step can take only one way.

moves        the first step of every legal move, and what it would take
hint         what the program would play
board        draw the board again
undo         take back your last move, and the reply to it
redo         play again what undo took back
level N      how hard the program plays, 1 to 5
side WHO     white, black, both or neither
new          another game; new telo and new dimy change the board
save FILE    write the game to a file
load FILE    read one back
draw         offer a draw; accept and decline answer one
resign       give the game up
rules        the rules
help         the keys and the commands
quit         stop

METHODS

new

my $terminal = Game::Fanorona::Terminal->new(%options);

Every option is also an accessor of the same name.

human

white (the default), black, both or neither: the side or sides played from the keyboard. Anything else croaks.

level

1 to 5, 3 by default: which of "levels" in Game::Fanorona::Bot the program plays at. Anything else croaks.

variant

What "new" in Game::Fanorona takes as variant: a name such as telo, a hash of fields, or a Game::Fanorona::Variant.

game

A Game::Fanorona to carry on with, in place of a new one.

in, out

The filehandles. Standard input and standard output by default.

interactive

Whether out is a screen to be redrawn. True by default when in is a terminal.

colour

Whether to paint. On by default on a terminal, unless NO_COLOR is set.

unicode

Whether the stones are a ring and a disc, or the letters O and X. It follows colour by default.

picking

Whether moves are chosen with the keys. On by default on a terminal, and turned off when the keys cannot be read one at a time, which needs Term::ReadKey.

Whether "start" first asks for the side, the level and the board. Off by default.

width

The width of the window in columns. By default it is asked of the terminal each time the board is drawn. When the board does not fit, a line saying how wide it needs to be is drawn in its place, and no key but q does anything until it fits.

pause

Whether to wait a moment between moves when the program plays both sides.

keysource

A code reference called for each character in place of the keyboard, handed a true value when it should wait for one. It returns one character, or undef at the end. This is how the tests press keys.

options

my $fields = Game::Fanorona::Terminal->options;

The options a person would set before a game, in the order a launcher shows them. Each is a hash reference with a name, a type and a help, and min and max or choices where the type has them. A new list is returned each time.

side

One of white, black, both, neither: your side; White moves first.

level

A whole number from 1 to 5: how hard the program plays.

variant

One of sivy, dimy, telo: the board: nine by five, five by five, or three by three.

run

exit Game::Fanorona::Terminal->run(@ARGV);

The whole command line program as a class method: parses the options the fanorona program documents, builds the terminal, plays, and returns the exit status rather than calling exit: 0 when the game was left in the ordinary way, 2 for a bad option, a stray word, a refused value or a file that could not be loaded, with the reason and the usage on STDERR. --help and --version print to STDOUT and return 0. Given none of --side, --level, --variant and --load, and a terminal whose keys it can read, it begins by asking for the three. Signal handlers are local to the call and the keyboard is given back on every way out, so a launcher such as Game::Terminal can call it in its own process and carry on afterwards. Colour is off under NO_COLOR as well as off a terminal.

start

my $status = $terminal->start;

Plays until the player stops or the input ends, and returns 0. The keyboard is given back as it was found, on the way out and when interrupted.

command

my $stop = $terminal->command('d2-e3A');

Does one line: a command, or else a move. Returns true when the line asks to stop.

load

$terminal->load('saved.txt') or die;

Replaces the game with the one in the file. Returns false, having said why, when the file cannot be read or is not a game.

pick

my $line = $terminal->pick;

Lets the player build one move with the keys and plays it. Returns an empty string once a move has been played, a command for "command" when the player asked for one, and undef when the keys ran out.

take_back

Takes back one step of "history", as u and undo do. Returns false, having said so, when there is none.

play_again

Plays one step again, as r and redo do. Returns false, having said so, when there is none.

swap

$terminal->swap($game);

Replaces the game, puts down a stone being stepped, and forgets the cursor, the last move and what was written above the board. The history is left as it is.

person_turn

Keeps the game in "history": called each time the move passes to a person, and once a game has ended with a person at the keys.

lit

The stones that can move, as an array reference of point names in the order they are drawn: the top row first, each row from the left.

steer

my $name = $terminal->steer('d3', 'up', \@names);

The nearest of the names in that direction from the point, or the point itself when there is none. The direction is one of the keys that steps a stone.

so_far

The move as built so far, written out, or an empty string when the stone has not stepped.

playable

Whether the move as built so far is a whole legal move.

marks

my ($mark, $stones, $sign) = $terminal->marks($mode);

What a drawing shows: the mark on each marked point, the side of the stone on each occupied point, and for a point that shows something other than its stone what it shows. The mode is plain, which while a stone is being chosen, where while one is being stepped, or ask while a step waits for a or w. In the last two the stones are those of the position the move would leave.

board_lines

my $lines = $terminal->board_lines($mode);

The board as lines of text, with the counts beside it.

screen

my $lines = $terminal->screen($mode);

A whole screen as lines of text. As well as the modes above there are ended, thinking, menu, help and rules.

show

Draws "screen" on out, over the last one when interactive is true.

render

Writes the board and whose turn it is, as typed play does before each prompt.

budget

The number of positions the program looks at for a move at the present level.

raw

Whether the keyboard is being read a key at a time.

notice

The lines written above the board, as an array reference: the last move, and what a command said. The newest eight are kept.

focus

The point the cursor is on.

chosen

The point the stone being stepped started from, or undef.

prefix

The steps taken so far by the stone being stepped, as "steps" in Game::Fanorona describes a step.

last

The last move played here, or after u or r the last move of the game then on the board, as a hash of side, move, the points the stone stood on and the points of the stones taken; undef before one has been.

history

The Game::Terminal::Kit::History the turns are kept in, as the game's text. A turn is kept each time the move passes to a person, and when a game ends with a person at the keys; with the program playing both sides nothing is kept. A new game, a loaded game, a board changed in the opening questions and "start" each begin it again.

TABLES

%GROUND, %INK, %GLYPH and %FRAME are package variables holding the colours, the stones and the brackets, so that a test can measure them. A colour is one of the 240 that every terminal with 256 agrees on, and never one of the first sixteen, which each terminal sets for itself.

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 (GPL Compatible)