I first give the generic part of the format, common to all games. Then I give the game-specific formats (Hex, Twixt, ...).
In the future, I plan to extend the format in at least two ways:
Generic (non-game-specific) format
----------------------------------
[Game file] = [key-val list] [(root) node]
(Global game parameters (player names, board size, etc.), followed
by the game tree.)
[key-val list] = [key-val pair] [key-val pair] ... [zero-byte]
(A list of key-value pairs. List terminated by a zero byte.)
[key-val pair] = [1 unsigned byte giving length of key string]
[key string (NOT zero-terminated)]
[4 byte integer in "network" order giving length of value]
[the value]
(Examples: 'bdsize' => 10 would be encoded as the bytes
{\x06 'b' 'd' 's' 'i' 'z' 'e' \x00 \x00 \x00 \x01 \x0a}.
'player1' => 'vvvjv' would be {\x07 'p' 'l' 'a' 'y' 'e' 'r' '1'
\x00 \x00 \x00 \x05 'v' 'v' 'v' 'j' 'v'}.)
Note: The format of the value depends on the key. Currently in use are:
'gtv' - Game Tree (file format) Version; 4-byte integer (current
value = 2); required
'player1' - string; name of first player; optional
'player2' - string; name of second player; optional
'name' - string; name of game; optional
'pov' - point of view for displaying 'good' and 'bad' moves (0 = alternate (default),
1 = Player 1, 2 = Player 2); 1-byte integer; optional
In addition, there are game-specific keys (e.g. board size; see below).
[node] = [node-key-val list]
[number of child nodes (2 byte network unsigned short integer)]
[child node 1] [child node 2] ...
[node-key-val list] = [node-key-val pair] [node-key-val pair] ... [zero-byte]
(A list of key-value pairs. List terminated by a zero byte.)
[node-key-val pair] = [1 unsigned byte giving length of key string]
[key string (NOT zero-terminated)]
[2 or 4 byte integer giving length of value]
[the value]
(The third item (length of value field) is a 2-byte, network,
unsigned, short integer, unless the key is 'c' (comment),
in which case it is a 4 byte integer. (In other words, the
maximum length of a comment is 2-gigabytes (31 bits), not
64 kbytes (16 bits).))
For a node the keys are:
'm' - the move; length and format depend on the specific game (see below)
'r' - value of the position; signed 2-byte short integer in network order;
current convention is that 10000 means player 1 wins, -10000 means
that player 2 wins, 0 means an even position, 0 < x < 10000 means a
favorable position for player 1, 12345 means undetermined; this key
is optional
'g' - 1 byte boolean; true means that this is the move is the main
variation from its parent (typicially, the move played in an actual
game); optional
'c' - string, 4 byte length then the string itself without terminating 0 byte;
the comment associated to this node; optional
Hex Specifics
-------------
For a Hex Game Tree File, there are the following additional header fields:
'hgtv' - Hex Game Tree Version; 4-byte integer (current value = 1); required
'bdsize' - board size; 4 byte integer; required
'type' - string identifying type of file: 'hex1'
Hex moves are always 3 bytes long:
[Hex game move] = [x-coordinate (1 unsigned byte); 0...bdsize-1]
[y-coordinate (1 unsigned byte); 0...bdsize-1]
[color (1 unsigned byte); 1 for player 1, 2 for player 2]
Twixt Specifics
---------------
For a Twixt Game Tree File, there are the following additional header fields:
'tgtv' - Twixt Game Tree Version; 4-byte integer (current value = 1); required
'bdsize' - board size; 4 byte integer; required
'type' - string identifying type of file: 'twixt1'
There are 2 kinds of Twixt moves: "short" and "long". Short moves are always
3 bytes long, while long moves are always more than 3 bytes long. Thus one knows
what kind of move follows after reading the length field.
[Short twixt game move] = [x-coordinate of peg (1 unsigned byte); 0...bdsize-1]
[y-coordinate of peg (1 unsigned byte); 0...bdsize-1]
[color (1 unsigned byte); 1 for player 1, 2 for player 2]
(For short moves, all available links to the new peg
are made.)
[Long twixt game move] = [x-coordinate of peg (1 unsigned byte); 0...bdsize-1]
[y-coordinate of peg (1 unsigned byte); 0...bdsize-1]
[color (1 unsigned byte); 1 for player 1, 2 for player 2]
['pbem_null'; 1 byte boolean; see below]
[number of removed links; 2 byte unsigned short integer]
[list of removed links]
[number of added links; 2 byte unsigned short integer]
[list of added links]
(Total length of a long move is
3 + 2 + 3*num_removed_links + 2 + 3*num_added_links.
If pbem_null is false, then links on the remove list
are removed, links on the add list are added, and that's
it -- no implicit links are added.
If pbem_null is true, then links on the remove list are
removed, and afterwards all available links to the new peg
are made. The list of added links should be zero-length in
this case. Whether or not it is zero-length, it is ignored.)
[list of links] = [link] [link] ...
[link] = [x-coordinate of bottom peg (1 unsigned byte)]
[y-coordinate of bottom peg (1 unsigned byte)]
[link direction; 1 byte: 1, 2, 3 or 4]
(The bottom peg is the one closest to the bottom of the
board. (The upper left corner of the board is at x=0, y=0.)
This is not necessarily the peg placed on this move.
Directions: 1 means x+2, y-1, 2 means x+1, y-2,
3 means x-1, y-2, 4 means x-2, y-1. In other words,
direction 1 points to 2 O'clock from the bottom peg,
2 points to 1 O'clock, 3 points to 11 O'clock, and 4
points to 10 O'clock.)