NAME
Game::Brandubh::Notation - squares, moves, positions and whole games as strings
VERSION
Version 0.01
SYNOPSIS
use Game::Brandubh::Notation ':all';
my ($file, $rank) = square_parse('d4'); # (3, 3)
my $name = square_name(3, 3); # 'd4'
my $move = move_parse('Kd4-d1'); # 'd4d1'
my $text = move_display('d1d3', { captures => ['c3'] }); # 'd1-d3xc3'
print "a position\n" if position_ok(SETUP);
my $record = game_string({ variant => 'brandubh', moves => [qw(d1c1 d3c3)] });
my $game = game_parse($record);
DESCRIPTION
The strings a person and a log use. Functions only: nothing here holds a board, and nothing here knows a rule. A move that this module accepts is a move that is written correctly, which is a different thing from one that may be played.
It loads on its own, without the rest of the distribution.
A square
A file letter from a to g and a rank digit from 1 to 7: a1 is the bottom left corner as the diagram is drawn, d4 the throne, g7 the top right corner. Written in lower case and read in either.
A move
As it is stored, four characters: the square left and the square reached, d1d3. This is the form a log keeps and move_parse returns.
As it is shown, with what happened:
d1-d3 a move
d1-d3xc3 a move that captured the piece on c3
d1-d3xc3,e3 one that captured two
Ke4-e1 the king's move
Kg2-g1++ the king reaching a corner
c5-c4xd4# the move that captured the king
The K marks the king; the other pieces have no letter. Captured squares are listed in order.
The game has no settled notation, and nothing in the rules this distribution follows gives one. The two endings are this distribution's own: ++ for the king reaching a corner and # for his capture, so that the last line of a finished game does not look like any other line.
What a shown move says was captured is commentary. move_parse reads past it: the position decides what a move captures, and a string cannot.
A position
Seven rows from rank 7 down to rank 1 with a / between them, a digit for a run of empty squares, then one space and the side to move.
3a3/3a3/3d3/aadkdaa/3d3/3a3/3a3 a
a is an attacker, d a defender, k the king; the side is a or d. That string is the set-up, and is the constant SETUP.
A game
Three things, and everything else about a game can be worked out again by playing them: the rule set, the position it started from, and the moves.
variant brandubh
start 7/7/7/3k3/7/7/a6 d
moves d4d1 a1a2 d1g1
The start line is left out when the game began from the set-up. A fourth line records an ending the board cannot show, because it is something the players did:
result resign attackers
result agreed
A resignation and an agreed draw are not moves and are never written among them.
CONSTANTS
SETUP
The position every game starts from unless it is told otherwise.
FUNCTIONS
Nothing is exported unless asked for. :all exports everything.
square_name
my $name = square_name($file, $rank);
The name of a square from its file and rank, both counted from 0. undef when either is off the board.
square_parse
my ($file, $rank) = square_parse('d4');
The file and rank of a named square, both counted from 0. The empty list for anything that is not the name of a square, without a warning.
move_wire
my $move = move_wire('d1', 'd3'); # 'd1d3'
A stored move from two square names. undef unless both are squares.
move_split
my ($from, $to) = move_split('d1d3');
The two square names of a stored move. The empty list for anything else. It is strict: lower case, four characters, nothing more.
move_parse
my $move = move_parse('Kd4-d1'); # 'd4d1'
A stored move from a string a person might type or a log might show: either form above, in either case, with or without the K, the hyphen, the captures and the ending. undef for anything else.
It checks the writing and nothing more. Whether a piece stands on the first square, whether it may reach the second, and what it captures on the way are questions for a position.
move_display
my $text = move_display($move, \%about);
A stored move as it is shown. %about says what happened, and every key is optional:
king-
True when the piece that moved is the king.
captures-
An array reference of the names of the squares captured.
king_home-
True when the king's move ended where he wins.
king_taken-
True when the move captured the king.
undef when the move is not a stored move.
position_ok
if (position_ok($string)) { ... }
True when the string is written as a position: seven rows, each seven squares wide, the three piece letters and the digits 1 to 7, one space, a side. It agrees with "of_string" in Game::Brandubh::Engine on what is and is not a position, and like it judges the writing and never the sense: two kings pass.
position_cells
my ($rows, $side) = position_cells($string);
The position as seven array references of seven cells, rank 7 first and file a first, each cell '', 'a', 'd' or 'k'; and the side to move, 'a' or 'd'. The empty list when the string is not a position.
game_string
my $text = game_string(\%game);
A game as text. The keys of %game:
variant-
A word or a line naming the rule set.
brandubhwhen left out. start-
A position. Left out, or the set-up, when the game began from the set-up.
moves-
An array reference of stored moves, in order.
result-
Left out unless the game ended by something the players did:
{ how => 'resign', by => 'attackers' }, the same withdefenders, or{ how => 'agreed' }.
undef when any part of it is not written correctly.
game_parse
my $game = game_parse($text);
The reverse: a hash reference with variant, start (the set-up when the text had no start line), moves and result (undef when the text had none). undef when the text is not a game: a line it does not know, a line given twice, a move or a position that is not one, or no variant or moves line.
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)