NAME
Games::Go::SGF2misc - Reads SGF files and produces usable output in many formats
SYNOPSIS
use Games::Go::SGF2misc;
my $sgf = new Games::Go::SGF2misc;
for my $file (<*.sgf>) {
$sgf->parse($file);
# do things with the parsed sgf:
# the output options are listed below
}
as_perl
my @gametree = $sgf->as_perl; # smart enough to return an arrayref or array as appropriate
my $gametree = $sgf->as_perl; # the arrayref is probably a better choice, since it's not a copy.
# This will probably be the most useful as_ function (if you're doing
# your own custom thing). It returns all the nodes, beautifully
# parsed, with the board positions as a big matrix, kibitzen as an
# array of strings, the list of moves, the list of captures, and the
# rules, etc.
#
# Could you ask for anything more?
#
# Less memory usage perhaps? Because of the huge amount of
# semi-duplicate data in the tree, these take up (very roughly) around
# a meg of ram per 300 move game.
The Layout (Pretty Much)
# The game tree is actually an array(ref) of games.
$gametree = [ $game1, $game2, $game3, $game4 ];
# The games are hashes (refs) of game data with the Collections of
# Nodes stuffed into a kids=>[] array(ref).
$game = { variations=>6,
game_properties={
'AP' => 'CGoban:2', 'FF' => 3, 'PB' => 'Myself', 'GM' => 1, 'KM' => '0', 'SZ' => 5,
'RU' => 'Japanese', 'CA' => 'UTF-8', 'PW' => 'Me'
},
kids => [ $node1, $node2, $node3 ],
};
# And, lastly, the nodes are hashes with their own kids array.
$node = {
parent=>$game, # this is actually a pointer (ref) to the hashref
# who's kids=>[] array points to this node.
'variation' => 1,
'other' => { 'ST' => '2' }, # cgoban 1 and 2 kick this out. *shrug*
# the other properties are just values
# SGF2misc doesn't handle
'move_no' => 1, # The root node is move #0.
# It is technically possible to have more than one
# move in a given node. If so, the move counter is
# bumped up to count the last move of the node.
'kids' => [ $node1, $node2, $etc ],
# This should be pretty clear. SGF2misc leaves the sgf
# co-ordinates intact, but also presents some numerical ones for
# your enjoyment. CR is a circle, btw. The numerical co-ordinates
# are for the board matrix and start in the upper left corner
# (unlike the letter-number co-ordinates we use IRL).
'marks' => [ [ 'CR', 1, 3, 'bd' ] ],
'moves' => [ [ 'B', 1, 3, 'bd' ] ],
# This is from the root node of a handicap game... They're the handicap stones.
'edits' => [ [ 'B', 15, 3, 'pd' ], [ 'B', 3, 15, 'dp' ] ],
# The board is a matrix of descriptive characters. This is a 3x3
# board, and clearly, the edits from above do not fit on it.
'board' => [ [' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' '] ],
# This speaks for itself I hope.
'captures' => { B=>3, W=>4 },
# I generally like to say something friendly at the start of all my games, you?
'comments' => [ 'jettero [15k]: hi ' ],
}
Lemme See It
# Rather than explain the layout in detail, it's better to simply see
# it. WARNING: This can be gigantically huge! In memory, a complete
# game is probably around a meg. When you print them though, the
# indenting get's out of control!
use Data::Dumper;
$Data::Dumper::Maxdepth = 10; # set this to 0 to see the whole show...
$Data::Dumper::Indent = 1;
$Data::Dumper::Purity = 1 if $Data::Dumper::Maxdepth == 0;
# Purity makes some of the crazy-refs show up at the end instead
# crazy refs? EG: 'parent' =>
# $VAR1->[0]{'kids'}[0]{'kids'}[0]{'kids'}[0]{'kids'}[0]{'kids'}[0]{'kids'}[0]{'kids'}[0],
open OUT, ">darray.pl" or die $!;
print OUT Dumper( $gametree );
clsoe OUT;
# One last thing. You can check the memory usage by using the DEBUG
# environment variable (see below). Anything over a 1 will show how
# big the structures get at both parse phasen.
node_list
my $node_list = $sgf->node_list;
# Parsing the game tree from as_perl() could be pretty tedius.
# Fortunately, you don't have to. This returns a special list
# of node-id's (human readable $variation-$move_no node descriptors).
# example:
$node_list = { 'game #1' => [
[ '1-root', '1-1', '1-2', '1-3', '1-4', '1-5', ],
[ undef, undef, undef, undef, undef, '2-5', '2-6', '2-7', ],
[ undef, undef, undef, undef, undef, undef, undef, '3-7', '3-8' ],
] };
# As confusing as you found the as_perl() above, you'll probably like this.
# as_perl() understands these node identifiers!
my $game_info = $sgf->as_perl('game #1');
my $root_node = $sgf->as_perl('1-root');
my $move5_v2 = $sgf->as_perl('2-5');
my $s = $game_info->{game_properties}{SZ};
print "The board size is: ${s}x${s}!\n";
print my $c (@{ $move5_v2->{comments} }) {
print "Comment from 2-5: $c\n";
}
# Tada!!
as_text
# This is pretty much just an example
use strict;
use Games::Go::SGF2misc;
my $sgf = new Games::Go::SGF2misc;
$sgf->parse("sgf/jettero-sixrusses-2004-03-18.sgf");
my $nl = $sgf->node_list;
my $end = $nl->{'game #1'}[0][ $#{$nl->{'game #1'}[0]} ];
# 1st game 1st variation last node
my $caps = $sgf->as_perl( $end )->{captures};
print $sgf->as_text($end), "Captures: Black-$caps->{B} / White-$caps->{W}\n";
# Result:
# X O . . . O . . . . . . . . . O O O .
# . O O . O O X . X X O O X O O O X X X
# X O . . . O X . X O . O O . O X . . .
# O O . O O X O O O O O . . O X . X . .
# O O O O O X X X X O . O O X . . . . .
# O X X X O X . X . X O O X . X . . . .
# X X X O O . X . X . X X . . . . . . .
# X . . X O . . X . . . . . . . . X . .
# X . X X O O O X . . . . . . . . . . .
# X . X . X X O X O O O X . . . . . . .
# . X . . . X O O X X X X X . . . X . .
# . . . . X O O . O O O X . . . X X X X
# X X X . X X O O . O X X X . . X O O X
# X O O X . . X . O O O X X . X O O . O
# O O . O X X X X X O X X O X X X O . .
# . . O O O X . . X O O X O X O X O X .
# . . . . O O X X O O . O O O O O O X .
# . . . . . O X O . O . . . . O X X O O
# . . . . . O X O O . . . . . . . . . .
# Captures: Black-11 / White-16
as_html
# This function works very much like the as_text function above, but
# instead prints out an html table full of images.
open OUT, ">example.html" or die $!;
print OUT, $sgf->as_html( $end, "/image/dir/" );
# The only real difference is the image-dir argument (which defaults to
# "./img"). There is a directory of images included with SGF2misc.
# They are from this page:
# http://www.britgo.org/gopcres/gopcres1.html#ag-gifs
# They are Andrew Grant's GIF images. I did NOT seek permission to
# re-distribute them. Perhaps I have no right to do so. I really
# don't know how to get ahold of him.
# If anyone knows how who to ask, please tell me. If anyone knows it's
# a problem, please tell me.
# 3/22/04, Orien Vandenbergh made bc.gif, wc.gif, bq.gif and wq.gif for me.
# NOTE: On marks, this as_html only shows circles, triangles, squares,
# and numbers where there are stones. It does not show letters at all.
# This is only because I don't have images for _everything_. :)
as_image
# This is still in the works... sooon!
parse_hash
my $hash = $sgf->parse_hash;
# You'll find this highly useless. It returns the parse tree as a perl
# hash. Check out as_perl() instead.
Board Postion Character Map
$board = [
[ ' ', ' ', ' ' ],
[ ' ', ' ', ' ' ],
[ ' ', ' ', ' ' ],
];
# ' ' - an empty board position
# 'W' - a white stone
# 'B' - a black stone
# Marks are not placed on the board!
# You'll just have to fetch the marks array from the $node.
BUGS
Besides the lack of documentation? Well, I'm sure there's a bunch.
If you spot any bugs, please tell me.
ENV VARIABLES
DEBUG
Try setting $ENV{DEBUG}=1, $ENV{DEBUG}=2, or $ENV{DEBUG}=3 to see the internals.
Also, from your bash prompt you can 'DEBUG=1 perl ./myprog.pl' to
enable debugging dynamically.
DEBUG of 31 or over will show the lexical trace. That's kinda fun.
AUTHOR
Please contact me with ANY suggestions, no matter how pedantic.
Jettero Heller <japh@voltar-confed.org>
COPYRIGHT
GPL! I included a gpl.txt for your reading enjoyment.
Though, additionally, I will say that I'll be tickled if you were to
include this package in any commercial endeavor. Also, any thoughts to
the effect that using this module will somehow make your commercial
package GPL should be washed away.
I hereby release you from any such silly conditions.
This package and any modifications you make to it must remain GPL. Any
programs you (or your company) write shall remain yours (and under
whatever copyright you choose) even if you use this package's intended
and/or exported interfaces in them.