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

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.

head1 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>