Games::SGF - A general SGF parser
Version 0.991
use Games::SGF; my $sgf = new Games::SGF(); $sgf->setStoneRead( sub { "something useful"} ); $sgf->setMoveRead( sub { "something useful"} ); $sgf->setPointRead( sub { "something useful"} ); $sgf->addTag('KM', $sgf->T_GAME_INFO, $sgf->V_REAL ); $sgf->readFile("015-01.sgf"); $sgf->setProperty( "AP", $sgf->compose("MyApp", "Version 1.0") );
Games::SGF is a general Smart Game Format Parser. It parses the file, and checks the properties against the file format 4 standard. No game specific features are implemented, but can be added on in inheriting classes.
It is designed so that the user can tell the parser how to handle new tags. It also allows the user to set callbacks to parse Stone, Point, and Move types. These are game specific types.
SGF file contains 1 or more game trees. Each game tree consists of a sequence of nodes followed by a sequence of variations. Each variation also consists a sequence of nodes followed by a sequence of variations.
Each node contains a set of properties. Each property has a "Type", "Value Type", "Flags", and an "Attribute".
The interface is broken into 3 conceptal parts
This is the straight SGF Format which is saved and read using "IO" methods.
This is the format that the Games::SGF user will come in contact with. Various methods will convert the Uwer Format into the Internal Format which Games::SGF actually deals with.
These can take the form of Constants:
Or with converstion methods:
If this format differs from the others, you don't need to know.
Also see: http://www.red-bean.com/sgf
new Games::SGF(%options);
Creates a SGF object.
Options that new will look at.
These options operate in the same fashion. There are 3 value cases that it will check. If the value is a code reference it will ccall that subroutine when the event occurs with the event strings passed to it. If the value is true then it croak on Fatal, and carp on Warn or Debug. If the value is false it will be silent. You will still be able to get the error strings by calling "Fatal", "Warn", or "Debug".
$sgf_copy = $sgf->clone;
This will create a completely independent copy of the $sgf object.
$sgf
$sgf->readText($text);
This takes in a SGF formated string and parses it.
$sgf->readFile($file);
This will open the passed file, read it in then parse it.
$sgf->writeText;
Will return the current collection in SGF form;
$sgf->writeFile($filename);
Will write the current game collection to $filename.
$sgf->addTag($tagname, $type, $value_type, $flags, $attribute);
This add a new tag to the parsing engine. This needs to called before the read or write commands are called. This tag will not override the FF[4] standard properties, or already defined properties.
The $tagname is the name of the tag which will be read in, thus if you want to be able to read AAA[...] from an SGF file the tagname needs to be "AAA".
$tagname
The $type needs to be choosen from the "Type" list below. Defaults to T_NONE.
$type
T_NONE
The $value_type needs to be choosen from the "Type" list below. Defaults to V_TEXT.
$value_type
V_TEXT
The $flags are from the "Flags" List. Defaults to VF_EMPTY | VF_LIST.
$flags
VF_EMPTY | VF_LIST
The $attribute is from the "Attribute" List. Defaults to A_NONE.
$attribute
A_NONE
$sgf->redefineTag($tag, $type, $value, $value_flags, $attribute);
This will overwrite the flags set for $tagname. If one of the args is unset, it will be unaltered. For example:
$sgf->redefineTag($tag, , , $flags);
Will reset $tag's $flags leaving all other properties untouched.
$tag
The property fields are the same defined the same as "addTag".
$sgf->setPointRead(\&coderef); $sgf->setMoveRead(\&coderef); $sgf->setStoneRead(\&coderef);
These call backs are called when a properties value needs to be parsed. It takes in a string, and returns a structure of some type. Here is a possible example for a Go point callback:
sub parsepoint { my $value = shift; my( $x, $y) = split //, $value; return [ ord($x) - ord('a'), ord($y) - ord('a') ]; } # then somewhere else $sgf->setPointParse( \&parsepoint );
Note: that you should do more then this in practice, but it gets the across.
If the value is an empty string and VF_RMPTY is set then the call back will not be called but return an empty string.
$sgf->setPointCheck(\&coderef); $sgf->setMoveCheck(\&coderef); $sgf->setStoneCheck(\&coderef);
This callback is called when a parameter is stored. The callback takes the structure passed to setProperty, or component if composed, and returns true if it is a valid structure.
An Example of a stone check for go is as follows:
sub stoneCheck { my $stone = shift; if( ref $stone eq 'ARRAY' and @$stone == 2 and $stone->[0] > 0 and $stone->[1] > 0 ) { return 1; } else { return 0; } }
If the value is an empty string it will be passed to the check callback only if VF_EMPTY is not set.
$sgf->setPointWrite(\&coderef); $sgf->setMoveWrite(\&coderef); $sgf->setStoneWrite(\&coderef);
This callback is called when a parameter is written in text format. The callback takes the structure passed to setProperty, or component if composed, and returns the text string which will be stored.
sub stoneWrite { my $stone = shift; my @list = ('a'..'Z','A'..'Z'); return $list[$stone->[0] - 1] . $list[$stone->[1] - 1]; }
If the tag value is an empty string it will not be sent to the write callback, but immedeitely be returned as an empty string.
$sgf->nextGame;
Sets the node pointer to the next game in the Collection. If the current game is the last game then returns 0 otherwise 1.
$sgf->prevGame;
Sets the node pointer to the prevoius game in the Collection. If the current game is the first game then returns 0 otherwise 1.
$sgf->gotoRoot;
This will move the pointer to the root node of the game tree.
$sgf->next;
Moves the node pointer ahead one node.
Returns 0 if it is the last node in the branch, otherwise 1
$sgf->prev;
Moves the node pointer back one node.
Returns 0 if first node in the branch and 1 otherwise
$sgf->variations;
Returns the number of variations on this branch.
$sgf->gotoVariation($n);
Goes to the first node of the specified Variation. If it returns 4 that means that there is variations 0..3,
0..3
Returns 1 on success and 0 on Failure.
$sgf->gotoParent;
Will move the node pointer to the last node of the parent branch. This will fail if you already on the root branch for the current game.
Returns 1 on success or 0 on failure.
$self->addGame;
This will add a new game to the collection with the root node added. The current node pointer will be set to the root node of the new game.
Returns true on success.
$sgf->addNode;
Adds node end of the current branch. It will fail if there is any variations on this branch.
$sgf->addVariation;
Adds a new variation onto this branch. The current branch will be changed to this new variation. It will then add the first node for this variation.
Returns 1 on sucess 0 on Failure.
$sgf->removeNode;
Removes last node from the current Branch, will fail if there is any variations on this branch
$sgf->removeVariation($n);
This will remove the $n variation from the branch. If you have variations 0..4 and ask it to remove variation 1 then the indexs will be 0..3.
$n
0..4
1
$sgf->splitBranch($n);
This will split the current branch into 2 branches, so that the last part of the branch will be a variation of the first portion. $n will be the first node in the next variation.
Your node pointer will be the last node first branch. For Example say the branch you are on has nodes 0..9 and you want to split it on node 5 will give the first branch having nodes 0..4 having one variation containing nodes 5..9 and the variations of the original branch. Your node pointer will point to node 4
0..9
5
5..9
4
This is used for adding a variation of move $n:
$sgf->splitBranch($n); $sgf->addVariation; # set some node properties
The above code will add a variation on the a node in the middle of a node sequence in a branch.
$sgf->flatten;
If the current branch has only one variation then moves nodes and variations from that one variation into current branch, and removing the old branch.
my( @tags ) = $sgf->property; my $array_ref = $sgf->property( $value ); my $didSave = $sgf->property( $value , @values );
This is used to read and set properties on the current node. Will prevent T_MOVE and T_SETUP types from mixing. Will prevent writing T_ROOT tags to any location other then the root node. Will Lists from being stored in non list tags. Will prevent invalid structures from being stored.
If no options are given it will return all the tags set on this node. Inherited tags will only be returned if they were set on this node.
my $array_ref = $sgf->getProperty($tag, $isStrict); if( $array_ref ) { # sucess foreach my $value( @$array_ref ) { # do something } } else { # failure }
Will fetch the the $tag value stored in the current node.
$isStrict is for fetching inherited tags, if set it will only return an inherited tag if it is actually set on that node.
fail() unless $sgf->setProperty($tag,@values);
Sets the the $tag value of the current node to @values. This method does a series of sanity checks before attempting to write. It will fail if any of the following are true:
If @values is not passed then it will remove the property from the node. This is not the same as setting to a empty value.
$sgf->setProperty($tag); # will unset the $tag $sgf->setProperty($tag, "" ); # will set to an empty value
($pt1, $pt2) = $sgf->compose($compose); $compose = $sgf->compose($pt1,$pt2);
Used for creating and breaking apart composed values. If you will be setting or fetching a composed value you will be needing this function to breack it apart.
if( $sgf->isComposed($compose) ) { ($val1, $val2) = $sgf->compose($compose); }
This returns true if the value passed in is a composed value, otherwise false.
$self->isPoint($val);
Returns true if $val is a point, move or stone.
The determination for this is if it is blessing class matches m/^Games::SGF::.*type$/ where type is point, stone, or move. So as long as read,write,check methods work with it there is no need for these methods to be overwritten.
m/^Games::SGF::.*type$/
isEmpty will detect an empty tag.
$struct = $sgf->move(@cord); @cord = $sgf->move($struct);
If a point, stone, or move is passed in, it will be broken into it's parts and returned. If the parts are passed in it will construct the internal structure which the parser uses.
Will treat the outside format the same as the SGF value format. Thus will use the read and write callbacks for point,stone, and move.
If the SGF representation is not what you desire then override these.
Will return a empty value, which can be tested with isEmpty.
$self->Fatal( 'Failed to Parse Something'); @errors = $self->Fatal; $self->Warn( 'Some recoverable Error Occured'); @warnings = $self->Warn; $self->Debug('I am doing something here'); @debug = $self->Debug;
These methods are used for storing human readable error messages, and testing if an error has occured.
Fatal messages are set when there is a failure which can not be corrected, such as trying to move passed the last node in a branch, or parsing a bad SGF file.
Warn messages are set when a failure occurs and it can give a good guess as to how to proceed. For example, a node can not have more then one a given property set, but if the tag is for a list it will assume that you ment to add that element onto the end of the list and spit out a warning.
Debug messages are saved at various points in the program, these are mainly finding problems in module code (what is helpful for me to fix a bug).
If called with no arguments it will return a list of all event strings currently on the stack.
Otherwise it will push the arguments onto the event stack.
$self->Clear;
This will empty all events in the stack. This is only needed by extension modules, which need to clear the stack.
Each time the public methods are called (outside of Games::SGF) the event stacks will be cleared.
These are the defined property types. They tell the engine where the tag is allowed to be.
This is used for properties discribing a move. T_MOVE and T_SETUP tags may not be present in the same node.
These properties are used for setting up a position on the board. Such as placing stones on the board.
These properties must be in the root node. This is the root of the collection, not the root of a variation tree.
These are used for discribing the game. They should be on the earliest node, that the game is evident. For example if the SGF file is a fuseki, the Game_info should be when the game becomes unique in the collection.
There is no placement restrictions placed on tags of this type.
These can be in any node. There is no resrictions placed on these nodes.
These discribe the types of data contained in a tag.
These properties have no tag content.
This is a number which satifisies the regex: [+-]?[0-9]+
[+-]?[0-9]+
This is a number which satifisies the regex: [+-]?[0-9]+(\.[0-9]+)?
[+-]?[0-9]+(\.[0-9]+)?
This is used for emphasies. For example GB move the good for black property. GB[1] would mean "Good for Black" GB[2] would mean "Very Good for Black."
Used for normal emphasis. When 1 is passed into a V_DOUBLE.
Used for emphasis. When 2 is passed into a V_DOUBLE.
This is used to specify a color, such as which color starts.
Used when B is passed into a V_COLOR tag.
Used when W is passed into a V_COLOR tag.
Can take pretty much any text.
Same as V_TEXT except all spaces are reduced down to a single space.
This is used to specify a point on the board. Used for marking positions. This is a Game Specific property type and will be handled as V_TEXT unless a parsing callback is specified.
This is used to specify a stone or placement of a stone on the board on the board. Used for stone placement. This is a Game Specific property type and will be handled as V_TEXT unless a parsing callback is specified.
This is used to specify a move on the board. Used making moves on the board. This is a Game Specific property type and will be handled as V_TEXT unless a parsing callback is specified.
These are various flags that can be given to a property tag. Since these are bit flags, in order to set more then one flag use the bitwise | operator. For example to set both the VF_EMPTY and VF_LIST flag use VF_EMPTY | VF_LIST.
|
VF_EMPTY
VF_LIST
Used to specify that no flags are set.
This also's the property to the tag to be empty. For Example MA uses this flag:
MA[] or MA[ff][gg]
This allows you to list properties together. The second example above demstrates this behavior. Used in conjunction with VF_EMPTY allows you to have a empty list, otherwise it must have at least one property given.
This tag allows a property to be composed with itself. For example in the specification any List of Points can be used as a List of Point composed with point, in order to specify a rectangular region of points. As an Example:
MA[aa][ab][ba][bb] is equavalent to: MA[aa:bb]
Used to specify no Attribute is set.
Currently the only Attribute defined in the specs. This property value will be passed down to all subsequient nodes, untill a new value is set.
This is done by inheritance. You use the engine, but override the game specific features related to point, stone, and move.
A Simple template is shown below:
package MySGFGame; require Games::SGF; no warnings 'redefine'; our( @ISA ) = ('Games::SGF'); sub new { my $inv = shift; my $class = ref $inv || $inv; my $self = $class->SUPER::new(@_); # Add Tags $self->addTag('TB', $self->T_NONE, $self->V_POINT, $self->VF_EMPTY | $self->VF_LIST | $self->VF_OPT_COMPOSE); # more tags # Add Callbacks $self->addPointRead(\&pointRead); $self->addStoneRead(\&stoneRead); $self->addMoveRead(\&moveRead); $self->addPointCheck(\&pointCheck); $self->addStoneCheck(\&stoneCheck); $self->addMoveCheck(\&moveCheck); $self->addPointWrite(\&pointWrite); $self->addStoneWrite(\&stoneWrite); $self->addMoveWrite(\&moveWrite); return bless $self, $class; # Makes $self your class } # define the Callbacks # ... # # define move, point, stone # ...
This holds true for standard FF4 and I believe it would cause a conflict if it was not true.
The Documentation needs to be reviewed for accuracy
The internal methods _get*(branch,node) do not currently check any errors, and the methods using them don't check for errors. When this is fixed a few error handling portions of the _read method can be removed.
http://www.red-bean.com/sgf
Games::Goban
Games::Go::SGF
David Whitcomb, <whitcode at gmail.com>
<whitcode at gmail.com>
For pointing out that AW[aa]AW[ab] should be read in and corrected to AW[aa][ab].
Please report any bugs or feature requests to bug-games-sgf at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Games-SGF. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
bug-games-sgf at rt.cpan.org
You can find documentation for this module with the perldoc command.
perldoc Games::SGF
You can also look for information at:
RT: CPAN's request tracker
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Games-SGF
AnnoCPAN: Annotated CPAN documentation
http://annocpan.org/dist/Games-SGF
CPAN Ratings
http://cpanratings.perl.org/d/Games-SGF
Search CPAN
http://search.cpan.org/dist/Games-SGF
Copyright 2008 David Whitcomb, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Games::SGF, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Games::SGF
CPAN shell
perl -MCPAN -e shell install Games::SGF
For more information on module installation, please visit the detailed CPAN module installation guide.