NAME
Game::Sternhalma::Notation - names, moves, positions and games as text, with no compiled code
SYNOPSIS
use Game::Sternhalma::Notation ':all';
my $hole = hole_of('i5'); # 60, the centre
my $name = name_of(0); # 'a1', the top tip
my $move = parse_move('e5:g5:g7'); # { kind => 'chain', holes => [...] }
my $text = format_move($move);
my ($p, $code) = parse_position(SETUP_TWO);
print format_position($p), "\n";
DESCRIPTION
Everything a program needs to read and write sternhalma as text, in plain Perl. It loads no compiled code, so a saved game can be read, and a move told from a typo, on a machine where the engine was never built. It knows no rule: whether a move is legal is the engine's business.
Hole names
There is no standard notation for the star, so this is this distribution's own. The rows are a (the top tip) to q (the bottom tip), and a hole is its row and its place in the row counted from the left from 1. The two rows of thirteen are e and m; the centre is i5.
Moves
A step is two names joined by -: e5-f5. A chain of hops is every hole it lands on, from its start, joined by :: e5:g5:g7. Then pass, and resign and a seat: resign 2.
Positions
The seventeen rows from the top, / between them; in a row a digit 0 to 5 is that seat's piece and [n] a run of n empty holes. Then the seat to move, the seat count and the piece count. Then, only once the game has moved on from its set-up, a ; and the game: f= the seats home in order, r= the seats that resigned in order, p= the ply, k= passes in a row, c= the cap if it is not 1,000 a seat, o= how the game ended (1 home, 2 the cap, 3 nobody could move, 4 resigning).
FUNCTIONS
name_of
name_of($hole)
The name of a hole, 0 to 120, or undef.
hole_of
hole_of($name)
The hole a name names, or undef.
row_len
row_len($row)
How many holes row $row (0 to 16) has.
parse_move
my $m = parse_move($text);
A move as a hash: kind (step, chain, pass or resign), holes for a step or a chain, seat for a resignation. undef for text that is not a move. It checks the text, not the board.
format_move
The text of a move hash.
parse_position
my ($p, $code) = parse_position($string);
The position as a hash (cells, 121 of a seat or undef; to_move, seats, pieces; finished and resigned, lists of seats; ply, pass_run, cap, how) and 0; or undef and the refusal code, the same codes and the same order as "reason" in Game::Sternhalma::Engine.
format_position
The string of a position hash.
format_game
my $text = format_game({ seats => 3, pieces => 10, cap => 3000, first => 1, moves => [ ... ] });
A game as text: a header, then one move a line. first, the seat that moved first, is written only when it is not seat 0; start, a position the game began from instead of its set-up, only when there is one.
parse_game
my ($game, $why) = parse_game($text);
The hash format_game takes, or undef and what is wrong with the text.
SETUP_TWO
The position string of the two-seat set-up.
HOLES
121.
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)