NAME
Game::Senet::Notation - a Senet move, a position and a game record, as text
VERSION
Version 0.02
SYNOPSIS
use Game::Senet::Notation ':all';
my ($move, $why) = parse_move('12-15'); # { from => 12, to => 15 }
print format_move($move), "\n"; # 12-15
print format_display({ from => 22, to => 20, roll => 2, back => 1, swap => 1 }), "\n";
# 2: 22-20<x
print format_forfeit(4, 1), "\n"; # 4: -+
my ($record, $problem) = parse_record($text);
print format_record($record);
DESCRIPTION
Functions, no objects and no compiled code, for reading and writing a game of Senet as text: a move, a position string, and a whole game's record. Nothing here has a board. A move is read and written without being asked whether it is legal; that is the game's question.
A MOVE
The wire form names two places: a house, a whole number from 1 to 30 with no leading zero, and the word off. 12-15, 22-20, 26-off, 26-15. It carries no roll and no marks.
The display form leads with the roll, then the move, then its marks in a fixed order: < a backward move, x a swap, + the same side throws next. 2: 22-20<x is a backward swap on a 2. A forfeit is the roll and a dash: 3: -, or 4: -+ when it keeps the turn.
< cannot be worked out from the two houses. From 25 or below a lower house is a backward move; from 26 or 27 it is the walk down from 15, which is forward. The mark says which.
A RECORD
[variant kendall pieces=5 blockade=3 protect=run backward=1 reach26=exact throw_on_26=0]
[first light]
1. l 1: 10-11
2. l 2: 11-13
3. d 3: 9-12
4. l 5 0000: 6-11
5. l 3: 2-5
6. d 2: 7-9
A header, then one line a ply. The variant line is the rule set's name and every one of its fields in this order: pieces, blockade, protect, backward, reach26, throw_on_26. first says which side threw first. position, optional, is the position string the game began from, its side the side of first, when it did not begin at the start. seed, in hexadecimal, is optional; with one, every roll is checked: line k is throw k - 1 of the seed, since there is no opening throw.
A ply line is its number, the side, the roll, optionally the four sticks as they fell (1 a light face), and the wire move or -. The side is on every line because turns do not alternate: the next line is the same side after a roll of 1, 4 or 5, and after a move from below house 26 onto it when the variant's throw_on_26 is 1. A record may end [result light home], [result dark resign] or [result draw ply_cap], and ends with a newline.
FUNCTIONS
None is exported unless asked for. :all exports them all, and the POS_ constants, which are Game::Senet::Engine's.
house_ok
house_ok('15'); # 1
True for a house number as the wire form writes one: 1 to 30, no leading zero.
parse_move
my ($move, $why) = parse_move($text);
The move a wire form names, as { from, to } with to a number or off, and undef; or undef and why not: empty, long, shape, house, from_off or same. off is read in any case; nothing else is forgiven.
format_move
my $text = format_move($move);
The wire form of a move: a Game::Senet::Move or a hash with from and to.
format_display
my $text = format_display($move, $again);
The display form. $again is whether the same side throws next, which only the game can say, and puts the + on.
format_forfeit
my $text = format_forfeit($roll, $again);
A throw that allowed nothing, in the display form.
validate_position
my $code = validate_position($text);
POS_OK, or the code Game::Senet::Engine would refuse the string with, worked out without building a board.
parse_record
my ($record, $problem) = parse_record($text);
A record as a hash: variant (the name and the fields), first, seed when given, plies (each with side, roll, sticks when given, and move, undef for a forfeit) and result when given. Or undef and { line, error }. It checks the record's own consistency: the numbering, the sides, the sticks against the roll, and the rolls against the seed. It does not play the game, so it cannot say whether a move was legal.
format_record
my $text = format_record($record);
A record as text, the inverse of parse_record, byte for byte.
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)