NAME
Games::SGF - A general SGF parser
VERSION
Version 0.993
SYNOPSIS
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") );
DISCRIPTION
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 Structure
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".
Interface
The interface is broken into 3 conceptal parts
- SGF Format
-
This is the straight SGF Format which is saved and read using "IO" methods.
- User Format
-
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:
- Internal Format
-
If this format differs from the others, you don't need to know.
Also see: http://www.red-bean.com/sgf
METHODS
new
new Games::SGF(%options);
Creates a SGF object.
Options that new will look at.
- Fatal
- Warn
- Debug
-
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".
clone
$sgf_copy = $sgf->clone;
This will create a completely independent copy of the $sgf
object.
IO
readText
$sgf->readText($text);
This takes in a SGF formated string and parses it.
readFile
$sgf->readFile($file);
This will open the passed file, read it in then parse it.
writeText
$sgf->writeText;
Will return the current collection in SGF form;
writeFile
$sgf->writeFile($filename);
Will write the current game collection to $filename.
Property Manipulation
addTag
$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".
The $type
needs to be choosen from the "Type" list below. Defaults to T_NONE
.
The $value_type
needs to be choosen from the "Type" list below. Defaults to V_TEXT
.
The $flags
are from the "Flags" List. Defaults to VF_EMPTY | VF_LIST
.
The $attribute
is from the "Attribute" List. Defaults to A_NONE
.
redefineTag
$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.
The property fields are the same defined the same as "addTag".
setPointRead
setMoveRead
setStoneRead
$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.
setPointCheck
setMoveCheck
setStoneCheck
$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.
setPointWrite
setMoveWrite
setStoneWrite
$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.
An Example of a stone check for go is as follows:
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.
getTagFlags
$flags = getTagFlags($tag);
if( $flags & VF_LIST ) {
# do something about lists
}
This will return the flags set on this tag.
getTagType
$flags = getTagType($tag);
if( $flags & T_NONE ) {
# do something about T_NONE tags
}
This will return the flags set on this tag.
getTagAttribute
$flags = getTagAttribute($tag);
if( $flags & A_NONE ) {
# do something about about no attributes
}
This will return the flags set on this tag.
getTagValueType
$valuetype = getTagValueType($tag);
if( $flags & V_TEXT ) {
# do something about text
}
This will return the flags set on this tag.
Navigation
nextGame
$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.
prevGame;
$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.
game
$sgf->game; # returns the game number
$sgf->game($number); # sets the game to $number
gotoRoot
$sgf->gotoRoot;
This will move the pointer to the root node of the game tree.
next
$sgf->next;
Moves the node pointer ahead one node. If there are variations it will move down the main tree path.
Returns 0 if it is the last node, otherwise 1
prev
$sgf->prev;
Moves the node pointer back one node. Will move back out of variations.
Returns 0 if root node of tree
branches
$sgf->branches;
Returns the number of variations for the next move. If there is only the main game path then it will return 1, if there are no more moves left in the branch it will return 0.
gotoBranch
$sgf->gotoBranch($n);
Goes to the first node of the specified Variation. If it returns 4 that means that there is variations 0..3
,
Returns 1 on success and 0 on Failure.
getAddress
my $address = $sgf->getAddress;
# some movement
$sgf->goto($address);
This function returns an address of your location in the sgf object. It can then be latter recalled by using the goto method.
goto
goto will recall a position inside of an sgf object. Use getAddress returns an address.
SGF Manipulation
addGame
$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.
addNode
$sgf->addNode;
Adds a node into the game tree. if there is already a continuation of the branch, then it will add a variation at this point. The node pointer will be set to the new node.
Returns 1 on success and 0 on Failure.
removeNode
$sgf->removeNode;
Removes current node from tree if it has no sub nodes. If removed calls $sgf-
prev> node.
Returns 1 on success and 0 on Failure.
property
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.
getProperty
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.
setProperty
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:
- @values > 0 and is not a list
- $tag is of type T_ROOT but the current node is not the root node
- $tag is a T_MOVE or T_SETUP and the other type is already present in the node
- @values are invalid type values
- unseting a value that is not set.
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
Value Type Functions
compose
($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.
isComposed
if( $sgf->isComposed($compose) ) {
($val1, $val2) = $sgf->compose($compose);
}
This returns true if the value passed in is a composed value, otherwise false.
isPoint
isStone
isMove
isEmpty
$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.
isEmpty will detect an empty tag.
point
stone
move
$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.
empty
Will return a empty value, which can be tested with isEmpty.
Error and Diagnostic Methods
Fatal
Warn
Debug
$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.
Clear
$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.
CONSTANTS
Type
These are the defined property types. They tell the engine where the tag is allowed to be.
- T_MOVE
-
This is used for properties discribing a move. T_MOVE and T_SETUP tags may not be present in the same node.
- T_SETUP
-
These properties are used for setting up a position on the board. Such as placing stones on the board.
- T_ROOT
-
These properties must be in the root node. This is the root of the collection, not the root of a variation tree.
- T_GAME_INFO
-
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.
- T_NONE
-
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.
Value Type
These discribe the types of data contained in a tag.
- V_NONE
-
These properties have no tag content.
- V_NUMBER
-
This is a number which satifisies the regex:
[+-]?[0-9]+
- V_REAL
-
This is a number which satifisies the regex:
[+-]?[0-9]+(\.[0-9]+)?
- V_DOUBLE
-
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."
- DBL_NORM
-
Used for normal emphasis. When 1 is passed into a V_DOUBLE.
- DBL_EMPH
-
Used for emphasis. When 2 is passed into a V_DOUBLE.
- V_COLOR
-
This is used to specify a color, such as which color starts.
- C_BLACK
-
Used when B is passed into a V_COLOR tag.
- C_WHITE
-
Used when W is passed into a V_COLOR tag.
- V_TEXT
-
Can take pretty much any text.
- V_SIMPLE_TEXT
-
Same as V_TEXT except all spaces are reduced down to a single space.
- V_POINT
-
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.
- V_STONE
-
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.
- V_MOVE
-
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.
Flags
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_NONE
-
Used to specify that no flags are set.
- VF_EMPTY
-
This also's the property to the tag to be empty. For Example MA uses this flag:
MA[] or MA[ff][gg]
- VF_LIST
-
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.
- VF_OPT_COMPOSE
-
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]
Attribute
- A_NONE
-
Used to specify no Attribute is set.
- A_INHERIT
-
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.
EXTENDING Games::SGF
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
# ...
ASSUMPTIONS
- All Inherited properties are T_NONE
-
This holds true for standard FF4 and I believe it would cause a conflict if it was not true.
KNOWN PROBLEMS
Documentation
The Documentation needs to be reviewed for accuracy
Some Errors not handled
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.
ALSO SEE
AUTHOR
David Whitcomb, <whitcode at gmail.com>
ACKNOWLEDGEMENTS
Robin Redeker
For pointing out that AW[aa]AW[ab] should be read in and corrected to AW[aa][ab].
BUGS
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.
SUPPORT
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
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
ACKNOWLEDGEMENTS
COPYRIGHT & LICENSE
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.