Included gomill framework for SGF and GTP support, and sketched out SGF game-loading code.
This commit is contained in:
parent
700a6a2f32
commit
692dc294d6
119 changed files with 27458 additions and 3 deletions
914
gomill/docs/sgf.rst
Normal file
914
gomill/docs/sgf.rst
Normal file
|
@ -0,0 +1,914 @@
|
|||
SGF support
|
||||
-----------
|
||||
|
||||
.. module:: gomill.sgf
|
||||
:synopsis: High level SGF interface.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
|
||||
Gomill's |sgf| support is intended for use with version FF[4], which is
|
||||
specified at http://www.red-bean.com/sgf/index.html. It has support for the
|
||||
game-specific properties for Go, but not those of other games. Point, Move and
|
||||
Stone values are interpreted as Go points.
|
||||
|
||||
The :mod:`gomill.sgf` module provides the main support. This module is
|
||||
independent of the rest of Gomill.
|
||||
|
||||
The :mod:`gomill.sgf_moves` module contains some higher-level functions for
|
||||
processing moves and positions, and provides a link to the
|
||||
:mod:`.boards` module.
|
||||
|
||||
The :mod:`!gomill.sgf_grammar` and :mod:`!gomill.sgf_properties` modules are
|
||||
used to implement the :mod:`!sgf` module, and are not currently documented.
|
||||
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
Examples
|
||||
^^^^^^^^
|
||||
|
||||
Reading and writing::
|
||||
|
||||
>>> from gomill import sgf
|
||||
>>> g = sgf.Sgf_game.from_string("(;FF[4]GM[1]SZ[9];B[ee];W[ge])")
|
||||
>>> g.get_size()
|
||||
9
|
||||
>>> root_node = g.get_root()
|
||||
>>> root_node.get("SZ")
|
||||
9
|
||||
>>> root_node.get_raw("SZ")
|
||||
'9'
|
||||
>>> root_node.set("RE", "B+R")
|
||||
>>> new_node = g.extend_main_sequence()
|
||||
>>> new_node.set_move("b", (2, 3))
|
||||
>>> [node.get_move() for node in g.get_main_sequence()]
|
||||
[(None, None), ('b', (4, 4)), ('w', (4, 6)), ('b', (2, 3))]
|
||||
>>> g.serialise()
|
||||
'(;FF[4]GM[1]RE[B+R]SZ[9];B[ee];W[ge];B[dg])\n'
|
||||
|
||||
|
||||
Recording a game::
|
||||
|
||||
g = sgf.Sgf_game(size=13)
|
||||
for move_info in ...:
|
||||
node = g.extend_main_sequence()
|
||||
node.set_move(move_info.colour, move_info.move)
|
||||
if move_info.comment is not None:
|
||||
node.set("C", move_info.comment)
|
||||
with open(pathname, "w") as f:
|
||||
f.write(g.serialise())
|
||||
|
||||
See also the :script:`show_sgf.py` and :script:`split_sgf_collection.py`
|
||||
example scripts.
|
||||
|
||||
|
||||
Sgf_game objects
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
|sgf| data is represented using :class:`!Sgf_game` objects. Each object
|
||||
represents the data for a single |sgf| file (corresponding to a ``GameTree``
|
||||
in the |sgf| spec). This is typically used to represent a single game,
|
||||
possibly with variations (but it could be something else, such as a problem
|
||||
set).
|
||||
|
||||
An :class:`!Sgf_game` can either be created from scratch or loaded from a
|
||||
string.
|
||||
|
||||
To create one from scratch, instantiate an :class:`!Sgf_game` object directly:
|
||||
|
||||
.. class:: Sgf_game(size, encoding="UTF-8"])
|
||||
|
||||
*size* is an integer from 1 to 26, indicating the board size.
|
||||
|
||||
The optional *encoding* parameter specifies the :ref:`raw property encoding
|
||||
<raw_property_encoding>` to use for the game.
|
||||
|
||||
When a game is created this way, the following root properties are initially
|
||||
set: :samp:`FF[4]`, :samp:`GM[1]`, :samp:`SZ[{size}]`, and
|
||||
:samp:`CA[{encoding}]`.
|
||||
|
||||
To create a game from existing |sgf| data, use the
|
||||
:func:`!Sgf_game.from_string` classmethod:
|
||||
|
||||
.. classmethod:: Sgf_game.from_string(s[, override_encoding=None])
|
||||
|
||||
:rtype: :class:`!Sgf_game`
|
||||
|
||||
Creates an :class:`!Sgf_game` from the |sgf| data in *s*, which must be an
|
||||
8-bit string.
|
||||
|
||||
The board size and :ref:`raw property encoding <raw_property_encoding>` are
|
||||
taken from the ``SZ`` and ``CA`` properties in the root node (defaulting to
|
||||
``19`` and ``"ISO-8859-1"``, respectively). Board sizes greater than ``26``
|
||||
are rejected.
|
||||
|
||||
If *override_encoding* is present, the source data is assumed to be in the
|
||||
encoding it specifies (no matter what the ``CA`` property says), and the
|
||||
``CA`` property and raw property encoding are changed to match.
|
||||
|
||||
Raises :exc:`ValueError` if it can't parse the string, or if the ``SZ`` or
|
||||
``CA`` properties are unacceptable. No error is reported for other
|
||||
malformed property values. See also :ref:`parsing_details` below.
|
||||
|
||||
Example::
|
||||
|
||||
g = sgf.Sgf_game.from_string(
|
||||
"(;FF[4]GM[1]SZ[9]CA[UTF-8];B[ee];W[ge])",
|
||||
override_encoding="iso8859-1")
|
||||
|
||||
|
||||
To retrieve the |sgf| data as a string, use the :meth:`!serialise` method:
|
||||
|
||||
.. method:: Sgf_game.serialise([wrap])
|
||||
|
||||
:rtype: string
|
||||
|
||||
Produces the |sgf| representation of the data in the :class:`!Sgf_game`.
|
||||
|
||||
Returns an 8-bit string, in the encoding specified by the ``CA`` root
|
||||
property (defaulting to ``"ISO-8859-1"``).
|
||||
|
||||
See :ref:`transcoding <transcoding>` below for details of the behaviour if
|
||||
the ``CA`` property is changed from its initial value.
|
||||
|
||||
This makes some effort to keep the output line length to no more than 79
|
||||
bytes. Pass ``None`` in the *wrap* parameter to disable this behaviour, or
|
||||
pass an integer to specify a different limit.
|
||||
|
||||
|
||||
The complete game tree is represented using :class:`Tree_node` objects, which
|
||||
are used to access the |sgf| properties. An :class:`!Sgf_game` always has at
|
||||
least one node, the :dfn:`root node`.
|
||||
|
||||
.. method:: Sgf_game.get_root()
|
||||
|
||||
:rtype: :class:`Tree_node`
|
||||
|
||||
Returns the root node of the game tree.
|
||||
|
||||
The root node contains global properties for the game tree, and typically also
|
||||
contains *game-info* properties. It sometimes also contains *setup* properties
|
||||
(for example, if the game does not begin with an empty board).
|
||||
|
||||
Changing the ``FF`` and ``GM`` properties is permitted, but Gomill will carry
|
||||
on using the FF[4] and GM[1] (Go) rules. Changing ``SZ`` is not permitted (but
|
||||
if the size is 19 you may remove the property). Changing ``CA`` is permitted
|
||||
(this controls the encoding used by :meth:`~Sgf_game.serialise`).
|
||||
|
||||
|
||||
.. rubric:: Convenience methods for tree access
|
||||
|
||||
The complete game tree can be accessed through the root node, but the
|
||||
following convenience methods are also provided. They return the same
|
||||
:class:`Tree_node` objects that would be reached via the root node.
|
||||
|
||||
Some of the convenience methods are for accessing the :dfn:`leftmost`
|
||||
variation of the game tree. This is the variation which appears first in the
|
||||
|sgf| ``GameTree``, often shown in graphical editors as the topmost horizontal
|
||||
line of nodes. In a game tree without variations, the leftmost variation is
|
||||
just the whole game.
|
||||
|
||||
|
||||
.. method:: Sgf_game.get_last_node()
|
||||
|
||||
:rtype: :class:`Tree_node`
|
||||
|
||||
Returns the last (leaf) node in the leftmost variation.
|
||||
|
||||
.. method:: Sgf_game.get_main_sequence()
|
||||
|
||||
:rtype: list of :class:`Tree_node` objects
|
||||
|
||||
Returns the complete leftmost variation. The first element is the root
|
||||
node, and the last is a leaf.
|
||||
|
||||
.. method:: Sgf_game.get_main_sequence_below(node)
|
||||
|
||||
:rtype: list of :class:`Tree_node` objects
|
||||
|
||||
Returns the leftmost variation beneath the :class:`Tree_node` *node*. The
|
||||
first element is the first child of *node*, and the last is a leaf.
|
||||
|
||||
Note that this isn't necessarily part of the leftmost variation of the
|
||||
game as a whole.
|
||||
|
||||
.. method:: Sgf_game.get_main_sequence_above(node)
|
||||
|
||||
:rtype: list of :class:`Tree_node` objects
|
||||
|
||||
Returns the partial variation leading to the :class:`Tree_node` *node*. The
|
||||
first element is the root node, and the last is the parent of *node*.
|
||||
|
||||
.. method:: Sgf_game.extend_main_sequence()
|
||||
|
||||
:rtype: :class:`Tree_node`
|
||||
|
||||
Creates a new :class:`Tree_node`, adds it to the leftmost variation, and
|
||||
returns it.
|
||||
|
||||
This is equivalent to
|
||||
:meth:`get_last_node`\ .\ :meth:`~Tree_node.new_child`
|
||||
|
||||
|
||||
.. rubric:: Convenience methods for root properties
|
||||
|
||||
The following methods provide convenient access to some of the root node's
|
||||
|sgf| properties. The main difference between using these methods and using
|
||||
:meth:`~Tree_node.get` on the root node is that these methods return the
|
||||
appropriate default value if the property is not present.
|
||||
|
||||
.. method:: Sgf_game.get_size()
|
||||
|
||||
:rtype: integer
|
||||
|
||||
Returns the board size (``19`` if the ``SZ`` root property isn't present).
|
||||
|
||||
.. method:: Sgf_game.get_charset()
|
||||
|
||||
:rtype: string
|
||||
|
||||
Returns the effective value of the ``CA`` root property (``ISO-8859-1`` if
|
||||
the ``CA`` root property isn't present).
|
||||
|
||||
The returned value is a codec name in normalised form, which may not be
|
||||
identical to the string returned by ``get_root().get("CA")``. Raises
|
||||
:exc:`ValueError` if the property value doesn't identify a Python codec.
|
||||
|
||||
This gives the encoding that would be used by :meth:`serialise`. It is not
|
||||
necessarily the same as the :ref:`raw property encoding
|
||||
<raw_property_encoding>` (use :meth:`~Tree_node.get_encoding` on the root
|
||||
node to retrieve that).
|
||||
|
||||
|
||||
.. method:: Sgf_game.get_komi()
|
||||
|
||||
:rtype: float
|
||||
|
||||
Returns the :term:`komi` (``0.0`` if the ``KM`` root property isn't
|
||||
present).
|
||||
|
||||
Raises :exc:`ValueError` if the ``KM`` root property is present but
|
||||
malformed.
|
||||
|
||||
.. method:: Sgf_game.get_handicap()
|
||||
|
||||
:rtype: integer or ``None``
|
||||
|
||||
Returns the number of handicap stones.
|
||||
|
||||
Returns ``None`` if the ``HA`` root property isn't present, or if it has
|
||||
value zero (which isn't strictly permitted).
|
||||
|
||||
Raises :exc:`ValueError` if the ``HA`` property is otherwise malformed.
|
||||
|
||||
.. method:: Sgf_game.get_player_name(colour)
|
||||
|
||||
:rtype: string or ``None``
|
||||
|
||||
Returns the name of the specified player, or ``None`` if the required
|
||||
``PB`` or ``PW`` root property isn't present.
|
||||
|
||||
.. method:: Sgf_game.get_winner()
|
||||
|
||||
:rtype: *colour*
|
||||
|
||||
Returns the colour of the winning player.
|
||||
|
||||
Returns ``None`` if the ``RE`` root property isn't present, or if neither
|
||||
player won.
|
||||
|
||||
.. method:: Sgf_game.set_date([date])
|
||||
|
||||
Sets the ``DT`` root property, to a single date.
|
||||
|
||||
If *date* is specified, it should be a :class:`datetime.date`. Otherwise
|
||||
the current date is used.
|
||||
|
||||
(|sgf| allows ``DT`` to be rather more complicated than a single date, so
|
||||
there's no corresponding get_date() method.)
|
||||
|
||||
|
||||
Tree_node objects
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. class:: Tree_node
|
||||
|
||||
A Tree_node object represents a single node from an |sgf| file.
|
||||
|
||||
Don't instantiate Tree_node objects directly; retrieve them from
|
||||
:class:`Sgf_game` objects.
|
||||
|
||||
Tree_node objects have the following attributes (which should be treated as
|
||||
read-only):
|
||||
|
||||
.. attribute:: owner
|
||||
|
||||
The :class:`Sgf_game` that the node belongs to.
|
||||
|
||||
.. attribute:: parent
|
||||
|
||||
The node's parent :class:`!Tree_node` (``None`` for the root node).
|
||||
|
||||
|
||||
.. rubric:: Tree navigation
|
||||
|
||||
A :class:`!Tree_node` acts as a list-like container of its children: it can be
|
||||
indexed, sliced, and iterated over like a list, and it supports the `index`__
|
||||
method. A :class:`!Tree_node` with no children is treated as having truth
|
||||
value false. For example, to find all leaf nodes::
|
||||
|
||||
def print_leaf_comments(node):
|
||||
if node:
|
||||
for child in node:
|
||||
print_leaf_comments(child)
|
||||
else:
|
||||
if node.has_property("C"):
|
||||
print node.get("C")
|
||||
else:
|
||||
print "--"
|
||||
|
||||
.. __: http://docs.python.org/release/2.7/library/stdtypes.html#mutable-sequence-types
|
||||
|
||||
|
||||
.. rubric:: Property access
|
||||
|
||||
Each node holds a number of :dfn:`properties`. Each property is identified by
|
||||
a short string called the :dfn:`PropIdent`, eg ``"SZ"`` or ``"B"``. See
|
||||
:ref:`sgf_property_list` below for a list of the standard properties. See the
|
||||
:term:`SGF` specification for full details. See :ref:`parsing_details` below
|
||||
for restrictions on well-formed *PropIdents*.
|
||||
|
||||
Gomill doesn't enforce |sgf|'s restrictions on where properties can appear
|
||||
(eg, the distinction between *setup* and *move* properties).
|
||||
|
||||
The principal methods for accessing the node's properties are:
|
||||
|
||||
.. method:: Tree_node.get(identifier)
|
||||
|
||||
Returns a native Python representation of the value of the property whose
|
||||
*PropIdent* is *identifier*.
|
||||
|
||||
Raises :exc:`KeyError` if the property isn't present.
|
||||
|
||||
Raises :exc:`ValueError` if it detects that the property value is
|
||||
malformed.
|
||||
|
||||
See :ref:`sgf_property_types` below for details of how property values are
|
||||
represented in Python.
|
||||
|
||||
See :ref:`sgf_property_list` below for a list of the known properties.
|
||||
Setting nonstandard properties is permitted; they are treated as having
|
||||
type Text.
|
||||
|
||||
.. method:: Tree_node.set(identifier, value)
|
||||
|
||||
Sets the value of the property whose *PropIdent* is *identifier*.
|
||||
|
||||
*value* should be a native Python representation of the required property
|
||||
value (as returned by :meth:`get`).
|
||||
|
||||
Raises :exc:`ValueError` if the property value isn't acceptable.
|
||||
|
||||
See :ref:`sgf_property_types` below for details of how property values
|
||||
should be represented in Python.
|
||||
|
||||
See :ref:`sgf_property_list` below for a list of the known properties. Any
|
||||
other property is treated as having type Text.
|
||||
|
||||
.. method:: Tree_node.unset(identifier)
|
||||
|
||||
Removes the property whose *PropIdent* is *identifier* from the node.
|
||||
|
||||
Raises :exc:`KeyError` if the property isn't currently present.
|
||||
|
||||
.. method:: Tree_node.has_property(identifier)
|
||||
|
||||
:rtype: bool
|
||||
|
||||
Checks whether the property whose *PropIdent* is *identifier* is present.
|
||||
|
||||
.. method:: Tree_node.properties()
|
||||
|
||||
:rtype: list of strings
|
||||
|
||||
Lists the properties which are present in the node.
|
||||
|
||||
Returns a list of *PropIdents*, in unspecified order.
|
||||
|
||||
.. method:: Tree_node.find_property(identifier)
|
||||
|
||||
Returns the value of the property whose *PropIdent* is *identifier*,
|
||||
looking in the node's ancestors if necessary.
|
||||
|
||||
This is intended for use with properties of type *game-info*, and with
|
||||
properties which have the *inherit* attribute.
|
||||
|
||||
It looks first in the node itself, then in its parent, and so on up to the
|
||||
root, returning the first value it finds. Otherwise the behaviour is the
|
||||
same as :meth:`get`.
|
||||
|
||||
Raises :exc:`KeyError` if no node defining the property is found.
|
||||
|
||||
|
||||
.. method:: Tree_node.find(identifier)
|
||||
|
||||
:rtype: :class:`!Tree_node` or ``None``
|
||||
|
||||
Returns the nearest node defining the property whose *PropIdent* is
|
||||
*identifier*.
|
||||
|
||||
Searches in the same way as :meth:`find_property`, but returns the node
|
||||
rather than the property value. Returns ``None`` if no node defining the
|
||||
property is found.
|
||||
|
||||
|
||||
.. rubric:: Convenience methods for properties
|
||||
|
||||
The following convenience methods are also provided, for more flexible access
|
||||
to a few of the most important properties:
|
||||
|
||||
.. method:: Tree_node.get_move()
|
||||
|
||||
:rtype: tuple (*colour*, *move*)
|
||||
|
||||
Indicates which of the the ``B`` or ``W`` properties is present, and
|
||||
returns its value.
|
||||
|
||||
Returns (``None``, ``None``) if neither property is present.
|
||||
|
||||
.. method:: Tree_node.set_move(colour, move)
|
||||
|
||||
Sets the ``B`` or ``W`` property. If the other property is currently
|
||||
present, it is removed.
|
||||
|
||||
Gomill doesn't attempt to ensure that moves are legal.
|
||||
|
||||
.. method:: Tree_node.get_setup_stones()
|
||||
|
||||
:rtype: tuple (set of *points*, set of *points*, set of *points*)
|
||||
|
||||
Returns the settings of the ``AB``, ``AW``, and ``AE`` properties.
|
||||
|
||||
The tuple elements represent black, white, and empty points respectively.
|
||||
If a property is missing, the corresponding set is empty.
|
||||
|
||||
.. method:: Tree_node.set_setup_stones(black, white[, empty])
|
||||
|
||||
Sets the ``AB``, ``AW``, and ``AE`` properties.
|
||||
|
||||
Each parameter should be a sequence or set of *points*. If a parameter
|
||||
value is empty (or, in the case of *empty*, if the parameter is
|
||||
omitted) the corresponding property will be unset.
|
||||
|
||||
.. method:: Tree_node.has_setup_stones()
|
||||
|
||||
:rtype: bool
|
||||
|
||||
Returns ``True`` if the ``AB``, ``AW``, or ``AE`` property is present.
|
||||
|
||||
.. method:: Tree_node.add_comment_text(text)
|
||||
|
||||
If the ``C`` property isn't already present, adds it with the value given
|
||||
by the string *text*.
|
||||
|
||||
Otherwise, appends *text* to the existing ``C`` property value, preceded by
|
||||
two newlines.
|
||||
|
||||
|
||||
.. rubric:: Board size and raw property encoding
|
||||
|
||||
Each :class:`!Tree_node` knows its game's board size, and its :ref:`raw
|
||||
property encoding <raw_property_encoding>` (because these are needed to
|
||||
interpret property values). They can be retrieved using the following methods:
|
||||
|
||||
.. method:: Tree_node.get_size()
|
||||
|
||||
:rtype: int
|
||||
|
||||
.. method:: Tree_node.get_encoding()
|
||||
|
||||
:rtype: string
|
||||
|
||||
This returns the name of the raw property encoding (in a normalised form,
|
||||
which may not be the same as the string originally used to specify the
|
||||
encoding).
|
||||
|
||||
An attempt to change the value of the ``SZ`` property so that it doesn't match
|
||||
the board size will raise :exc:`ValueError` (even if the node isn't the root).
|
||||
|
||||
|
||||
.. rubric:: Access to raw property values
|
||||
|
||||
Raw property values are 8-bit strings, containing the exact bytes that go
|
||||
between the ``[`` and ``]`` in the |sgf| file. They should be treated as being
|
||||
encoded in the node's :ref:`raw property encoding <raw_property_encoding>`
|
||||
(but there is no guarantee that they hold properly encoded data).
|
||||
|
||||
The following methods are provided for access to raw property values. They can
|
||||
be used to access malformed values, or to avoid the standard escape processing
|
||||
and whitespace conversion for Text and SimpleText values.
|
||||
|
||||
When setting raw property values, any string that is a well formed |sgf|
|
||||
*PropValue* is accepted: that is, any string that that doesn't contain an
|
||||
unescaped ``]`` or end with an unescaped ``\``. There is no check that the
|
||||
string is properly encoded in the raw property encoding.
|
||||
|
||||
.. method:: Tree_node.get_raw_list(identifier)
|
||||
|
||||
:rtype: nonempty list of 8-bit strings
|
||||
|
||||
Returns the raw values of the property whose *PropIdent* is *identifier*.
|
||||
|
||||
Raises :exc:`KeyError` if the property isn't currently present.
|
||||
|
||||
If the property value is an empty elist, returns a list containing a single
|
||||
empty string.
|
||||
|
||||
.. method:: Tree_node.get_raw(identifier)
|
||||
|
||||
:rtype: 8-bit string
|
||||
|
||||
Returns the raw value of the property whose *PropIdent* is *identifier*.
|
||||
|
||||
Raises :exc:`KeyError` if the property isn't currently present.
|
||||
|
||||
If the property has multiple `PropValue`\ s, returns the first. If the
|
||||
property value is an empty elist, returns an empty string.
|
||||
|
||||
.. method:: Tree_node.get_raw_property_map(identifier)
|
||||
|
||||
:rtype: dict: string → list of 8-bit strings
|
||||
|
||||
Returns a dict mapping *PropIdents* to lists of raw values.
|
||||
|
||||
Returns the same dict object each time it's called.
|
||||
|
||||
Treat the returned dict object as read-only.
|
||||
|
||||
.. method:: Tree_node.set_raw_list(identifier, values)
|
||||
|
||||
Sets the raw values of the property whose *PropIdent* is *identifier*.
|
||||
|
||||
*values* must be a nonempty list of 8-bit strings. To specify an empty
|
||||
elist, pass a list containing a single empty string.
|
||||
|
||||
Raises :exc:`ValueError` if the identifier isn't a well-formed *PropIdent*,
|
||||
or if any value isn't a well-formed *PropValue*.
|
||||
|
||||
.. method:: Tree_node.set_raw(identifier, value)
|
||||
|
||||
Sets the raw value of the property whose *PropIdent* is *identifier*.
|
||||
|
||||
Raises :exc:`ValueError` if the identifier isn't a well-formed *PropIdent*,
|
||||
or if the value isn't a well-formed *PropValue*.
|
||||
|
||||
|
||||
.. rubric:: Tree manipulation
|
||||
|
||||
The following methods are provided for manipulating the tree:
|
||||
|
||||
.. method:: Tree_node.new_child([index])
|
||||
|
||||
:rtype: :class:`!Tree_node`
|
||||
|
||||
Creates a new :class:`!Tree_node` and adds it to the tree as this node's
|
||||
last child.
|
||||
|
||||
If the optional integer *index* parameter is present, the new node is
|
||||
inserted in the list of children at the specified index instead (with the
|
||||
same behaviour as :meth:`!list.insert`).
|
||||
|
||||
Returns the new node.
|
||||
|
||||
.. method:: Tree_node.delete()
|
||||
|
||||
Removes the node from the tree (along with all its descendents).
|
||||
|
||||
Raises :exc:`ValueError` if called on the root node.
|
||||
|
||||
You should not continue to use a node which has been removed from its tree.
|
||||
|
||||
.. method:: Tree_node.reparent(new_parent[, index])
|
||||
|
||||
Moves the node from one part of the tree to another (along with all its
|
||||
descendents).
|
||||
|
||||
*new_parent* must be a node belonging to the same game.
|
||||
|
||||
Raises :exc:`ValueError` if the operation would create a loop in the tree
|
||||
(ie, if *new_parent* is the node being moved or one of its descendents).
|
||||
|
||||
If the optional integer *index* parameter is present, the new node is
|
||||
inserted in the new parent's list of children at the specified index;
|
||||
otherwise it is placed at the end.
|
||||
|
||||
This method can be used to reorder variations. For example, to make a node
|
||||
the leftmost variation of its parent::
|
||||
|
||||
node.reparent(node.parent, 0)
|
||||
|
||||
|
||||
.. _sgf_property_types:
|
||||
|
||||
Property types
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The :meth:`~Tree_node.get` and :meth:`~Tree_node.set` node methods convert
|
||||
between raw |sgf| property values and suitable native Python types.
|
||||
|
||||
The following table shows how |sgf| property types are represented as Python
|
||||
values:
|
||||
|
||||
=========== ========================
|
||||
|sgf| type Python representation
|
||||
=========== ========================
|
||||
None ``True``
|
||||
Number int
|
||||
Real float
|
||||
Double ``1`` or ``2`` (int)
|
||||
Colour *colour*
|
||||
SimpleText 8-bit UTF-8 string
|
||||
Text 8-bit UTF-8 string
|
||||
Stone *point*
|
||||
Point *point*
|
||||
Move *move*
|
||||
=========== ========================
|
||||
|
||||
Gomill doesn't distinguish the Point and Stone |sgf| property types. It
|
||||
rejects representations of 'pass' for the Point and Stone types, but accepts
|
||||
them for Move (this is not what is described in the |sgf| specification, but
|
||||
it does correspond to the properties in which 'pass' makes sense).
|
||||
|
||||
Values of list or elist types are represented as Python lists. An empty elist
|
||||
is represented as an empty Python list (in contrast, the raw value is a list
|
||||
containing a single empty string).
|
||||
|
||||
Values of compose types are represented as Python pairs (tuples of length
|
||||
two). ``FG`` values are either a pair (int, string) or ``None``.
|
||||
|
||||
For Text and SimpleText values, :meth:`~Tree_node.get` and
|
||||
:meth:`~Tree_node.set` take care of escaping. You can store arbitrary strings
|
||||
in a Text value and retrieve them unchanged, with the following exceptions:
|
||||
|
||||
* all linebreaks are are normalised to ``\n``
|
||||
|
||||
* whitespace other than line breaks is converted to a single space
|
||||
|
||||
:meth:`~Tree_node.get` accepts compressed point lists, but
|
||||
:meth:`~Tree_node.set` never produces them (some |sgf| viewers still don't
|
||||
support them).
|
||||
|
||||
In some cases, :meth:`~Tree_node.get` will accept values which are not
|
||||
strictly permitted in |sgf|, if there's a sensible way to interpret them. In
|
||||
particular, empty lists are accepted for all list types (not only elists).
|
||||
|
||||
In some cases, :meth:`~Tree_node.set` will accept values which are not exactly
|
||||
in the Python representation listed, if there's a natural way to convert them
|
||||
to the |sgf| representation.
|
||||
|
||||
Both :meth:`~Tree_node.get` and :meth:`~Tree_node.set` check that Point values
|
||||
are in range for the board size. Neither :meth:`~Tree_node.get` nor
|
||||
:meth:`~Tree_node.set` pays attention to range restrictions for values of type
|
||||
Number.
|
||||
|
||||
Examples::
|
||||
|
||||
>>> node.set('KO', True)
|
||||
>>> node.get_raw('KO')
|
||||
''
|
||||
>>> node.set('HA', 3)
|
||||
>>> node.set('KM', 5.5)
|
||||
>>> node.set('GB', 2)
|
||||
>>> node.set('PL', 'w')
|
||||
>>> node.set('RE', 'W+R')
|
||||
>>> node.set('GC', 'Example game\n[for documentation]')
|
||||
>>> node.get_raw('GC')
|
||||
'Example game\n[for documentation\\]'
|
||||
>>> node.set('B', (2, 3))
|
||||
>>> node.get_raw('B')
|
||||
'dg'
|
||||
>>> node.set('LB', [((6, 0), "label 1"), ((6, 1), "label 2")])
|
||||
>>> node.get_raw_list('LB')
|
||||
['ac:label 1', 'bc:label 2']
|
||||
|
||||
|
||||
|
||||
.. _sgf_property_list:
|
||||
|
||||
Property list
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Gomill knows the types of all general and Go-specific |sgf| properties defined
|
||||
in FF[4]:
|
||||
|
||||
====== ========================== ===================
|
||||
Id |sgf| type Meaning
|
||||
====== ========================== ===================
|
||||
``AB`` list of Stone Add Black
|
||||
``AE`` list of Point Add Empty
|
||||
``AN`` SimpleText Annotation
|
||||
``AP`` SimpleText:SimpleText Application
|
||||
``AR`` list of Point:Point Arrow
|
||||
``AW`` list of Stone Add White
|
||||
``B`` Move Black move
|
||||
``BL`` Real Black time left
|
||||
``BM`` Double Bad move
|
||||
``BR`` SimpleText Black rank
|
||||
``BT`` SimpleText Black team
|
||||
``C`` Text Comment
|
||||
``CA`` SimpleText Charset
|
||||
``CP`` SimpleText Copyright
|
||||
``CR`` list of Point Circle
|
||||
``DD`` elist of Point Dim Points
|
||||
``DM`` Double Even position
|
||||
``DO`` None Doubtful
|
||||
``DT`` SimpleText Date
|
||||
``EV`` SimpleText Event
|
||||
``FF`` Number File format
|
||||
``FG`` None | Number:SimpleText Figure
|
||||
``GB`` Double Good for Black
|
||||
``GC`` Text Game comment
|
||||
``GM`` Number Game
|
||||
``GN`` SimpleText Game name
|
||||
``GW`` Double Good for White
|
||||
``HA`` Number Handicap
|
||||
``HO`` Double Hotspot
|
||||
``IT`` None Interesting
|
||||
``KM`` Real Komi
|
||||
``KO`` None Ko
|
||||
``LB`` list of Point:SimpleText Label
|
||||
``LN`` list of Point:Point Line
|
||||
``MA`` list of Point Mark
|
||||
``MN`` Number Set move number
|
||||
``N`` SimpleText Node name
|
||||
``OB`` Number Overtime stones left for Black
|
||||
``ON`` SimpleText Opening
|
||||
``OT`` SimpleText Overtime description
|
||||
``OW`` Number Overtime stones left for White
|
||||
``PB`` SimpleText Black player name
|
||||
``PC`` SimpleText Place
|
||||
``PL`` Colour Player to play
|
||||
``PM`` Number Print move mode
|
||||
``PW`` SimpleText White player name
|
||||
``RE`` SimpleText Result
|
||||
``RO`` SimpleText Round
|
||||
``RU`` SimpleText Rules
|
||||
``SL`` list of Point Selected
|
||||
``SO`` SimpleText Source
|
||||
``SQ`` list of Point Square
|
||||
``ST`` Number Style
|
||||
``SZ`` Number Size
|
||||
``TB`` elist of Point Black territory
|
||||
``TE`` Double Tesuji
|
||||
``TM`` Real Time limit
|
||||
``TR`` list of Point Triangle
|
||||
``TW`` elist of Point White territory
|
||||
``UC`` Double Unclear position
|
||||
``US`` SimpleText User
|
||||
``V`` Real Value
|
||||
``VW`` elist of Point View
|
||||
``W`` Move White move
|
||||
``WL`` Real White time left
|
||||
``WR`` SimpleText White rank
|
||||
``WT`` SimpleText White team
|
||||
====== ========================== ===================
|
||||
|
||||
|
||||
.. _raw_property_encoding:
|
||||
|
||||
Character encoding handling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The |sgf| format is defined as containing ASCII-encoded data, possibly with
|
||||
non-ASCII characters in Text and SimpleText property values. The Gomill
|
||||
functions for loading and serialising |sgf| data work with 8-bit Python
|
||||
strings.
|
||||
|
||||
The encoding used for Text and SimpleText property values is given by the
|
||||
``CA`` root property (if that isn't present, the encoding is ``ISO-8859-1``).
|
||||
|
||||
In order for an encoding to be used in Gomill, it must exist as a Python
|
||||
built-in codec, and it must be compatible with ASCII (at least whitespace,
|
||||
``\``, ``]``, and ``:`` must be in the usual places). Behaviour is unspecified
|
||||
if a non-ASCII-compatible encoding is requested.
|
||||
|
||||
When encodings are passed as parameters (or returned from functions), they are
|
||||
represented using the names or aliases of Python built-in codecs (eg
|
||||
``"UTF-8"`` or ``"ISO-8859-1"``). See `standard encodings`__ for a list.
|
||||
Values of the ``CA`` property are interpreted in the same way.
|
||||
|
||||
.. __: http://docs.python.org/release/2.7/library/codecs.html#standard-encodings
|
||||
|
||||
Each :class:`.Sgf_game` and :class:`.Tree_node` has a fixed :dfn:`raw property
|
||||
encoding`, which is the encoding used internally to store the property values.
|
||||
The :meth:`Tree_node.get_raw` and :meth:`Tree_node.set_raw` methods use the
|
||||
raw property encoding.
|
||||
|
||||
When an |sgf| game is loaded from a file, the raw property encoding is the
|
||||
original file encoding (unless overridden). Improperly encoded property values
|
||||
will not be detected until they are accessed (:meth:`~Tree_node.get` will
|
||||
raise :exc:`ValueError`; use :meth:`~Tree_node.get_raw` to retrieve the actual
|
||||
bytes).
|
||||
|
||||
|
||||
.. _transcoding:
|
||||
|
||||
.. rubric:: Transcoding
|
||||
|
||||
When an |sgf| game is serialised to a string, the encoding represented by the
|
||||
``CA`` root property is used. This :dfn:`target encoding` will be the same as
|
||||
the raw property encoding unless ``CA`` has been changed since the
|
||||
:class:`.Sgf_game` was created.
|
||||
|
||||
When the raw property encoding and the target encoding match, the raw property
|
||||
values are included unchanged in the output (even if they are improperly
|
||||
encoded.)
|
||||
|
||||
Otherwise, if any raw property value is improperly encoded,
|
||||
:exc:`UnicodeDecodeError` is raised, and if any property value can't be
|
||||
represented in the target encoding, :exc:`UnicodeEncodeError` is raised.
|
||||
|
||||
If the target encoding doesn't identify a Python codec, :exc:`ValueError` is
|
||||
raised. The behaviour of :meth:`~Sgf_game.serialise` is unspecified if the
|
||||
target encoding isn't ASCII-compatible (eg, UTF-16).
|
||||
|
||||
|
||||
.. _parsing_details:
|
||||
|
||||
Parsing
|
||||
^^^^^^^
|
||||
|
||||
The parser permits non-|sgf| content to appear before the beginning and after
|
||||
the end of the game. It identifies the start of |sgf| content by looking for
|
||||
``(;`` (with possible whitespace between the two characters).
|
||||
|
||||
The parser accepts at most 8 letters in *PropIdents* (there is no formal limit
|
||||
in the specification, but no standard property has more than 2).
|
||||
|
||||
The parser doesn't perform any checks on property values. In particular, it
|
||||
allows multiple values to be present for any property.
|
||||
|
||||
The parser doesn't, in general, attempt to 'fix' ill-formed |sgf| content. As
|
||||
an exception, if a *PropIdent* appears more than once in a node it is
|
||||
converted to a single property with multiple values.
|
||||
|
||||
The parser doesn't permit lower-case letters in *PropIdents* (these are
|
||||
allowed in some ancient |sgf| variants).
|
||||
|
||||
|
||||
The :mod:`!sgf_moves` module
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. module:: gomill.sgf_moves
|
||||
:synopsis: Higher-level processing of moves and positions from SGF games.
|
||||
|
||||
The :mod:`!gomill.sgf_moves` module contains some higher-level functions for
|
||||
processing moves and positions, and provides a link to the :mod:`.boards`
|
||||
module.
|
||||
|
||||
|
||||
.. function:: get_setup_and_moves(sgf_game[, board])
|
||||
|
||||
:rtype: tuple (:class:`.Board`, list of tuples (*colour*, *move*))
|
||||
|
||||
Returns the initial setup and the following moves from an
|
||||
:class:`.Sgf_game`.
|
||||
|
||||
The board represents the position described by ``AB`` and/or ``AW``
|
||||
properties in the |sgf| game's root node. :exc:`ValueError` is raised if
|
||||
this position isn't legal.
|
||||
|
||||
The moves are from the game's leftmost variation. Doesn't check that the
|
||||
moves are legal.
|
||||
|
||||
Raises :exc:`ValueError` if the game has structure it doesn't support.
|
||||
|
||||
Currently doesn't support ``AB``/``AW``/``AE`` properties after the root
|
||||
node.
|
||||
|
||||
If the optional *board* parameter is provided, it must be an empty
|
||||
:class:`.Board` of the right size; the same object will be returned (this
|
||||
option is provided so you can use a different Board class).
|
||||
|
||||
See also the :script:`show_sgf.py` example script.
|
||||
|
||||
|
||||
.. function:: set_initial_position(sgf_game, board)
|
||||
|
||||
Adds ``AB``/``AW``/``AE`` properties to an :class:`.Sgf_game`'s root node,
|
||||
to reflect the position from a :class:`.Board`.
|
||||
|
||||
Replaces any existing ``AB``/``AW``/``AE`` properties in the root node.
|
||||
|
||||
|
||||
.. function:: indicate_first_player(sgf_game)
|
||||
|
||||
Adds a ``PL`` property to an :class:`.Sgf_game`'s root node if appropriate,
|
||||
to indicate which colour is first to play.
|
||||
|
||||
Looks at the first child of the root to see who the first player is, and
|
||||
sets ``PL`` it isn't the expected player (Black normally, but White if
|
||||
there is a handicap), or if there are non-handicap setup stones.
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue