Included gomill framework for SGF and GTP support, and sketched out SGF game-loading code.
This commit is contained in:
43
gomill/docs/_static/gomill.css_t
vendored
Normal file
43
gomill/docs/_static/gomill.css_t
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
@import url("default.css");
|
||||
|
||||
p.topic-title {
|
||||
color: {{ theme_headtextcolor }};
|
||||
}
|
||||
|
||||
dl.setting dd > p:first-child,
|
||||
dl.mc-setting dd > p:first-child,
|
||||
dl.ce-setting dd > p:first-child,
|
||||
dl.gtp dd > p:first-child {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
tt.std-gtp span.pre {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
li.current > a {color: yellow;}
|
||||
|
||||
div.tip {
|
||||
background-color: #EEEEEE;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
div.caution {
|
||||
background-color: #EEEEEE;
|
||||
border: 1px solid #A00000;
|
||||
}
|
||||
|
||||
abbr {
|
||||
border-bottom: none; cursor:help;
|
||||
}
|
||||
|
||||
th.field-name {
|
||||
background-color: #E4E4E4;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
div#library-overview table.docutils {
|
||||
width : 100%;
|
||||
margin-bottom: 3ex;
|
||||
}
|
||||
|
35
gomill/docs/_templates/genindex.html
vendored
Normal file
35
gomill/docs/_templates/genindex.html
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
{% extends "!genindex.html" %}
|
||||
{% block body %}
|
||||
|
||||
<h1 id="index">{{ _('Index') }}</h1>
|
||||
|
||||
<div class="genindex-jumpbox">
|
||||
{% for key, dummy in genindexentries -%}
|
||||
<a href="#{{ key }}"><strong>{{ key }}</strong></a> {% if not loop.last %}| {% endif %}
|
||||
{%- endfor %}
|
||||
</div>
|
||||
|
||||
{%- for key, entries in genindexentries %}
|
||||
<h2 id="{{ key }}">{{ key }}</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td valign="top"><dl>
|
||||
{%- for entryname, (links, subitems) in entries %}
|
||||
<dt>{% if links %}<a href="{{ links[0] }}">{{ entryname|e }}</a>
|
||||
{%- for link in links[1:] %}, <a href="{{ link }}">[{{ loop.index }}]</a>{% endfor %}
|
||||
{%- else %}{{ entryname|e }}{% endif %}</dt>
|
||||
{%- if subitems %}
|
||||
<dd><dl>
|
||||
{%- for subentryname, subentrylinks in subitems %}
|
||||
<dt><a href="{{ subentrylinks[0] }}">{{ subentryname|e }}</a>
|
||||
{%- for link in subentrylinks[1:] %}, <a href="{{ link }}">[{{ loop.index }}]</a>{% endfor -%}
|
||||
</dt>
|
||||
{%- endfor %}
|
||||
</dl></dd>
|
||||
{%- endif -%}
|
||||
{%- endfor %}
|
||||
</dl></td>
|
||||
</tr></table>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
2
gomill/docs/_templates/wholetoc.html
vendored
Normal file
2
gomill/docs/_templates/wholetoc.html
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
<h3><a href="{{ pathto(master_doc) }}">{{ _('Table Of Contents') }}</a></h3>
|
||||
{{ toctree(collapse=False) }}
|
120
gomill/docs/allplayalls.rst
Normal file
120
gomill/docs/allplayalls.rst
Normal file
@ -0,0 +1,120 @@
|
||||
.. index:: all-play-all
|
||||
|
||||
All-play-all tournaments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
:setting:`competition_type` string: ``"allplayall"``.
|
||||
|
||||
In an all-play-all tournament the control file lists a number of players (the
|
||||
:dfn:`competitors`), and games are played between each possible pairing.
|
||||
|
||||
All games are played with no handicap and with the same komi. The players in
|
||||
each pairing will swap colours in successive games.
|
||||
|
||||
For most purposes an all-play-all tournament is equivalent to a playoff
|
||||
tournament with a matchup defined for each pair of competitors; the main
|
||||
difference is that reports include a results summary grid.
|
||||
|
||||
The tournament runs until :aa-setting:`rounds` games have been played between
|
||||
each pairing (indefinitely, if :aa-setting:`rounds` is unset).
|
||||
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
.. _sample_allplayall_control_file:
|
||||
|
||||
Sample control file
|
||||
"""""""""""""""""""
|
||||
|
||||
Here is a sample control file::
|
||||
|
||||
competition_type = 'allplayall'
|
||||
|
||||
players = {
|
||||
'gnugo-l1' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=1"),
|
||||
|
||||
'gnugo-l2' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=2"),
|
||||
|
||||
'gnugo-l3' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=3"),
|
||||
}
|
||||
|
||||
board_size = 9
|
||||
komi = 6
|
||||
|
||||
rounds = 20
|
||||
competitors = ['gnugo-l1', 'gnugo-l2', 'gnugo-l3']
|
||||
|
||||
|
||||
.. _allplayall_control_file_settings:
|
||||
|
||||
Control file settings
|
||||
"""""""""""""""""""""
|
||||
|
||||
The following settings can be set at the top level of the control file:
|
||||
|
||||
All :ref:`common settings <common settings>`.
|
||||
|
||||
The following game settings: :setting:`board_size`, :setting:`komi`,
|
||||
:setting:`move_limit`, :setting:`scorer`.
|
||||
|
||||
The following additional settings:
|
||||
|
||||
.. aa-setting:: competitors
|
||||
|
||||
List of :ref:`player codes <player codes>`.
|
||||
|
||||
This defines which players will take part. Reports will list the players
|
||||
in the order in which they appear here. You may not list the same player
|
||||
more than once.
|
||||
|
||||
.. aa-setting:: rounds
|
||||
|
||||
Integer (default ``None``)
|
||||
|
||||
The number of games to play for each pairing. If you leave this unset, the
|
||||
tournament will continue indefinitely.
|
||||
|
||||
The only required settings are :setting:`competition_type`,
|
||||
:setting:`players`, :aa-setting:`competitors`, :setting:`board_size`, and
|
||||
:setting:`komi`.
|
||||
|
||||
|
||||
Reporting
|
||||
"""""""""
|
||||
|
||||
The :ref:`live display <live_display>` and :ref:`competition report
|
||||
<competition report file>` summarise the tournament results in the form of a
|
||||
grid, for example::
|
||||
|
||||
A B C
|
||||
A gnugo-l1 4-5 3-5
|
||||
B gnugo-l2 5-4 3-5
|
||||
C gnugo-l3 5-3 5-3
|
||||
|
||||
Each row shows the number of wins and losses for the player named on that row
|
||||
against each opponent (in the example, ``gnugo-l1`` has won 4 games and lost 5
|
||||
against ``gnugo-l2``).
|
||||
|
||||
If any games have unknown results (because they could not be scored, or
|
||||
reached the :setting:`move_limit`), they will not be shown in the grid.
|
||||
|
||||
The competition report also shows full details of each pairing in the same
|
||||
style as playoff tournaments.
|
||||
|
||||
For purposes of the :doc:`tournament results API <tournament_results>`, the
|
||||
matchup ids are of the form ``AvB`` (using the competitor letters shown in the
|
||||
results grid).
|
||||
|
||||
|
||||
Changing the control file between runs
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
You can add new players to the end of the :aa-setting:`competitors` list
|
||||
between runs, but you may not remove or reorder competitors.
|
||||
|
52
gomill/docs/ascii_boards.rst
Normal file
52
gomill/docs/ascii_boards.rst
Normal file
@ -0,0 +1,52 @@
|
||||
The :mod:`~gomill.ascii_boards` module
|
||||
--------------------------------------
|
||||
|
||||
.. module:: gomill.ascii_boards
|
||||
:synopsis: ASCII Go board diagrams.
|
||||
|
||||
The :mod:`!gomill.ascii_boards` module contains functions for producing and
|
||||
interpreting ASCII diagrams of Go board positions.
|
||||
|
||||
|
||||
.. function:: render_board(board)
|
||||
|
||||
:rtype: string
|
||||
|
||||
Returns an ASCII diagram of the position on the :class:`.Board` *board*.
|
||||
|
||||
The returned string does not end with a newline.
|
||||
|
||||
::
|
||||
|
||||
>>> b = boards.Board(9)
|
||||
>>> b.play(2, 5, 'b')
|
||||
>>> b.play(3, 6, 'w')
|
||||
>>> print ascii_boards.render_board(b)
|
||||
9 . . . . . . . . .
|
||||
8 . . . . . . . . .
|
||||
7 . . . . . . . . .
|
||||
6 . . . . . . . . .
|
||||
5 . . . . . . . . .
|
||||
4 . . . . . . o . .
|
||||
3 . . . . . # . . .
|
||||
2 . . . . . . . . .
|
||||
1 . . . . . . . . .
|
||||
A B C D E F G H J
|
||||
|
||||
See also the :script:`show_sgf.py` example script.
|
||||
|
||||
|
||||
.. function:: interpret_diagram(diagram, size[, board])
|
||||
|
||||
:rtype: :class:`.Board`
|
||||
|
||||
Returns the position given in an ASCII diagram.
|
||||
|
||||
*diagram* must be a string in the format returned by :func:`render_board`,
|
||||
representing a position with the specified size.
|
||||
|
||||
Raises :exc:`ValueError` if it can't interpret the diagram.
|
||||
|
||||
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).
|
114
gomill/docs/boards.rst
Normal file
114
gomill/docs/boards.rst
Normal file
@ -0,0 +1,114 @@
|
||||
The :mod:`~gomill.boards` module
|
||||
--------------------------------
|
||||
|
||||
.. module:: gomill.boards
|
||||
:synopsis: Go board representation.
|
||||
|
||||
The :mod:`!gomill.boards` module contains Gomill's Go board representation.
|
||||
|
||||
Everything in this module works with boards of arbitrarily large sizes.
|
||||
|
||||
The implementation is not designed for speed (even as Python code goes), and
|
||||
is certainly not appropriate for implementing a playing engine.
|
||||
|
||||
The module contains a single class:
|
||||
|
||||
|
||||
.. class:: Board(side)
|
||||
|
||||
A :class:`!Board` object represents a legal position on a Go board.
|
||||
|
||||
Instantiate with the board size, as an int >= 1. Only square boards are
|
||||
supported. The board is initially empty.
|
||||
|
||||
Board objects do not maintain any history information.
|
||||
|
||||
Board objects have the following attributes (which should be treated as
|
||||
read-only):
|
||||
|
||||
.. attribute:: side
|
||||
|
||||
The board size.
|
||||
|
||||
.. attribute:: board_points
|
||||
|
||||
A list of *points*, giving all points on the board.
|
||||
|
||||
|
||||
The principal :class:`!Board` methods are :meth:`!get` and :meth:`!play`.
|
||||
Their *row* and *col* parameters should be ints representing coordinates in
|
||||
the :ref:`system <go_related_data_representation>` used for a *point*.
|
||||
|
||||
The behaviour of :class:`!Board` methods is unspecified if they are passed
|
||||
out-of-range coordinates.
|
||||
|
||||
.. method:: Board.get(row, col)
|
||||
|
||||
:rtype: *colour* or ``None``
|
||||
|
||||
Returns the contents of the specified point.
|
||||
|
||||
.. method:: Board.play(row, col, colour)
|
||||
|
||||
:rtype: *move*
|
||||
|
||||
Places a stone of the specified *colour* on the specified point.
|
||||
|
||||
Raises :exc:`ValueError` if the point isn't empty.
|
||||
|
||||
Carries out any captures which follow from the placement, including
|
||||
self-captures.
|
||||
|
||||
This method doesn't enforce any ko rule.
|
||||
|
||||
The return value indicates whether, immediately following this move, any
|
||||
point would be forbidden by the :term:`simple ko` rule. If so, that point
|
||||
is returned; otherwise the return value is ``None``.
|
||||
|
||||
|
||||
The other :class:`!Board` methods are:
|
||||
|
||||
.. method:: Board.is_empty()
|
||||
|
||||
:rtype: bool
|
||||
|
||||
Returns ``True`` if all points on the board are empty.
|
||||
|
||||
.. method:: Board.list_occupied_points()
|
||||
|
||||
:rtype: list of pairs (*colour*, *point*)
|
||||
|
||||
Returns a list of all nonempty points, in unspecified order.
|
||||
|
||||
.. method:: Board.area_score()
|
||||
|
||||
:rtype: int
|
||||
|
||||
Calculates the area score of a position, assuming that all stones are
|
||||
alive. The result is the number of points controlled (occupied or
|
||||
surrounded) by Black minus the number of points controlled by White.
|
||||
|
||||
Doesn't take any :term:`komi` into account.
|
||||
|
||||
.. method:: Board.copy()
|
||||
|
||||
:rtype: :class:`!Board`
|
||||
|
||||
Returns an independent copy of the board.
|
||||
|
||||
.. method:: Board.apply_setup(black_points, white_points, empty_points)
|
||||
|
||||
:rtype: bool
|
||||
|
||||
Adds and/or removes stones on arbitrary points. This is intended to support
|
||||
behaviour like |sgf| ``AB``/``AW``/``AE`` properties.
|
||||
|
||||
Each parameter is an iterable of *points*.
|
||||
|
||||
This method applies all the specified additions and removals, then removes
|
||||
any groups with no liberties (so the resulting position is always legal).
|
||||
|
||||
If the same point is specified in more than one list, the order in which
|
||||
the instructions are applied is undefined.
|
||||
|
||||
Returns ``True`` if the position was legal as specified.
|
376
gomill/docs/cem_tuner.rst
Normal file
376
gomill/docs/cem_tuner.rst
Normal file
@ -0,0 +1,376 @@
|
||||
.. |ce| replace:: :ref:`[CE] <ce_paper>`
|
||||
|
||||
The cross-entropy tuner
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
:setting:`competition_type` string: ``"ce_tuner"``.
|
||||
|
||||
The cross-entropy tuner uses the :dfn:`cross-entropy method` described in
|
||||
|ce|:
|
||||
|
||||
.. _ce_paper:
|
||||
|
||||
| [CE] G.M.J-B. Chaslot, M.H.M Winands, I. Szita, and H.J. van den Herik.
|
||||
| Cross-entropy for Monte-Carlo Tree Search. ICGA Journal, 31(3):145-156.
|
||||
| http://www.personeel.unimaas.nl/g-chaslot/papers/crossmcICGA.pdf
|
||||
|
||||
.. caution:: The cross-entropy tuner is experimental. It can take a very large
|
||||
number of games to converge.
|
||||
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
The tuning algorithm
|
||||
""""""""""""""""""""
|
||||
|
||||
The algorithm is not described in detail in this documentation. See |ce|
|
||||
section 3 for the description. The tuner always uses a Gaussian distribution.
|
||||
The improvement suggested in section 5 is not implemented.
|
||||
|
||||
|
||||
.. _ce parameter model:
|
||||
|
||||
The parameter model
|
||||
"""""""""""""""""""
|
||||
|
||||
The parameter values taken from the Gaussian distribution are floating-point
|
||||
numbers known as :dfn:`optimiser parameters`.
|
||||
|
||||
These parameters can be transformed before being used to configure the
|
||||
candidate (see 3.3 *Normalising Parameters* in |ce|). The transformed values
|
||||
are known as :dfn:`engine parameters`. The transformation is implemented using
|
||||
a Python :ce-setting:`transform` function defined in the control file.
|
||||
|
||||
Reports show engine parameters (see the :ce-setting:`format` parameter
|
||||
setting), together with the mean and variance of the corresponding optimiser
|
||||
parameter distribution in the form :samp:`{mean}~{variance}`.
|
||||
|
||||
|
||||
.. _the cem tuning algorithm:
|
||||
|
||||
.. _sample_cem_control_file:
|
||||
|
||||
Sample control file
|
||||
"""""""""""""""""""
|
||||
|
||||
Here is a sample control file, illustrating most of the available settings for
|
||||
a cross-entropy tuning event::
|
||||
|
||||
competition_type = "ce_tuner"
|
||||
|
||||
description = """\
|
||||
This is a sample control file.
|
||||
|
||||
It illustrates the available settings for the cross entropy tuner.
|
||||
"""
|
||||
|
||||
players = {
|
||||
'gnugo-l10' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=10"),
|
||||
}
|
||||
|
||||
def fuego(max_games, additional_commands=[]):
|
||||
commands = [
|
||||
"go_param timelimit 999999",
|
||||
"uct_max_memory 350000000",
|
||||
"uct_param_search number_threads 1",
|
||||
"uct_param_player reuse_subtree 0",
|
||||
"uct_param_player ponder 0",
|
||||
"uct_param_player max_games %d" % max_games,
|
||||
]
|
||||
return Player(
|
||||
"fuego --quiet",
|
||||
startup_gtp_commands=commands+additional_commands)
|
||||
|
||||
FUEGO_MAX_GAMES = 1000
|
||||
|
||||
def exp_10(f):
|
||||
return 10.0**f
|
||||
|
||||
parameters = [
|
||||
Parameter('rave_weight_initial',
|
||||
# Mean and variance are in terms of log_10 (rave_weight_initial)
|
||||
initial_mean = -1.0,
|
||||
initial_variance = 1.5,
|
||||
transform = exp_10,
|
||||
format = "I: %4.2f"),
|
||||
|
||||
Parameter('rave_weight_final',
|
||||
# Mean and variance are in terms of log_10 (rave_weight_final)
|
||||
initial_mean = 3.5,
|
||||
initial_variance = 1.5,
|
||||
transform = exp_10,
|
||||
format = "F: %4.2f"),
|
||||
]
|
||||
|
||||
def make_candidate(rwi, rwf):
|
||||
return fuego(
|
||||
FUEGO_MAX_GAMES,
|
||||
["uct_param_search rave_weight_initial %f" % rwi,
|
||||
"uct_param_search rave_weight_final %f" % rwf])
|
||||
|
||||
board_size = 9
|
||||
komi = 7.5
|
||||
opponent = 'gnugo-l10'
|
||||
candidate_colour = 'w'
|
||||
|
||||
number_of_generations = 5
|
||||
samples_per_generation = 100
|
||||
batch_size = 10
|
||||
elite_proportion = 0.1
|
||||
step_size = 0.8
|
||||
|
||||
|
||||
|
||||
.. _cem_control_file_settings:
|
||||
|
||||
Control file settings
|
||||
"""""""""""""""""""""
|
||||
|
||||
The following settings can be set at the top level of the control file:
|
||||
|
||||
All :ref:`common settings <common settings>` (the :setting:`players`
|
||||
dictionary is required, though it is used only to define the opponent).
|
||||
|
||||
The following game settings (only :setting:`!board_size` and :setting:`!komi`
|
||||
are required):
|
||||
|
||||
- :setting:`board_size`
|
||||
- :setting:`komi`
|
||||
- :setting:`handicap`
|
||||
- :setting:`handicap_style`
|
||||
- :setting:`move_limit`
|
||||
- :setting:`scorer`
|
||||
|
||||
|
||||
The following additional settings (they are all required):
|
||||
|
||||
.. ce-setting:: candidate_colour
|
||||
|
||||
String: ``"b"`` or ``"w"``
|
||||
|
||||
The colour for the candidates to take in every game.
|
||||
|
||||
|
||||
.. ce-setting:: opponent
|
||||
|
||||
Identifier
|
||||
|
||||
The :ref:`player code <player codes>` of the player to use as the
|
||||
candidates' opponent.
|
||||
|
||||
|
||||
.. ce-setting:: parameters
|
||||
|
||||
List of :ce-setting-cls:`Parameter` definitions (see :ref:`ce parameter
|
||||
configuration`).
|
||||
|
||||
Describes the parameters that the tuner will work with. See :ref:`ce
|
||||
parameter model` for more details.
|
||||
|
||||
The order of the :ce-setting-cls:`Parameter` definitions is used for the
|
||||
arguments to :ce-setting:`make_candidate`, and whenever parameters are
|
||||
described in reports or game records.
|
||||
|
||||
|
||||
.. ce-setting:: make_candidate
|
||||
|
||||
Python function
|
||||
|
||||
Function to create a :setting-cls:`Player` from its engine parameters.
|
||||
|
||||
This function is passed one argument for each candidate parameter, and must
|
||||
return a :setting-cls:`Player` definition. Each argument is the output of
|
||||
the corresponding Parameter's :ce-setting:`transform`.
|
||||
|
||||
The function will typically use its arguments to construct command line
|
||||
options or |gtp| commands for the player. For example::
|
||||
|
||||
def make_candidate(param1, param2):
|
||||
return Player(["goplayer", "--param1", str(param1),
|
||||
"--param2", str(param2)])
|
||||
|
||||
def make_candidate(param1, param2):
|
||||
return Player("goplayer", startup_gtp_commands=[
|
||||
["param1", str(param1)],
|
||||
["param2", str(param2)],
|
||||
])
|
||||
|
||||
|
||||
.. ce-setting:: number_of_generations
|
||||
|
||||
Positive integer
|
||||
|
||||
The number of times to repeat the tuning algorithm (*number of iterations*
|
||||
or *T* in the terminology of |ce|).
|
||||
|
||||
|
||||
.. ce-setting:: samples_per_generation
|
||||
|
||||
Positive integer
|
||||
|
||||
The number of candidates to make in each generation (*population_size* or
|
||||
*N* in the terminology of |ce|).
|
||||
|
||||
|
||||
.. ce-setting:: batch_size
|
||||
|
||||
Positive integer
|
||||
|
||||
The number of games played by each candidate.
|
||||
|
||||
|
||||
.. ce-setting:: elite_proportion
|
||||
|
||||
Float between 0.0 and 1.0
|
||||
|
||||
The proportion of candidates to select from each generation as 'elite' (the
|
||||
*selection ratio* or *ρ* in the terminology of |ce|). A value between 0.01
|
||||
and 0.1 is recommended.
|
||||
|
||||
|
||||
|
||||
.. ce-setting:: step_size
|
||||
|
||||
Float between 0.0 and 1.0
|
||||
|
||||
The rate at which to update the distribution parameters between generations
|
||||
(*α* in the terminology of |ce|).
|
||||
|
||||
.. caution:: I can't find anywhere in the paper the value they used for
|
||||
this, so I don't know what to recommend.
|
||||
|
||||
|
||||
.. _ce parameter configuration:
|
||||
|
||||
Parameter configuration
|
||||
"""""""""""""""""""""""
|
||||
|
||||
.. ce-setting-cls:: Parameter
|
||||
|
||||
A :ce-setting-cls:`!Parameter` definition has the same syntax as a Python
|
||||
function call: :samp:`Parameter({arguments})`. Apart from :ce-setting:`!code`,
|
||||
the arguments should be specified using keyword form (see
|
||||
:ref:`sample_cem_control_file`).
|
||||
|
||||
The :ce-setting:`code`, :ce-setting:`initial_mean`, and
|
||||
:ce-setting:`initial_variance` arguments are required.
|
||||
|
||||
The arguments are:
|
||||
|
||||
|
||||
.. ce-setting:: code
|
||||
|
||||
Identifier
|
||||
|
||||
A short string used to identify the parameter. This is used in error
|
||||
messages, and in the default for :ce-setting:`format`.
|
||||
|
||||
|
||||
.. ce-setting:: initial_mean
|
||||
|
||||
Float
|
||||
|
||||
The mean value for the parameter in the first generation's distribution.
|
||||
|
||||
|
||||
.. ce-setting:: initial_variance
|
||||
|
||||
Float >= 0
|
||||
|
||||
The variance for the parameter in the first generation's distribution.
|
||||
|
||||
|
||||
.. ce-setting:: transform
|
||||
|
||||
Python function (default identity)
|
||||
|
||||
Function mapping an optimiser parameter to an engine parameter; see :ref:`ce
|
||||
parameter model`.
|
||||
|
||||
Examples::
|
||||
|
||||
def exp_10(f):
|
||||
return 10.0**f
|
||||
|
||||
Parameter('p1', initial_mean = …, initial_variance = …,
|
||||
transform = exp_10)
|
||||
|
||||
If the :ce-setting:`!transform` is not specified, the optimiser parameter is
|
||||
used directly as the engine parameter.
|
||||
|
||||
|
||||
.. ce-setting:: format
|
||||
|
||||
String (default :samp:`"{parameter_code}: %s"`)
|
||||
|
||||
Format string used to display the parameter value. This should include a
|
||||
short abbreviation to indicate which parameter is being displayed, and also
|
||||
contain ``%s``, which will be replaced with the engine parameter value.
|
||||
|
||||
You can use any Python conversion specifier instead of ``%s``. For example,
|
||||
``%.2f`` will format a floating point number to two decimal places. ``%s``
|
||||
should be safe to use for all types of value. See `string formatting
|
||||
operations`__ for details.
|
||||
|
||||
.. __: http://docs.python.org/release/2.7/library/stdtypes.html#string-formatting-operations
|
||||
|
||||
Format strings should be kept short, as screen space is limited.
|
||||
|
||||
Examples::
|
||||
|
||||
Parameter('parameter_1',
|
||||
initial_mean = 0.0, initial_variance = 1.0,
|
||||
format = "p1: %.2f")
|
||||
|
||||
Parameter('parameter_2',
|
||||
initial_mean = 5000, initial_variance = 250000,
|
||||
format = "p2: %d")
|
||||
|
||||
|
||||
Reporting
|
||||
"""""""""
|
||||
|
||||
Currently, there aren't any sophisticated reports.
|
||||
|
||||
The standard report shows the parameters of the current Gaussian distribution,
|
||||
and the number of wins for each candidate in the current generation.
|
||||
|
||||
After each generation, the details of the candidates are written to the
|
||||
:ref:`history file <logging>`. The candidates selected as elite are marked
|
||||
with a ``*``.
|
||||
|
||||
|
||||
Changing the control file between runs
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Some settings can safely be changed between runs of the same cross-entropy
|
||||
tuning event:
|
||||
|
||||
:ce-setting:`batch_size`
|
||||
safe to increase
|
||||
|
||||
:ce-setting:`samples_per_generation`
|
||||
not safe to change
|
||||
|
||||
:ce-setting:`number_of_generations`
|
||||
safe to change
|
||||
|
||||
:ce-setting:`elite_proportion`
|
||||
safe to change
|
||||
|
||||
:ce-setting:`step_size`
|
||||
safe to change
|
||||
|
||||
:ce-setting:`make_candidate`
|
||||
safe to change, but don't alter play-affecting options
|
||||
|
||||
:ce-setting:`transform`
|
||||
not safe to change
|
||||
|
||||
:ce-setting:`format`
|
||||
safe to change
|
||||
|
93
gomill/docs/changes.rst
Normal file
93
gomill/docs/changes.rst
Normal file
@ -0,0 +1,93 @@
|
||||
Changes
|
||||
=======
|
||||
|
||||
Gomill 0.7.2 (2011-09-05)
|
||||
-------------------------
|
||||
|
||||
* Added the *wrap* parameter to :meth:`.Sgf_game.serialise`.
|
||||
|
||||
* Added the :script:`gomill-clop` example script.
|
||||
|
||||
|
||||
Gomill 0.7.1 (2011-08-15)
|
||||
-------------------------
|
||||
|
||||
Bug-fix release.
|
||||
|
||||
* Bug fix: made board sizes 24 and 25 work (column lettering, and therefore
|
||||
|gtp| support, was incorrect for these sizes in all previous versions).
|
||||
|
||||
* Tightened up input validation for :func:`.format_vertex` and
|
||||
:func:`.colour_name`.
|
||||
|
||||
* Distinguished Stone, Point, and Move in the :ref:`sgf_property_types`
|
||||
table in |sgf| documentation.
|
||||
|
||||
|
||||
|
||||
Gomill 0.7 (2011-08-13)
|
||||
-----------------------
|
||||
|
||||
The ringmaster now applies handicap stone compensation when using its internal
|
||||
scorer. Set :setting:`internal_scorer_handicap_compensation` to ``"no"`` to
|
||||
return to the old behaviour.
|
||||
|
||||
* Added a full implementation of :doc:`sgf`, replacing the previous minimal
|
||||
support.
|
||||
|
||||
* Added a :script:`split_sgf_collection.py` example script.
|
||||
|
||||
* The :mod:`~gomill.common`, :mod:`~gomill.boards`,
|
||||
:mod:`~gomill.ascii_boards`, and :mod:`~gomill.handicap_layout` modules are
|
||||
now documented as stable.
|
||||
|
||||
* Improved handling of long responses to the :gtp:`!version` |gtp| command.
|
||||
|
||||
* Added support for handicap stone compensation when scoring games.
|
||||
|
||||
* Gomill now checks the response to the :gtp:`!fixed_handicap` |gtp| command.
|
||||
|
||||
* Added the :data:`gomill.__version__` constant.
|
||||
|
||||
|
||||
Changes to (previously) undocumented parts of the library:
|
||||
|
||||
* Renamed the :mod:`!gomill.gomill_common` module to :mod:`!gomill.common`.
|
||||
|
||||
* Renamed the :mod:`!gomill.gomill_utils` module to :mod:`!gomill.utils`.
|
||||
|
||||
* Renamed :attr:`!Board.board_coords` to :attr:`~.Board.board_points`.
|
||||
|
||||
* Replaced the :func:`!ascii_boards.play_diagram` function with
|
||||
:func:`~.ascii_boards.interpret_diagram`, making the *board* parameter
|
||||
optional.
|
||||
|
||||
* :func:`!gtp_engine.interpret_float` now rejects infinities and NaNs.
|
||||
|
||||
* Changes to the :mod:`!gtp_states` module: tightened error handling, removed
|
||||
the komi-mangling feature, renamed :attr:`!History_move.coords` to
|
||||
:attr:`!History_move.move`.
|
||||
|
||||
|
||||
Gomill 0.6 (2011-02-13)
|
||||
-----------------------
|
||||
|
||||
Playoff tournament :ref:`state files <competition state>` from Gomill 0.5 are
|
||||
incompatible with Gomill 0.6. Tuning event state files are compatible.
|
||||
|
||||
* Added the :doc:`All-play-all <allplayalls>` tournament type.
|
||||
|
||||
* Expanded and documented the :doc:`tournament_results`. Changed return type
|
||||
of
|
||||
:meth:`~.Tournament_results.get_matchup_results`.
|
||||
|
||||
* Fixed reporting for matchups with the same player specified twice.
|
||||
|
||||
* Allowed arbitrary filename extensions for control files.
|
||||
|
||||
|
||||
Gomill 0.5 (2010-10-29)
|
||||
-----------------------
|
||||
|
||||
* First public release.
|
||||
|
74
gomill/docs/common.rst
Normal file
74
gomill/docs/common.rst
Normal file
@ -0,0 +1,74 @@
|
||||
The :mod:`~gomill.common` module
|
||||
--------------------------------
|
||||
|
||||
.. module:: gomill.common
|
||||
:synopsis: Go-related utility functions.
|
||||
|
||||
The :mod:`!gomill.common` module provides Go-related utility functions, used
|
||||
throughout Gomill.
|
||||
|
||||
It is designed to be safe to use as ``from common import *``.
|
||||
|
||||
.. function:: opponent_of(colour)
|
||||
|
||||
:rtype: *colour*
|
||||
|
||||
Returns the other colour::
|
||||
|
||||
>>> opponent_of('b')
|
||||
'w'
|
||||
|
||||
.. function:: colour_name(colour)
|
||||
|
||||
:rtype: string
|
||||
|
||||
Returns the (lower-case) full name of a *colour*::
|
||||
|
||||
>>> colour_name('b')
|
||||
'black'
|
||||
|
||||
.. function:: format_vertex(move)
|
||||
|
||||
:rtype: string
|
||||
|
||||
Returns a string describing a *move* in conventional notation::
|
||||
|
||||
>>> format_vertex((3, 0))
|
||||
'A4'
|
||||
>>> format_vertex(None)
|
||||
'pass'
|
||||
|
||||
The result is suitable for use directly in |GTP| responses. Note that ``I``
|
||||
is omitted from the letters used to indicate columns, so the maximum
|
||||
supported column value is ``25``.
|
||||
|
||||
.. function:: format_vertex_list(moves)
|
||||
|
||||
:rtype: string
|
||||
|
||||
Returns a string describing a sequence of *moves*::
|
||||
|
||||
>>> format_vertex_list([(0, 1), (2, 3), None])
|
||||
'B1,D3,pass'
|
||||
>>> format_vertex_list([])
|
||||
''
|
||||
|
||||
.. function:: move_from_vertex(vertex, board_size)
|
||||
|
||||
:rtype: *move*
|
||||
|
||||
Interprets the string *vertex* as conventional notation, assuming a square
|
||||
board whose side is *board_size*::
|
||||
|
||||
>>> move_from_vertex("A4", 9)
|
||||
(3, 0)
|
||||
>>> move_from_vertex("a4", 9)
|
||||
(3, 0)
|
||||
>>> move_from_vertex("pass", 9)
|
||||
None
|
||||
|
||||
Raises :exc:`ValueError` if it can't parse the string, or if the resulting
|
||||
point would be off the board.
|
||||
|
||||
Treats *vertex* case-insensitively.
|
||||
|
64
gomill/docs/competition_types.rst
Normal file
64
gomill/docs/competition_types.rst
Normal file
@ -0,0 +1,64 @@
|
||||
.. index:: competition type
|
||||
|
||||
.. _competition types:
|
||||
|
||||
Competition types
|
||||
-----------------
|
||||
|
||||
The ringmaster supports a number of different :dfn:`competition types`. These
|
||||
are divided into :dfn:`tournaments` and :dfn:`tuning events`.
|
||||
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
.. index:: tournament
|
||||
|
||||
.. _tournaments:
|
||||
|
||||
Tournaments
|
||||
^^^^^^^^^^^
|
||||
|
||||
A :dfn:`tournament` is a form of competition in which the ringmaster plays
|
||||
games between predefined players, in order to compare their strengths.
|
||||
|
||||
|
||||
There are currently two types of tournament:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:titlesonly:
|
||||
|
||||
Playoff <playoffs>
|
||||
All-play-all <allplayalls>
|
||||
|
||||
|
||||
.. index:: tuning event
|
||||
|
||||
.. _tuners:
|
||||
|
||||
Tuning events
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
A :dfn:`tuning event` is a form of competition in which the ringmaster runs an
|
||||
algorithm which adjusts engine parameters to try to find the values which give
|
||||
strongest play.
|
||||
|
||||
.. index:: opponent
|
||||
|
||||
At present, all tuning events work by playing games between different
|
||||
:dfn:`candidate` players and a single fixed :dfn:`opponent` player. The
|
||||
candidate always takes the same colour. The komi and any handicap can be
|
||||
specified as usual.
|
||||
|
||||
There are currently two tuning algorithms:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:titlesonly:
|
||||
|
||||
Monte Carlo <mcts_tuner>
|
||||
Cross-entropy <cem_tuner>
|
||||
|
370
gomill/docs/competitions.rst
Normal file
370
gomill/docs/competitions.rst
Normal file
@ -0,0 +1,370 @@
|
||||
.. _running competitions:
|
||||
|
||||
Running competitions
|
||||
--------------------
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
Pairings
|
||||
^^^^^^^^
|
||||
|
||||
When a competition is run, the ringmaster will launch one or more games
|
||||
between pairs of players.
|
||||
|
||||
For playoff tournaments, the pairings are determined by the
|
||||
:pl-setting-cls:`Matchup` descriptions in the control file. If more than one
|
||||
matchup is specified, the ringmaster prefers to start games from the matchup
|
||||
which has played fewest games.
|
||||
|
||||
For all-play-all tournaments, the ringmaster will again prefer the pair of
|
||||
:aa-setting:`competitors` which has played the fewest games.
|
||||
|
||||
For tuning events, the pairings are specified by a tuning algorithm.
|
||||
|
||||
|
||||
.. _simultaneous games:
|
||||
|
||||
Simultaneous games
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ringmaster can run more than one game at a time, if the
|
||||
:option:`--parallel <ringmaster --parallel>` command line option is specified.
|
||||
|
||||
This can be useful to keep processor cores busy, or if the actual playing
|
||||
programs are running on different machines to the ringmaster.
|
||||
|
||||
Normally it makes no difference whether the ringmaster starts games in
|
||||
sequence or in parallel, but it does have an effect on the :doc:`Monte Carlo
|
||||
tuner <mcts_tuner>`, as in parallel mode it will have less information each
|
||||
time it chooses a candidate player.
|
||||
|
||||
.. tip:: Even if an engine is capable of using multiple threads, it may be
|
||||
better to use a single-threaded configuration during development to get
|
||||
reproducible results, or to be sure that system load does not affect play.
|
||||
|
||||
.. tip:: When deciding how many games to run in parallel, remember to take
|
||||
into account the amount of memory needed, as well as the number of
|
||||
processor cores available.
|
||||
|
||||
|
||||
.. _live_display:
|
||||
|
||||
Display
|
||||
^^^^^^^
|
||||
|
||||
While the competition runs, the ringmaster displays a summary of the
|
||||
tournament results (or of the tuning algorithm status), a list of games in
|
||||
progress, and a list of recent game results. For example, in a playoff
|
||||
tournament with a single matchup::
|
||||
|
||||
2 games in progress: 0_2 0_4
|
||||
(Ctrl-X to halt gracefully)
|
||||
|
||||
gnugo-l1 v gnugo-l2 (3/5 games)
|
||||
board size: 9 komi: 7.5
|
||||
wins black white avg cpu
|
||||
gnugo-l1 2 66.67% 1 100.00% 1 50.00% 1.13
|
||||
gnugo-l2 1 33.33% 1 50.00% 0 0.00% 1.32
|
||||
2 66.67% 1 33.33%
|
||||
|
||||
= Results =
|
||||
game 0_1: gnugo-l2 beat gnugo-l1 B+8.5
|
||||
game 0_0: gnugo-l1 beat gnugo-l2 B+33.5
|
||||
game 0_3: gnugo-l1 beat gnugo-l2 W+2.5
|
||||
|
||||
Use :ref:`quiet mode <quiet mode>` to turn this display off.
|
||||
|
||||
|
||||
.. _stopping competitions:
|
||||
|
||||
Stopping competitions
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Unless interrupted, a run will continue until either the competition completes
|
||||
or the per-run limit specified by the :option:`--max-games
|
||||
<ringmaster --max-games>` command line option is reached.
|
||||
|
||||
Type :kbd:`Ctrl-X` to stop a run. The ringmaster will wait for all games in
|
||||
progress to complete, and then exit (the stop request won't be acknowledged on
|
||||
screen until the next game result comes in).
|
||||
|
||||
It's also reasonable to stop a run with :kbd:`Ctrl-C`; games in progress will
|
||||
be terminated immediately (assuming the engine processes are well-behaved).
|
||||
The partial games will be forgotten; the ringmaster will replay them as
|
||||
necessary if the competition is resumed later.
|
||||
|
||||
You can also stop a competition by running the command line :action:`stop`
|
||||
action from a shell; like :kbd:`Ctrl-X`, this will be acknowledged when the
|
||||
next game result comes in, and the ringmaster will wait for games in progress
|
||||
to complete.
|
||||
|
||||
|
||||
Running players
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The ringmaster requires the player engines to be standalone executables which
|
||||
speak :term:`GTP` version 2 on their standard input and output streams.
|
||||
|
||||
It launches the executables itself, with command line arguments and other
|
||||
environment as detailed by the :ref:`player settings <player configuration>`
|
||||
in the control file.
|
||||
|
||||
It launches a new engine subprocess for each game and closes it when the game
|
||||
is terminated.
|
||||
|
||||
.. tip:: To run a player on a different computer to the ringmaster, specify a
|
||||
suitable :program:`ssh` command line in the :setting-cls:`Player`
|
||||
definition.
|
||||
|
||||
See :ref:`engine errors` and :ref:`engine exit behaviour` for details of what
|
||||
happens if engines misbehave.
|
||||
|
||||
|
||||
.. index:: rules, ko, superko
|
||||
|
||||
.. _playing games:
|
||||
|
||||
Playing games
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The :setting:`board_size`, :setting:`komi`, :setting:`handicap`, and
|
||||
:setting:`handicap_style` game settings control the details of the game. The
|
||||
ringmaster doesn't know or care what rule variant the players are using; it's
|
||||
up to you to make sure they agree with each other.
|
||||
|
||||
Any :setting:`startup_gtp_commands` configured for a player will be sent
|
||||
before the :gtp:`!boardsize` and :gtp:`!clear_board` commands. Failure responses
|
||||
from these commands are ignored.
|
||||
|
||||
Each game normally continues until both players pass in succession, or one
|
||||
player resigns.
|
||||
|
||||
The ringmaster rejects moves to occupied points, and moves forbidden by
|
||||
:term:`simple ko`, as illegal. It doesn't reject self-capture moves, and it
|
||||
doesn't enforce any kind of :term:`superko` rule. If the ringmaster rejects a
|
||||
move, the player that tried to make it loses the game by forfeit.
|
||||
|
||||
If one of the players rejects a move as illegal (ie, with the |gtp| failure
|
||||
response ``illegal move``), the ringmaster assumes its opponent really has
|
||||
played an illegal move and so should forfeit the game (this is convenient if
|
||||
you're testing an experimental engine against an established one).
|
||||
|
||||
If one of the players returns any other |gtp| failure response (either to
|
||||
:gtp:`!genmove` or to :gtp:`!play`), or an uninterpretable response to
|
||||
:gtp:`!genmove`, it forfeits the game.
|
||||
|
||||
If the game lasts longer than the configured :setting:`move_limit`, it is
|
||||
stopped at that point, and recorded as having an unknown result (with |sgf|
|
||||
result ``Void``).
|
||||
|
||||
See also :ref:`claiming wins`.
|
||||
|
||||
.. note:: The ringmaster does not provide a game clock, and it does not
|
||||
use any of the |gtp| time handling commands. Players should normally be
|
||||
configured to use a fixed amount of computing power, independent of
|
||||
wall-clock time.
|
||||
|
||||
|
||||
.. index:: handicap compensation
|
||||
|
||||
.. _scoring:
|
||||
|
||||
Scoring
|
||||
^^^^^^^
|
||||
|
||||
The ringmaster has two scoring methods: ``players`` (which is the default),
|
||||
and ``internal``. The :setting:`scorer` game setting determines which is used.
|
||||
|
||||
When the ``players`` method is used, the players are asked to score the game
|
||||
using the |gtp| :gtp:`!final_score` command. See also the
|
||||
:setting:`is_reliable_scorer` player setting.
|
||||
|
||||
When the ``internal`` method is used, the ringmaster scores the game itself,
|
||||
area-fashion. It assumes that all stones remaining on the board at the end of
|
||||
the game are alive. It applies :setting:`komi`.
|
||||
|
||||
In handicap games, the internal scorer can also apply handicap stone
|
||||
compensation, controlled by the
|
||||
:setting:`internal_scorer_handicap_compensation` game setting: ``"full"`` (the
|
||||
default) means that White is given an additional point for each handicap
|
||||
stone, ``"short"`` means White is given an additional point for each handicap
|
||||
stone except the first, and ``"no"`` means that no handicap stone compensation
|
||||
is given.
|
||||
|
||||
|
||||
.. _claiming wins:
|
||||
|
||||
Claiming wins
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The ringmaster supports a protocol to allow players to declare that they have
|
||||
won the game. This can save time if you're testing against opponents which
|
||||
don't resign.
|
||||
|
||||
To support this, the player has to implement :gtp:`gomill-genmove_ex` and
|
||||
recognise the ``claim`` keyword.
|
||||
|
||||
You must also set :setting:`allow_claim` ``True`` in the :setting-cls:`Player`
|
||||
definition for this mechanism to be used.
|
||||
|
||||
The |sgf| result of a claimed game will simply be ``B+`` or ``W+``.
|
||||
|
||||
|
||||
.. _startup checks:
|
||||
|
||||
Startup checks
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Whenever the ringmaster starts a run, before starting any games, it launches
|
||||
an instance of each engine that will be required for the run and checks that
|
||||
it operates reasonably.
|
||||
|
||||
If any engine fails the checks, the run is cancelled. The standard error
|
||||
stream from the engines is suppressed for these automatic startup checks.
|
||||
|
||||
The :action:`check` command line action runs the same checks, but it leaves
|
||||
the engines' standard error going to the console (any
|
||||
:setting:`discard_stderr` player settings are ignored).
|
||||
|
||||
For playoff tournaments, only players listed in matchups are checked (and
|
||||
matchups with :pl-setting:`number_of_games` set to ``0`` are ignored). If a
|
||||
player appears in more than one matchup, the board size and komi from its
|
||||
first matchup are used.
|
||||
|
||||
For all-play-all tournaments, all players listed as :aa-setting:`competitors`
|
||||
are checked.
|
||||
|
||||
For tuning events, the opponent and one sample candidate are checked.
|
||||
|
||||
The checks are as follows:
|
||||
|
||||
- the engine subprocess starts, and replies to |gtp| commands
|
||||
- the engine reports |gtp| protocol version 2 (if it supports
|
||||
:gtp:`!protocol_version` at all)
|
||||
- the engine accepts any :setting:`startup_gtp_commands`
|
||||
- the engine accepts the required board size and komi
|
||||
- the engine accepts the :gtp:`!clear_board` |gtp| command
|
||||
|
||||
|
||||
.. _quiet mode:
|
||||
|
||||
.. index:: quiet mode
|
||||
|
||||
Quiet mode
|
||||
^^^^^^^^^^
|
||||
|
||||
The :option:`--quiet <ringmaster --quiet>` command line option makes the
|
||||
ringmaster run in :dfn:`quiet mode`. In this mode, it prints nothing to
|
||||
standard output, and only errors and warnings to standard error.
|
||||
|
||||
This mode is suitable for running in the background.
|
||||
|
||||
:kbd:`Ctrl-X` still works in quiet mode to stop a run gracefully, if the
|
||||
ringmaster process is in the foreground.
|
||||
|
||||
|
||||
.. _output files:
|
||||
|
||||
.. _competition directory:
|
||||
|
||||
Output files
|
||||
^^^^^^^^^^^^
|
||||
|
||||
.. index:: competition directory
|
||||
|
||||
The ringmaster writes a number of files, which it places in the directory
|
||||
which contains the control file (the :dfn:`competition directory`). The
|
||||
filename stem (the part before the filename extension) of each file is the
|
||||
same as in the control file (:file:`{code}` in the table below).
|
||||
|
||||
The full set of files that may be present in the competition directory is:
|
||||
|
||||
======================= =======================================================
|
||||
:file:`{code}.ctl` the :doc:`control file <settings>`
|
||||
:file:`{code}.status` the :ref:`competition state <competition state>` file
|
||||
:file:`{code}.log` the :ref:`event log <logging>`
|
||||
:file:`{code}.hist` the :ref:`history file <logging>`
|
||||
:file:`{code}.report` the :ref:`report file <competition report file>`
|
||||
:file:`{code}.cmd` the :ref:`remote control file <remote control file>`
|
||||
:file:`{code}.games/` |sgf| :ref:`game records <game records>`
|
||||
:file:`{code}.void/` |sgf| game records for :ref:`void games <void games>`
|
||||
:file:`{code}.gtplogs/` |gtp| logs
|
||||
(from :option:`--log-gtp <ringmaster --log-gtp>`)
|
||||
======================= =======================================================
|
||||
|
||||
The recommended filename extension for the control file is :file:`.ctl`, but
|
||||
other extensions are allowed (except those listed in the table above).
|
||||
|
||||
|
||||
.. _competition state:
|
||||
|
||||
Competition state
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. index:: state file
|
||||
|
||||
The competition :dfn:`state file` (:file:`{code}.state`) contains a
|
||||
machine-readable description of the competition's results; this allows
|
||||
resuming the competition, and also programmatically :ref:`querying the results
|
||||
<querying the results>`. It is rewritten after each game result is received,
|
||||
so that little information will be lost if the ringmaster stops ungracefully
|
||||
for any reason.
|
||||
|
||||
The :action:`reset` command line action deletes **all** competition output
|
||||
files, including game records and the state file.
|
||||
|
||||
State files written by one Gomill release may not be accepted by other
|
||||
releases. See :doc:`changes` for details.
|
||||
|
||||
.. caution:: If the ringmaster loads a state file written by a hostile party,
|
||||
it can be tricked into executing arbitrary code. On a shared system, do not
|
||||
make the competition directory or the state file world-writeable.
|
||||
|
||||
|
||||
.. index:: logging, event log, history file
|
||||
|
||||
.. _logging:
|
||||
|
||||
Logging
|
||||
^^^^^^^
|
||||
|
||||
The ringmaster writes two log files: the :dfn:`event log` (:file:`{code}.log`)
|
||||
and the :dfn:`history file` (:file:`{code}.hist`).
|
||||
|
||||
The event log has entries for competition runs starting and finishing and for
|
||||
games starting and finishing, including details of errors from games which
|
||||
fail. It may also include output from the players' :ref:`standard error
|
||||
streams <standard error>`, depending on the :setting:`stderr_to_log` setting.
|
||||
|
||||
The history file has entries for game results, and in tuning events it
|
||||
may have periodic descriptions of the tuner status.
|
||||
|
||||
Also, if the :option:`--log-gtp <ringmaster --log-gtp>` command line option is
|
||||
passed, the ringmaster logs all |gtp| commands and responses. It writes a
|
||||
separate log file for each game, in the :file:`{code}.gtplogs` directory.
|
||||
|
||||
|
||||
.. _standard error:
|
||||
|
||||
Players' standard error
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
By default, the players' standard error streams are sent to the ringmaster's
|
||||
:ref:`event log <logging>`. All players write to the same log, so there's no
|
||||
direct indication of which messages came from which player (the log entries
|
||||
for games starting and completing may help).
|
||||
|
||||
If the competition setting :setting:`stderr_to_log` is False, the players'
|
||||
standard error streams are left unchanged from the ringmaster's. This is only
|
||||
useful in :ref:`quiet mode <quiet mode>`, or if you redirect the ringmaster's
|
||||
standard error.
|
||||
|
||||
You can send standard error for a particular player to :file:`/dev/null` using
|
||||
the player setting :setting:`discard_stderr`. This can be used for players
|
||||
which like to send copious diagnostics to stderr, but if possible it is better
|
||||
to configure the player not to do that, so that any real error messages aren't
|
||||
hidden (eg with a command line option like ``fuego --quiet``).
|
||||
|
124
gomill/docs/conf.py
Normal file
124
gomill/docs/conf.py
Normal file
@ -0,0 +1,124 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
needs_sphinx = '1.0'
|
||||
extensions = ['sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.viewcode']
|
||||
templates_path = ['_templates']
|
||||
source_suffix = '.rst'
|
||||
source_encoding = 'utf-8'
|
||||
master_doc = 'index'
|
||||
project = u'gomill'
|
||||
copyright = u'2009-2011, Matthew Woodcraft'
|
||||
version = '0.7.2'
|
||||
release = '0.7.2'
|
||||
unused_docs = []
|
||||
exclude_dirnames = ['.git']
|
||||
pygments_style = 'vs'
|
||||
modindex_common_prefix = ['gomill.']
|
||||
|
||||
html_theme = 'default'
|
||||
html_theme_options = {
|
||||
'nosidebar' : False,
|
||||
#'rightsidebar' : True,
|
||||
'stickysidebar' : False,
|
||||
|
||||
'footerbgcolor' : '#3d3011',
|
||||
#'footertextcolor' : ,
|
||||
'sidebarbgcolor' : '#3d3011',
|
||||
#'sidebartextcolor' : ,
|
||||
'sidebarlinkcolor' : '#d8d898',
|
||||
'relbarbgcolor' : '#523f13',
|
||||
#'relbartextcolor' : ,
|
||||
#'relbarlinkcolor' : ,
|
||||
#'bgcolor' : ,
|
||||
#'textcolor' : ,
|
||||
'linkcolor' : '#7c5f35',
|
||||
'visitedlinkcolor' : '#7c5f35',
|
||||
#'headbgcolor' : ,
|
||||
'headtextcolor' : '#5c4320',
|
||||
#'headlinkcolor' : ,
|
||||
#'codebgcolor' : ,
|
||||
#'codetextcolor' : ,
|
||||
|
||||
'externalrefs' : True,
|
||||
}
|
||||
|
||||
html_static_path = ['_static']
|
||||
html_add_permalinks = False
|
||||
html_copy_source = False
|
||||
html_sidebars = {'**' : ['wholetoc.html', 'relations.html', 'searchbox.html']}
|
||||
html_style = "gomill.css"
|
||||
html_show_sourcelink = False
|
||||
|
||||
pngmath_use_preview = True
|
||||
|
||||
todo_include_todos = True
|
||||
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/2.7',
|
||||
'python-inv.txt')}
|
||||
|
||||
|
||||
rst_epilog = """
|
||||
.. |gtp| replace:: :abbr:`GTP (Go Text Protocol)`
|
||||
.. |sgf| replace:: :abbr:`SGF (Smart Game Format)`
|
||||
"""
|
||||
|
||||
def setup(app):
|
||||
app.add_object_type('action', 'action',
|
||||
indextemplate='pair: %s; ringmaster action',
|
||||
objname="Ringmaster action")
|
||||
|
||||
app.add_object_type('gtp', 'gtp',
|
||||
indextemplate='pair: %s; GTP command',
|
||||
objname="GTP command")
|
||||
|
||||
app.add_object_type('script', 'script',
|
||||
indextemplate='pair: %s; example script',
|
||||
objname="Example script")
|
||||
|
||||
app.add_object_type('setting', 'setting',
|
||||
indextemplate='pair: %s; control file setting',
|
||||
objname="Control file setting")
|
||||
|
||||
app.add_object_type('pl-setting', 'pl-setting',
|
||||
indextemplate='pair: %s; Playoff tournament setting',
|
||||
objname="Playoff tournament setting")
|
||||
|
||||
app.add_object_type('aa-setting', 'aa-setting',
|
||||
indextemplate='pair: %s; All-play-all tournament setting',
|
||||
objname="All-play-all tournament setting")
|
||||
|
||||
app.add_object_type('mc-setting', 'mc-setting',
|
||||
indextemplate='pair: %s; Monte Carlo tuner setting',
|
||||
objname="Monte Carlo tuner setting")
|
||||
|
||||
app.add_object_type('ce-setting', 'ce-setting',
|
||||
indextemplate='pair: %s; cross-entropy tuner setting',
|
||||
objname="Cross-entropy tuner setting")
|
||||
|
||||
app.add_crossref_type('setting-cls', 'setting-cls',
|
||||
indextemplate='single: %s',
|
||||
objname="Control file object")
|
||||
|
||||
app.add_crossref_type('pl-setting-cls', 'pl-setting-cls',
|
||||
indextemplate='single: %s',
|
||||
objname="Control file object")
|
||||
|
||||
app.add_crossref_type('mc-setting-cls', 'mc-setting-cls',
|
||||
indextemplate='single: %s',
|
||||
objname="Control file object")
|
||||
|
||||
app.add_crossref_type('ce-setting-cls', 'ce-setting-cls',
|
||||
indextemplate='single: %s',
|
||||
objname="Control file object")
|
||||
|
||||
|
||||
# Undo undesirable sphinx code that auto-adds 'xref' class to literals 'True',
|
||||
# 'False', and 'None'.
|
||||
from sphinx.writers import html as html_mod
|
||||
def visit_literal(self, node):
|
||||
self.body.append(self.starttag(node, 'tt', '',
|
||||
CLASS='docutils literal'))
|
||||
self.protect_literal_text += 1
|
||||
html_mod.HTMLTranslator.visit_literal = visit_literal
|
||||
|
13
gomill/docs/contact.rst
Normal file
13
gomill/docs/contact.rst
Normal file
@ -0,0 +1,13 @@
|
||||
Contact
|
||||
=======
|
||||
|
||||
Gomill's home page is http://mjw.woodcraft.me.uk/gomill/.
|
||||
|
||||
Updated versions will be made available for download from that site.
|
||||
|
||||
I'm happy to receive any bug reports, suggestions, patches, questions and so
|
||||
on at <matthew@woodcraft.me.uk>.
|
||||
|
||||
I'm particularly interested in hearing about any |gtp| engines (even buggy
|
||||
ones) which don't work with the ringmaster.
|
||||
|
187
gomill/docs/errors.rst
Normal file
187
gomill/docs/errors.rst
Normal file
@ -0,0 +1,187 @@
|
||||
Error handling and exceptional situations
|
||||
-----------------------------------------
|
||||
|
||||
This page contains some tedious details of the implementation; it might be of
|
||||
interest if you're wondering whether the behaviour you see is intentional or a
|
||||
bug.
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
.. _game id:
|
||||
|
||||
Game identification
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Each game played in a competition is identified using a short string (the
|
||||
:dfn:`game_id`). This is used in the |sgf| :ref:`game record <game records>`
|
||||
filename and game name (``GN``), the :ref:`log files <logging>`, the live
|
||||
display, and so on.
|
||||
|
||||
For playoff tournaments, game ids are made up from the :pl-setting:`matchup id
|
||||
<id>` and the number of the game within the matchup; for example, the first
|
||||
game played might be ``0_0`` or ``0_000`` (depending on the value of
|
||||
:pl-setting:`number_of_games`).
|
||||
|
||||
Similarly for all-play-all tournaments, game ids are like ``AvB_0``, using the
|
||||
competitor letters shown in the results grid, with the length depending on the
|
||||
:aa-setting:`rounds` setting.
|
||||
|
||||
|
||||
.. _details of scoring:
|
||||
|
||||
Details of scoring
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If :setting:`scorer` is ``"players"`` but neither engine is able to score
|
||||
(whether because :gtp:`!final_score` isn't implemented, or it fails, or
|
||||
:setting:`is_reliable_scorer` is ``False``), the game result is reported as
|
||||
unknown (|sgf| result ``?``).
|
||||
|
||||
If both engines are able to score but they disagree about the winner, the game
|
||||
result is reported as unknown. The engines' responses to :gtp:`!final_score`
|
||||
are recorded in |sgf| file comments.
|
||||
|
||||
If the engines agree about the winner but disagree about the winning margin,
|
||||
the |sgf| result is simply ``B+`` or ``W+``, and the engines' responses are
|
||||
recorded in |sgf| file comments.
|
||||
|
||||
|
||||
.. _engine errors:
|
||||
|
||||
Engine errors
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
If an engine returns a |gtp| failure response to any of the commands which set
|
||||
up the game (eg :gtp:`!boardsize` or :gtp:`!fixed_handicap`), the game is
|
||||
treated as :ref:`void <void games>`.
|
||||
|
||||
If an engine fails to start, exits unexpectedly, or produces a |gtp| response
|
||||
which is ill-formed at the protocol level, the game is treated as :ref:`void
|
||||
<void games>`.
|
||||
|
||||
As an exception, if such an error happens after the game's result has been
|
||||
established (in particular, if one player has already forfeited the game), the
|
||||
game is not treated as void.
|
||||
|
||||
|
||||
.. _engine exit behaviour:
|
||||
|
||||
Engine exit behaviour
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Before reporting the game result, the ringmaster sends :gtp:`!quit` to both
|
||||
engines, closes their input and output pipes, and waits for the subprocesses
|
||||
to exit.
|
||||
|
||||
If an engine hangs (during the game or at exit), the ringmaster will just hang
|
||||
too (or, if in parallel mode, one worker process will).
|
||||
|
||||
The exit status of engine subprocesses is ignored.
|
||||
|
||||
|
||||
.. index:: void games
|
||||
|
||||
.. _void games:
|
||||
|
||||
Void games
|
||||
^^^^^^^^^^
|
||||
|
||||
Void games are games which were not completed due to a software failure, and
|
||||
which don't count as a forfeit by either engine.
|
||||
|
||||
Void games don't appear in the competition results. They're recorded in the
|
||||
:ref:`event log <logging>`, and a warning is displayed on screen when they
|
||||
occur.
|
||||
|
||||
If :setting:`record_games` is enabled, a game record will be written for each
|
||||
void game that had at least one move played. These are placed in the
|
||||
:file:`{code}.void/` subdirectory of the competition directory.
|
||||
|
||||
A void game will normally be replayed, with the same game id (the details
|
||||
depend on the competition type; see below).
|
||||
|
||||
(Note that void games aren't the same thing as games whose |sgf| result is
|
||||
``Void``; the ringmaster uses that result for games which exceed the
|
||||
:setting:`move_limit`.)
|
||||
|
||||
|
||||
Halting competitions due to errors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A single error which causes a void game will not normally cause a competition
|
||||
to be prematurely halted, but multiple errors may.
|
||||
|
||||
The details depend on the competition type:
|
||||
|
||||
For playoff and all-play-all tournaments, a run is halted early if the first
|
||||
game in any matchup is void, or if two games in a row for the same matchup are
|
||||
void.
|
||||
|
||||
For tuning events, a run is halted immediately if the first game to finish is
|
||||
void.
|
||||
|
||||
Otherwise, in Monte Carlo tuning events a void game will be ignored: a new
|
||||
game will be scheduled from the current state of the MCTS tree (and the
|
||||
original game number will be skipped). If two game results in a row are void,
|
||||
the run will be halted.
|
||||
|
||||
In cross-entropy tuning events a void game will be replayed; if it fails
|
||||
again, the run will be halted.
|
||||
|
||||
In parallel mode, outstanding games will be allowed to complete.
|
||||
|
||||
|
||||
Preventing simultaneous runs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If :c:func:`!flock()` is available, the ringmaster will detect attempts to run
|
||||
a competition which is already running (but this probably won't work if the
|
||||
control file is on a network filesystem).
|
||||
|
||||
It's fine to use :action:`show` and :action:`report`, or the :doc:`tournament
|
||||
results API <tournament_results>`, while a competition is running.
|
||||
|
||||
|
||||
Signals and controlling terminal
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The check for :kbd:`Ctrl-X` uses the ringmaster's controlling terminal,
|
||||
independently of stdin and stdout. If there's no controlling terminal, or
|
||||
:mod:`termios` isn't available, this check is disabled.
|
||||
|
||||
The engine subprocesses are left attached to the ringmaster's controlling
|
||||
terminal, so they will receive signals from :kbd:`Ctrl-C`; unless they detach
|
||||
from their controlling terminal or ignore the signal, they should exit
|
||||
cleanly in response.
|
||||
|
||||
Running the ringmaster in the background (including using :kbd:`Ctrl-Z`)
|
||||
should work properly (you probably want :ref:`quiet mode <quiet mode>`).
|
||||
|
||||
|
||||
.. _remote control file:
|
||||
|
||||
The remote control file
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :action:`stop` action is implemented by writing a :file:`{code}.cmd` file
|
||||
to the competition directory.
|
||||
|
||||
|
||||
Character encoding
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Gomill is designed for a UTF-8 environment; it is intended to work correctly
|
||||
if non-ASCII characters provided as input are encoded in UTF-8, and to produce
|
||||
terminal and report output in UTF-8.
|
||||
|
||||
Non-ASCII characters in the control file must be encoded in UTF-8.
|
||||
|
||||
|gtp| engines may return UTF-8 characters in in response to :gtp:`!name`,
|
||||
:gtp:`!version`, :gtp:`gomill-describe_engine`, or
|
||||
:gtp:`gomill-explain_last_move`.
|
||||
|
||||
SGF files written by Gomill always explicitly specify UTF-8 encoding.
|
||||
|
104
gomill/docs/example_scripts.rst
Normal file
104
gomill/docs/example_scripts.rst
Normal file
@ -0,0 +1,104 @@
|
||||
.. _example scripts:
|
||||
|
||||
The example scripts
|
||||
===================
|
||||
|
||||
The following example scripts are available in the :file:`gomill_examples/`
|
||||
directory of the Gomill source distribution.
|
||||
|
||||
Some of them may be independently useful, as well as illustrating the library
|
||||
API.
|
||||
|
||||
See the top of each script for further information.
|
||||
|
||||
See :ref:`running the example scripts <running the example scripts>` for notes
|
||||
on making the :mod:`!gomill` package available for use with the example
|
||||
scripts.
|
||||
|
||||
|
||||
.. script:: show_sgf.py
|
||||
|
||||
Prints an ASCII diagram of the position from an |sgf| file.
|
||||
|
||||
This demonstrates the :mod:`~gomill.sgf`, :mod:`~gomill.sgf_moves`, and
|
||||
:mod:`~gomill.ascii_boards` modules.
|
||||
|
||||
|
||||
.. script:: split_sgf_collection.py
|
||||
|
||||
Splits a file containing an |sgf| game collection into multiple files.
|
||||
|
||||
This demonstrates the parsing functions from the :mod:`!sgf_grammar` module.
|
||||
|
||||
|
||||
.. script:: twogtp
|
||||
|
||||
A 'traditional' twogtp implementation.
|
||||
|
||||
This demonstrates the :mod:`!gtp_games` module.
|
||||
|
||||
|
||||
.. script:: find_forfeits.py
|
||||
|
||||
Finds the forfeited games from a playoff or all-play-all tournament.
|
||||
|
||||
This demonstrates the :doc:`tournament results API <tournament_results>`.
|
||||
|
||||
|
||||
.. script:: gtp_test_player
|
||||
|
||||
A |gtp| engine intended for testing |gtp| controllers.
|
||||
|
||||
This demonstrates the low-level engine-side |gtp| code (the
|
||||
:mod:`!gtp_engine` module).
|
||||
|
||||
|
||||
.. script:: gtp_stateful_player
|
||||
|
||||
A |gtp| engine which maintains the board position.
|
||||
|
||||
This demonstrates the :mod:`!gtp_states` module, which can be used to make a
|
||||
|gtp| engine from a stateless move-generating program, or to add commands
|
||||
like :gtp:`!undo` and :gtp:`!loadsgf` to an engine which doesn't natively
|
||||
support them.
|
||||
|
||||
|
||||
.. script:: kgs_proxy.py
|
||||
|
||||
A |gtp| engine proxy intended for use with `kgsGtp`_. This produces game
|
||||
records including the engine's commentary, if the engine supports
|
||||
:gtp:`gomill-savesgf`.
|
||||
|
||||
.. _`kgsGtp`: http://senseis.xmp.net/?KgsGtp
|
||||
|
||||
This demonstrates the :mod:`!gtp_proxy` module, and may be independently
|
||||
useful.
|
||||
|
||||
|
||||
.. script:: mogo_wrapper.py
|
||||
|
||||
A |gtp| engine proxy intended for use with `Mogo`_. This can be used to run
|
||||
Mogo with a |gtp| controller (eg `Quarry`_) which doesn't get on with Mogo's
|
||||
|gtp| implementation.
|
||||
|
||||
.. _`Mogo`: http://www.lri.fr/~gelly/MoGo_Download.htm
|
||||
.. _`Quarry`: http://home.gna.org/quarry/
|
||||
|
||||
This demonstrates the :mod:`!gtp_proxy` module, and may be independently
|
||||
useful.
|
||||
|
||||
|
||||
.. script:: gomill-clop
|
||||
|
||||
An experimental script for using Gomill as a back end for Rémi Coulom's CLOP
|
||||
optimisation system. It has been tested with ``CLOP-0.0.8``, which can be
|
||||
downloaded from http://remi.coulom.free.fr/CLOP/ .
|
||||
|
||||
To use it, write a control file based on :file:`clop_example.ctl` in the
|
||||
:file:`gomill_examples/` directory, and run ::
|
||||
|
||||
$ gomill-clop <control file> setup
|
||||
|
||||
That will create a :samp:`.clop` file in the same directory as the control
|
||||
file, which you can then run using :samp:`clop-gui`.
|
||||
|
116
gomill/docs/glossary.rst
Normal file
116
gomill/docs/glossary.rst
Normal file
@ -0,0 +1,116 @@
|
||||
Glossary
|
||||
========
|
||||
|
||||
.. glossary::
|
||||
|
||||
GTP
|
||||
The Go Text Protocol
|
||||
|
||||
A communication protocol used to control Go-playing programs. Gomill
|
||||
uses only GTP version 2, which is specified at
|
||||
http://www.lysator.liu.se/~gunnar/gtp/gtp2-spec-draft2/gtp2-spec.html.
|
||||
|
||||
(As of August 2011, the specification describes itself as a draft, but it
|
||||
has remained stable for several years and is widely implemented.)
|
||||
|
||||
|
||||
SGF
|
||||
The Smart Game Format
|
||||
|
||||
A text-based file format used for storing Go game records.
|
||||
|
||||
Gomill uses version FF[4], which is specified at
|
||||
http://www.red-bean.com/sgf/index.html.
|
||||
|
||||
|
||||
jigo
|
||||
A tied game (after komi is taken into account).
|
||||
|
||||
|
||||
komi
|
||||
Additional points awarded to White in final scoring.
|
||||
|
||||
|
||||
simple ko
|
||||
A Go rule prohibiting repetition of the immediately-preceding position.
|
||||
|
||||
|
||||
superko
|
||||
A Go rule prohibiting repetition of preceding positions.
|
||||
|
||||
There are several possible variants of the superko rule. Gomill does not
|
||||
enforce any of them.
|
||||
|
||||
|
||||
pondering
|
||||
A feature implemented by some Go programs: thinking while it is their
|
||||
opponent's turn to move.
|
||||
|
||||
|
||||
controller
|
||||
A program implementing the 'referee' side of the |gtp| protocol.
|
||||
|
||||
The |gtp| protocol can be seen as a client-server protocol, with the
|
||||
controller as the client.
|
||||
|
||||
|
||||
engine
|
||||
A program implementing the 'playing' side of the |gtp| protocol.
|
||||
|
||||
The |gtp| protocol can be seen as a client-server protocol, with the
|
||||
engine as the server.
|
||||
|
||||
|
||||
player
|
||||
A |gtp| engine, together with a particular configuration.
|
||||
|
||||
|
||||
competition
|
||||
An 'event' consisting of multiple games managed by the Gomill ringmaster
|
||||
(either a tournament or a tuning event).
|
||||
|
||||
tournament
|
||||
A competition in which the ringmaster plays games between predefined
|
||||
players, to compare their strengths.
|
||||
|
||||
playoff
|
||||
A tournament comprising many games played between fixed pairings of
|
||||
players.
|
||||
|
||||
all-play-all
|
||||
A tournament in which games are played between all pairings from a list of
|
||||
players.
|
||||
|
||||
|
||||
matchup
|
||||
A pairing of players in a tournament, together with its settings (board
|
||||
size, komi, handicap, and so on)
|
||||
|
||||
|
||||
tuning event
|
||||
A competition in which the ringmaster runs an algorithm which adjusts
|
||||
player parameters to try to find the values which give strongest play.
|
||||
|
||||
|
||||
Bandit problem
|
||||
A problem in which an agent has to repeatedly choose between actions whose
|
||||
value is initially unknown, trading off time spent on the action with the
|
||||
best estimated value against time spent evaluating other actions.
|
||||
|
||||
See http://en.wikipedia.org/wiki/Multi-armed_bandit
|
||||
|
||||
|
||||
UCB
|
||||
Upper Confidence Bound algorithms
|
||||
|
||||
A family of algorithms for addressing bandit problems.
|
||||
|
||||
|
||||
UCT
|
||||
Upper Confidence bounds applied to Trees.
|
||||
|
||||
A variant of UCB for bandit problems in which the actions are arranged in
|
||||
the form of a tree.
|
||||
|
||||
See http://senseis.xmp.net/?UCT.
|
||||
|
79
gomill/docs/gomill_package.rst
Normal file
79
gomill/docs/gomill_package.rst
Normal file
@ -0,0 +1,79 @@
|
||||
The :mod:`gomill` package
|
||||
-------------------------
|
||||
|
||||
All Gomill code is contained in modules under the :mod:`!gomill` package.
|
||||
|
||||
The package includes both the 'toolkit' (Go board, |sgf|, and |gtp|) code, and
|
||||
the code implementing the ringmaster.
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
Package module contents
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The package module itself defines only a single constant:
|
||||
|
||||
.. module:: gomill
|
||||
:synopsis: Tools for testing and tuning Go-playing programs.
|
||||
|
||||
.. data:: __version__
|
||||
|
||||
The library version, as a string (like ``"0.7"``).
|
||||
|
||||
.. versionadded:: 0.7
|
||||
|
||||
|
||||
Generic data representation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Unless otherwise stated, string values are 8-bit UTF-8 strings.
|
||||
|
||||
|
||||
.. _go_related_data_representation:
|
||||
|
||||
Go-related data representation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Gomill represents Go colours and moves internally as follows:
|
||||
|
||||
======== ===========================================
|
||||
Name Possible values
|
||||
======== ===========================================
|
||||
*colour* single-character string: ``'b'`` or ``'w'``
|
||||
*point* pair (*int*, *int*) of coordinates
|
||||
*move* *point* or ``None`` (for a pass)
|
||||
======== ===========================================
|
||||
|
||||
The terms *colour*, *point*, and *move* are used as above throughout this
|
||||
library documentation (in particular, when describing parameters and return
|
||||
types).
|
||||
|
||||
*colour* values are used to represent players, as well as stones on the board.
|
||||
(When a way to represent an empty point is needed, ``None`` is used.)
|
||||
|
||||
*point* values are treated as (row, column). The bottom left is ``(0, 0)``
|
||||
(the same orientation as |gtp|, but not |sgf|). So the coordinates for a 9x9
|
||||
board are as follows::
|
||||
|
||||
9 (8,0) . . . . . (8,8)
|
||||
8 . . . . . . . . .
|
||||
7 . . . . . . . . .
|
||||
6 . . . . . . . . .
|
||||
5 . . . . . . . . .
|
||||
4 . . . . . . . . .
|
||||
3 . . . . . . . . .
|
||||
2 . . . . . . . . .
|
||||
1 (0,0) . . . . . (0,8)
|
||||
A B C D E F G H J
|
||||
|
||||
There are functions in the :mod:`~gomill.common` module to convert between
|
||||
these coordinates and the conventional (``T19``\ -style) notation.
|
||||
|
||||
Gomill is designed to work with square boards, up to 25x25 (which is the upper
|
||||
limit of the conventional notation, and the upper limit for |gtp|). Some parts
|
||||
of the library can work with larger board sizes; these cases are documented
|
||||
explicitly.
|
||||
|
133
gomill/docs/gtp_extensions.rst
Normal file
133
gomill/docs/gtp_extensions.rst
Normal file
@ -0,0 +1,133 @@
|
||||
GTP extensions
|
||||
==============
|
||||
|
||||
Gomill supports a number of |gtp| extension commands. These are all named with
|
||||
a ``gomill-`` prefix.
|
||||
|
||||
|
||||
The extensions used by the ringmaster are as follows:
|
||||
|
||||
.. gtp:: gomill-explain_last_move
|
||||
|
||||
Arguments: none
|
||||
|
||||
Return a string containing the engine's comments about the last move it
|
||||
generated.
|
||||
|
||||
This might include the engine's estimate of its winning chances, a principal
|
||||
variation, or any other diagnostic information.
|
||||
|
||||
The intention is that |gtp| controllers which produce game records should
|
||||
use this command to write a comment associated with the move.
|
||||
|
||||
Any non-ASCII characters in the response should be encoded as UTF-8.
|
||||
|
||||
If no information is available, return an empty string.
|
||||
|
||||
The behaviour of this command is unspecified if a command changing the board
|
||||
state (eg :gtp:`!play` or :gtp:`!undo`) has occurred since the engine last
|
||||
generated a move.
|
||||
|
||||
|
||||
.. gtp:: gomill-describe_engine
|
||||
|
||||
Arguments: none
|
||||
|
||||
Return a string with a description of the engine's configuration. This
|
||||
should repeat the information from the :gtp:`!name` and :gtp:`!version`
|
||||
commands. Controllers should expect the response to take multiple lines.
|
||||
|
||||
The intention is that |gtp| controllers which produce game records should
|
||||
use the output of this command as part of a comment for the game as a whole.
|
||||
|
||||
If possible, the response should include a description of all engine
|
||||
parameters which affect gameplay. If the engine plays reproducibly given the
|
||||
seed of a random number generator, the response should include that seed.
|
||||
|
||||
Any non-ASCII characters in the response should be encoded as UTF-8.
|
||||
|
||||
|
||||
.. gtp:: gomill-cpu_time
|
||||
|
||||
Arguments: none
|
||||
|
||||
Return a float (represented in decimal) giving the amount of CPU time the
|
||||
engine has used to generate all moves made so far (in seconds).
|
||||
|
||||
For engines which use multiple threads or processes, this should be the
|
||||
total time used on all CPUs.
|
||||
|
||||
It may not be possible to meaningfully respond to this command (for example,
|
||||
if an engine runs on multiple processors which run at different speeds); in
|
||||
complex cases, the engine should document how the CPU time is calculated.
|
||||
|
||||
|
||||
.. gtp:: gomill-genmove_ex
|
||||
|
||||
Arguments: colour, list of keywords
|
||||
|
||||
This is a variant of the standard :gtp:`!genmove` command. Each keyword
|
||||
indicates a permitted (or desired) variation of behaviour. For example::
|
||||
|
||||
gomill-genmove_ex b claim
|
||||
|
||||
If :gtp:`!gomill-genmove_ex` is sent without any arguments (ie, no colour is
|
||||
specified), the engine should return a list of the keywords it supports (one
|
||||
per line, like :gtp:`!list_commands`).
|
||||
|
||||
Engines must ignore keywords they do not support. :gtp:`!gomill-genmove_ex`
|
||||
with no keywords is exactly equivalent to :gtp:`!genmove`.
|
||||
|
||||
The following keywords are currently defined:
|
||||
|
||||
``claim``
|
||||
In addition to the usual responses to :gtp:`!genmove`, the engine may also
|
||||
return ``claim``, which indicates that the engine believes it is certain
|
||||
to win the game (the engine must not assume that the controller will act
|
||||
on this claim).
|
||||
|
||||
|
||||
There is also an extension which is not used by the ringmaster:
|
||||
|
||||
.. gtp:: gomill-savesgf
|
||||
|
||||
Arguments: filename, list of |sgf| properties
|
||||
|
||||
Write an |sgf| game record of the current game.
|
||||
|
||||
See the :term:`GTP` specification's description of :gtp:`!loadsgf` for the
|
||||
interpretation of the ``filename`` argument.
|
||||
|
||||
The |sgf| properties should be specified in the form
|
||||
:samp:`{PropIdent}={PropValue}`, eg ``RE=W+3.5``. Escape spaces in values
|
||||
with ``\_``, backslashes with ``\\``. Encode non-ASCII characters in UTF-8.
|
||||
|
||||
These |sgf| properties should be added to the root node. The engine should
|
||||
fill in any properties it can (at least ``AP``, ``SZ``, ``KM``, ``HA``, and
|
||||
``DT``). Explicitly-specified properties should override the engine's
|
||||
defaults.
|
||||
|
||||
The intention is that engines which have 'comments' about their moves (as
|
||||
for :gtp:`gomill-explain_last_move`) should include them in the game record.
|
||||
|
||||
Example::
|
||||
|
||||
gomill-savesgf xxx.sgf PB=testplayer PW=GNU\_Go:3.8 RE=W+3.5
|
||||
|
||||
.. note::
|
||||
|
||||
|gtp| engines aren't typically well placed to write game records, as they
|
||||
don't have enough information to write the game metadata properly (this is
|
||||
why :gtp:`!gomill-savesgf` has to take the |sgf| properties explicitly).
|
||||
It's usually better for the controller to do it. See the
|
||||
:script:`kgs_proxy.py` example script for an example of when this command
|
||||
might be useful.
|
||||
|
||||
|
||||
The :gtp:`gomill-explain_last_move`, :gtp:`gomill-genmove_ex`, and
|
||||
:gtp:`gomill-savesgf` commands are supported by the Gomill :mod:`!gtp_states`
|
||||
module.
|
||||
|
||||
.. The other extension is gomill-passthrough (used by proxies), but I don't
|
||||
think it makes sense to document it as a generic extension
|
||||
|
36
gomill/docs/handicap_layout.rst
Normal file
36
gomill/docs/handicap_layout.rst
Normal file
@ -0,0 +1,36 @@
|
||||
The :mod:`~gomill.handicap_layout` module
|
||||
-----------------------------------------
|
||||
|
||||
.. module:: gomill.handicap_layout
|
||||
:synopsis: Standard layout of fixed handicap stones.
|
||||
|
||||
The :mod:`!gomill.handicap_layout` module describes the standard layout used
|
||||
for fixed handicap stones. It follows the rules from the :term:`GTP`
|
||||
specification.
|
||||
|
||||
|
||||
.. function:: handicap_points(number_of_stones, board_size)
|
||||
|
||||
:rtype: list of *points*
|
||||
|
||||
Returns the handicap points for a given number of stones and board size.
|
||||
|
||||
Raises :exc:`ValueError` if there isn't a standard placement pattern for
|
||||
the specified number of handicap stones and board size.
|
||||
|
||||
The result's length is always exactly *number_of_stones*.
|
||||
|
||||
.. function:: max_fixed_handicap_for_board_size(board_size)
|
||||
|
||||
:rtype: int
|
||||
|
||||
Returns the maximum number of stones permitted for the |gtp|
|
||||
:gtp:`!fixed_handicap` command, given the specified board size.
|
||||
|
||||
.. function:: max_free_handicap_for_board_size(board_size)
|
||||
|
||||
:rtype: int
|
||||
|
||||
Returns the maximum number of stones permitted for the |gtp|
|
||||
:gtp:`!place_free_handicap` command, given the specified board size.
|
||||
|
24
gomill/docs/index.rst
Normal file
24
gomill/docs/index.rst
Normal file
@ -0,0 +1,24 @@
|
||||
******
|
||||
Gomill
|
||||
******
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:titlesonly:
|
||||
|
||||
intro
|
||||
ringmaster
|
||||
gtp_extensions
|
||||
library
|
||||
example_scripts
|
||||
install
|
||||
contact
|
||||
changes
|
||||
licence
|
||||
glossary
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
||||
.. todolist::
|
152
gomill/docs/install.rst
Normal file
152
gomill/docs/install.rst
Normal file
@ -0,0 +1,152 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Gomill requires Python 2.5, 2.6, or 2.7.
|
||||
|
||||
For Python 2.5 only, the :option:`--parallel <ringmaster --parallel>` feature
|
||||
requires the external `multiprocessing`__ package.
|
||||
|
||||
.. __: http://pypi.python.org/pypi/multiprocessing
|
||||
|
||||
Gomill is intended to run on any modern Unix-like system.
|
||||
|
||||
|
||||
Obtaining Gomill
|
||||
----------------
|
||||
|
||||
Gomill is distributed as a pure-Python source archive,
|
||||
:file:`gomill-{version}.tar.gz`. The most recent version can be obtained from
|
||||
http://mjw.woodcraft.me.uk/gomill/.
|
||||
|
||||
This documentation is distributed separately as
|
||||
:file:`gomill-doc-{version}.tar.gz`.
|
||||
|
||||
Once you have downloaded the source archive, extract it using a command like
|
||||
:samp:`tar -xzf gomill-{version}.tar.gz`. This will create a directory named
|
||||
:file:`gomill-{version}`, referred to below as the :dfn:`distribution
|
||||
directory`.
|
||||
|
||||
Alternatively, you can access releases using Git::
|
||||
|
||||
git clone http://mjw.woodcraft.me.uk/gomill/git/ gomill
|
||||
|
||||
which would create :file:`gomill` as the distribution directory.
|
||||
|
||||
|
||||
|
||||
Running the ringmaster
|
||||
----------------------
|
||||
|
||||
The ringmaster executable in the distribution directory can be run directly
|
||||
without any further installation; it will use the copy of the :mod:`!gomill`
|
||||
package in the distribution directory.
|
||||
|
||||
A symbolic link to the ringmaster executable will also work, but if you move
|
||||
the executable elsewhere it will not be able to find the :mod:`!gomill`
|
||||
package unless the package is installed.
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
Installing Gomill puts the :mod:`!gomill` package onto the Python module
|
||||
search path, and the ringmaster executable onto the executable
|
||||
:envvar:`!PATH`.
|
||||
|
||||
To install, first change to the distribution directory, then:
|
||||
|
||||
- to install for the system as a whole, run (as a sufficiently privileged
|
||||
user) ::
|
||||
|
||||
python setup.py install
|
||||
|
||||
|
||||
- to install for the current user only (Python 2.6 or 2.7), run ::
|
||||
|
||||
python setup.py install --user
|
||||
|
||||
(in this case the ringmaster executable will be placed in
|
||||
:file:`~/.local/bin`.)
|
||||
|
||||
Pass :option:`!--dry-run` to see what these will do. See
|
||||
http://docs.python.org/2.7/install/ for more information.
|
||||
|
||||
|
||||
Uninstalling
|
||||
------------
|
||||
|
||||
To remove an installed version of Gomill, run ::
|
||||
|
||||
python setup.py uninstall
|
||||
|
||||
(This uses the Python module search path and the executable :envvar:`!PATH` to
|
||||
find the files to remove; pass :option:`!--dry-run` to see what it will do.)
|
||||
|
||||
|
||||
|
||||
Running the test suite
|
||||
----------------------
|
||||
|
||||
To run the testsuite against the distributed :mod:`!gomill` package, change to
|
||||
the distribution directory and run ::
|
||||
|
||||
python -m gomill_tests.run_gomill_testsuite
|
||||
|
||||
|
||||
To run the testsuite against an installed :mod:`!gomill` package, change to
|
||||
the distribution directory and run ::
|
||||
|
||||
python test_installed_gomill.py
|
||||
|
||||
|
||||
With Python versions earlier than 2.7, the unittest2__ library is required
|
||||
to run the testsuite.
|
||||
|
||||
.. __: http://pypi.python.org/pypi/unittest2/
|
||||
|
||||
|
||||
.. _running the example scripts:
|
||||
|
||||
Running the example scripts
|
||||
---------------------------
|
||||
|
||||
To run the example scripts, it is simplest to install the :mod:`!gomill`
|
||||
package first.
|
||||
|
||||
If you do not wish to do so, you can run ::
|
||||
|
||||
export PYTHONPATH=<path to the distribution directory>
|
||||
|
||||
so that the example scripts will be able to find the :mod:`!gomill` package.
|
||||
|
||||
|
||||
|
||||
Building the documentation
|
||||
--------------------------
|
||||
|
||||
The sources for this HTML documentation are included in the Gomill source
|
||||
archive. To rebuild the documentation, change to the distribution directory
|
||||
and run ::
|
||||
|
||||
python setup.py build_sphinx
|
||||
|
||||
The documentation will be generated in :file:`build/sphinx/html`.
|
||||
|
||||
Requirements:
|
||||
|
||||
- Sphinx__ version 1.0 or later (at least 1.0.4 recommended)
|
||||
- LaTeX__
|
||||
- dvipng__
|
||||
|
||||
.. __: http://sphinx.pocoo.org/
|
||||
.. __: http://www.latex-project.org/
|
||||
.. __: http://www.nongnu.org/dvipng/
|
||||
|
97
gomill/docs/intro.rst
Normal file
97
gomill/docs/intro.rst
Normal file
@ -0,0 +1,97 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
Gomill is a suite of tools, and a Python library, for use in developing and
|
||||
testing Go-playing programs. It is based around the Go Text Protocol
|
||||
(:term:`GTP`) and the Smart Game Format (:term:`SGF`).
|
||||
|
||||
The principal tool is the :dfn:`ringmaster`, which plays programs against each
|
||||
other and keeps track of the results.
|
||||
|
||||
Ringmaster features include:
|
||||
|
||||
- testing multiple pairings in one run
|
||||
- playing multiple games in parallel
|
||||
- displaying live results
|
||||
- engine configuration by command line options or |gtp| commands
|
||||
- a protocol for including per-move engine diagnostics in |sgf| output
|
||||
- automatically tuning engine parameters based on game results
|
||||
(**experimental**)
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
Ringmaster example
|
||||
------------------
|
||||
|
||||
Create a file called :file:`demo.ctl`, with the following contents::
|
||||
|
||||
competition_type = 'playoff'
|
||||
|
||||
board_size = 9
|
||||
komi = 7.5
|
||||
|
||||
players = {
|
||||
'gnugo-l1' : Player('gnugo --mode=gtp --level=1'),
|
||||
'gnugo-l2' : Player('gnugo --mode=gtp --level=2'),
|
||||
}
|
||||
|
||||
matchups = [
|
||||
Matchup('gnugo-l1', 'gnugo-l2',
|
||||
alternating=True,
|
||||
number_of_games=5),
|
||||
]
|
||||
|
||||
(If you don't have :program:`gnugo` installed, change the
|
||||
:setting-cls:`Player` definitions to use a command line for whatever |gtp|
|
||||
engine you have available.)
|
||||
|
||||
Then run ::
|
||||
|
||||
$ ringmaster demo.ctl
|
||||
|
||||
The ringmaster will run five games between the two players, showing a summary
|
||||
of the results on screen, and then exit.
|
||||
|
||||
(If the ringmaster is not already installed, see :doc:`install` for
|
||||
instructions.)
|
||||
|
||||
The final display should be something like this::
|
||||
|
||||
gnugo-l1 v gnugo-l2 (5/5 games)
|
||||
board size: 9 komi: 7.5
|
||||
wins black white avg cpu
|
||||
gnugo-l1 2 40.00% 1 33.33% 1 50.00% 1.05
|
||||
gnugo-l2 3 60.00% 1 50.00% 2 66.67% 1.12
|
||||
2 40.00% 3 60.00%
|
||||
|
||||
= Results =
|
||||
game 0_0: gnugo-l2 beat gnugo-l1 W+21.5
|
||||
game 0_1: gnugo-l2 beat gnugo-l1 B+9.5
|
||||
game 0_2: gnugo-l2 beat gnugo-l1 W+14.5
|
||||
game 0_3: gnugo-l1 beat gnugo-l2 W+7.5
|
||||
game 0_4: gnugo-l1 beat gnugo-l2 B+2.5
|
||||
|
||||
The ringmaster will create several files named like :file:`demo.{xxx}` in the
|
||||
same directory as :file:`demo.ctl`, including a :file:`demo.sgf` directory
|
||||
containing game records.
|
||||
|
||||
|
||||
The Python library
|
||||
------------------
|
||||
|
||||
Gomill also provides a Python library for working with |gtp| and |sgf|, though
|
||||
as of Gomill |version| only part of the API is stable. See :doc:`library` for
|
||||
details.
|
||||
|
||||
|
||||
The example scripts
|
||||
-------------------
|
||||
|
||||
Some :doc:`example scripts <example_scripts>` are also included in the Gomill
|
||||
distribution, as illustrations of the library interface and in some cases as
|
||||
tools useful in themselves.
|
||||
|
||||
|
32
gomill/docs/library.rst
Normal file
32
gomill/docs/library.rst
Normal file
@ -0,0 +1,32 @@
|
||||
The Gomill library
|
||||
==================
|
||||
|
||||
Gomill is intended to be useful as a Python library for developing |gtp|- and
|
||||
|sgf|-based tools.
|
||||
|
||||
As of Gomill |version|, not all of the library API is formally documented.
|
||||
Only the parts which are described in this documentation should be considered
|
||||
stable public interfaces.
|
||||
|
||||
Nonetheless, the source files for the remaining modules contain fairly
|
||||
detailed documentation, and the :doc:`example scripts <example_scripts>`
|
||||
illustrate how some of them can be used.
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:titlesonly:
|
||||
|
||||
library_overview
|
||||
gomill_package
|
||||
common
|
||||
boards
|
||||
ascii_boards
|
||||
handicap_layout
|
||||
sgf
|
||||
tournament_results
|
||||
|
74
gomill/docs/library_overview.rst
Normal file
74
gomill/docs/library_overview.rst
Normal file
@ -0,0 +1,74 @@
|
||||
Library overview
|
||||
----------------
|
||||
|
||||
The :mod:`gomill` package includes the following modules:
|
||||
|
||||
.. the descriptions here should normally match the module :synopsis:, and
|
||||
therefore the module index.
|
||||
|
||||
========================================= ========================================================================
|
||||
Generic support code
|
||||
========================================= ========================================================================
|
||||
:mod:`~!gomill.utils`
|
||||
:mod:`~!gomill.compact_tracebacks`
|
||||
:mod:`~!gomill.ascii_tables`
|
||||
:mod:`~!gomill.job_manager`
|
||||
:mod:`~!gomill.settings`
|
||||
========================================= ========================================================================
|
||||
|
||||
========================================= ========================================================================
|
||||
Go-related support code
|
||||
========================================= ========================================================================
|
||||
:mod:`~gomill.common` Go-related utility functions.
|
||||
:mod:`~gomill.boards` Go board representation.
|
||||
:mod:`~gomill.ascii_boards` ASCII Go board diagrams.
|
||||
:mod:`~gomill.handicap_layout` Standard layout of fixed handicap stones.
|
||||
========================================= ========================================================================
|
||||
|
||||
========================================= ========================================================================
|
||||
|sgf| support
|
||||
========================================= ========================================================================
|
||||
:mod:`~!gomill.sgf_grammar`
|
||||
:mod:`~!gomill.sgf_properties`
|
||||
:mod:`~gomill.sgf` High level |sgf| interface.
|
||||
:mod:`~gomill.sgf_moves` Higher-level processing of moves and positions from |sgf| games
|
||||
========================================= ========================================================================
|
||||
|
||||
========================================= ========================================================================
|
||||
|gtp| controller side
|
||||
========================================= ========================================================================
|
||||
:mod:`~!gomill.gtp_controller`
|
||||
:mod:`~!gomill.gtp_games`
|
||||
========================================= ========================================================================
|
||||
|
||||
========================================= ========================================================================
|
||||
|gtp| engine side
|
||||
========================================= ========================================================================
|
||||
:mod:`~!gomill.gtp_engine`
|
||||
:mod:`~!gomill.gtp_states`
|
||||
:mod:`~!gomill.gtp_proxy`
|
||||
========================================= ========================================================================
|
||||
|
||||
========================================= ========================================================================
|
||||
Competitions
|
||||
========================================= ========================================================================
|
||||
:mod:`~!gomill.competition_schedulers`
|
||||
:mod:`~!gomill.competitions`
|
||||
:mod:`~gomill.tournament_results` Retrieving and reporting on tournament results.
|
||||
:mod:`~!gomill.tournaments`
|
||||
:mod:`~!gomill.playoffs`
|
||||
:mod:`~!gomill.allplayalls`
|
||||
:mod:`~!gomill.cem_tuners`
|
||||
:mod:`~!gomill.mcts_tuners`
|
||||
========================================= ========================================================================
|
||||
|
||||
========================================= ========================================================================
|
||||
The ringmaster
|
||||
========================================= ========================================================================
|
||||
:mod:`~!gomill.game_jobs`
|
||||
:mod:`~!gomill.terminal_input`
|
||||
:mod:`~!gomill.ringmaster_presenters`
|
||||
:mod:`~!gomill.ringmasters`
|
||||
:mod:`~!gomill.ringmaster_command_line`
|
||||
========================================= ========================================================================
|
||||
|
25
gomill/docs/licence.rst
Normal file
25
gomill/docs/licence.rst
Normal file
@ -0,0 +1,25 @@
|
||||
Licence
|
||||
=======
|
||||
|
||||
Gomill is copyright 2009-2011 Matthew Woodcraft
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
.. Note:: This is the licence commonly known as the 'MIT' Licence.
|
||||
|
646
gomill/docs/mcts_tuner.rst
Normal file
646
gomill/docs/mcts_tuner.rst
Normal file
@ -0,0 +1,646 @@
|
||||
.. index:: monte carlo tuner
|
||||
|
||||
The Monte Carlo tuner
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
:setting:`competition_type` string: ``"mc_tuner"``.
|
||||
|
||||
The Monte Carlo tuner treats the tuning event as a :term:`bandit problem`.
|
||||
That is, it attempts to find the candidate which has the highest probability
|
||||
of beating the opponent, and arranges to 'spend' more games on the candidates
|
||||
which have the highest winning percentages so far.
|
||||
|
||||
It does this using a form of the :term:`UCB` algorithm (or, optionally,
|
||||
:term:`UCT`) which is familiar to Go programmers.
|
||||
|
||||
.. caution:: As of Gomill |version|, the Monte Carlo tuner is still
|
||||
experimental. The control file settings may change in future. The reports
|
||||
aren't very good.
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
.. _mc parameter model:
|
||||
|
||||
The parameter model
|
||||
"""""""""""""""""""
|
||||
|
||||
The Monte Carlo tuner expects to work with one or more independent player
|
||||
parameters.
|
||||
|
||||
Internally, it models each parameter value as a floating point number in the
|
||||
range 0.0 to 1.0. It uses parameter values taken uniformly from this range to
|
||||
make the candidate players. Values from this range are known as
|
||||
:dfn:`optimiser parameters`.
|
||||
|
||||
In practice, engine parameters might not be floating point numbers, their
|
||||
range is unlikely to be 0.0 to 1.0, and you may wish to use a non-uniform (eg,
|
||||
logarithmic) scale for the candidates.
|
||||
|
||||
To support this, each parameter has an associated :mc-setting:`scale`. This is
|
||||
a function which maps an optimiser parameter to an :dfn:`engine parameter`
|
||||
(which can be of an arbitrary Python type). A number of :ref:`predefined
|
||||
scales <predefined scales>` are provided.
|
||||
|
||||
The candidate players are configured using these engine parameters.
|
||||
|
||||
Reports, and the live display, are also based on engine parameters; see the
|
||||
:mc-setting:`format` parameter setting.
|
||||
|
||||
|
||||
Candidates
|
||||
""""""""""
|
||||
|
||||
Each parameter also has a :mc-setting:`split` setting (a smallish integer).
|
||||
This determines how many 'samples' of the parameter range are used to make
|
||||
candidate players.
|
||||
|
||||
When there are multiple parameters, one candidate is made for each combination
|
||||
of these samples. So if there is only one parameter, the total number of
|
||||
candidates is just :mc-setting:`split`, and if there are multiple parameters,
|
||||
the total number of candidates is the product of all the :mc-setting:`split`
|
||||
settings. For example, the sample control file below creates 64 candidates.
|
||||
|
||||
.. caution:: While the Monte Carlo tuner does not impose any limit on the
|
||||
number of parameters you use, unless the games are unusually rapid it may
|
||||
be unreasonable to try to tune more than two or three parameters at once.
|
||||
|
||||
Each candidate's engine parameters are passed to the
|
||||
:mc-setting:`make_candidate` function, which returns a :setting-cls:`Player`
|
||||
definition.
|
||||
|
||||
The samples are taken by dividing the optimiser parameter range into
|
||||
:mc-setting:`split` divisions, and taking the centre of each division as the
|
||||
sample (so the end points of the range are not used). For example, if a
|
||||
parameter has a linear scale from 0.0 to 8.0, and :mc-setting:`split` is 3,
|
||||
the samples (after translation to engine parameters) will be 1.0, 4.0, and
|
||||
7.0.
|
||||
|
||||
|
||||
.. _the mcts tuning algorithm:
|
||||
|
||||
The tuning algorithm
|
||||
""""""""""""""""""""
|
||||
|
||||
Each time the tuner starts a new game, it chooses the candidate which gives
|
||||
the highest value to the following formula:
|
||||
|
||||
.. math:: w_c/g_c + E \sqrt(log(g_p) / g_c)
|
||||
|
||||
where
|
||||
|
||||
- :math:`E` is the :mc-setting:`exploration_coefficient`
|
||||
|
||||
- :math:`g_c` is the number of games the candidate has played
|
||||
|
||||
- :math:`w_c` is the number of games the candidate has won
|
||||
|
||||
- :math:`g_p` is the total number of games played in the tuning event
|
||||
|
||||
At the start of the tuning event, each candidate's :math:`g_c` is set to
|
||||
:mc-setting:`initial_visits`, and :math:`w_c` is set to
|
||||
:mc-setting:`initial_wins`.
|
||||
|
||||
(:math:`w_c/g_c` is just the candidate's current win rate. :math:`E
|
||||
\sqrt(log(g_p) / g_c)` is known as the :dfn:`exploration term`; as more games
|
||||
are played, its value increases most rapidly for the least used candidates, so
|
||||
that unpromising candidates will eventually be reconsidered.)
|
||||
|
||||
When more than one candidate has the highest value (for example, at the start
|
||||
of the event), one is chosen at random.
|
||||
|
||||
|
||||
The tuning event runs until :mc-setting:`number_of_games` games have been
|
||||
played (indefinitely, if :mc-setting:`number_of_games` is unset).
|
||||
|
||||
The tuner can be stopped at any time; after each game result, it reports the
|
||||
parameters of the current 'best' candidate. This is the candidate with the
|
||||
most *wins* (note that this may not be the one with the best win rate; it is
|
||||
usually the same as the candidate which has played the most games).
|
||||
|
||||
|
||||
|
||||
.. _sample_mcts_control_file:
|
||||
|
||||
Sample control file
|
||||
"""""""""""""""""""
|
||||
|
||||
Here is a sample control file, illustrating most of the available settings for
|
||||
a Monte Carlo tuning event::
|
||||
|
||||
competition_type = "mc_tuner"
|
||||
|
||||
description = """\
|
||||
This is a sample control file.
|
||||
|
||||
It illustrates the available settings for the Monte Carlo tuner.
|
||||
"""
|
||||
|
||||
players = {
|
||||
'gnugo-l10' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=10"),
|
||||
}
|
||||
|
||||
def fuego(max_games, additional_commands=[]):
|
||||
commands = [
|
||||
"go_param timelimit 999999",
|
||||
"uct_max_memory 350000000",
|
||||
"uct_param_search number_threads 1",
|
||||
"uct_param_player reuse_subtree 0",
|
||||
"uct_param_player ponder 0",
|
||||
"uct_param_player max_games %d" % max_games,
|
||||
]
|
||||
return Player(
|
||||
"fuego --quiet",
|
||||
startup_gtp_commands=commands+additional_commands)
|
||||
|
||||
FUEGO_MAX_GAMES = 5000
|
||||
|
||||
parameters = [
|
||||
Parameter('rave_weight_initial',
|
||||
scale = LOG(0.01, 5.0),
|
||||
split = 8,
|
||||
format = "I: %4.2f"),
|
||||
|
||||
Parameter('rave_weight_final',
|
||||
scale = LOG(1e2, 1e5),
|
||||
split = 8,
|
||||
format = "F: %4.2f"),
|
||||
]
|
||||
|
||||
def make_candidate(rwi, rwf):
|
||||
return fuego(
|
||||
FUEGO_MAX_GAMES,
|
||||
["uct_param_search rave_weight_initial %f" % rwi,
|
||||
"uct_param_search rave_weight_final %f" % rwf])
|
||||
|
||||
board_size = 19
|
||||
komi = 7.5
|
||||
opponent = 'gnugo-l10'
|
||||
candidate_colour = 'w'
|
||||
number_of_games = 10000
|
||||
|
||||
exploration_coefficient = 0.45
|
||||
initial_visits = 10
|
||||
initial_wins = 5
|
||||
|
||||
summary_spec = [40]
|
||||
log_tree_to_history_period = 200
|
||||
|
||||
|
||||
.. _mcts_control_file_settings:
|
||||
|
||||
Control file settings
|
||||
"""""""""""""""""""""
|
||||
|
||||
The following settings can be set at the top level of the control file:
|
||||
|
||||
All :ref:`common settings <common settings>` (the :setting:`players`
|
||||
dictionary is required, though it is used only to define the opponent).
|
||||
|
||||
The following game settings (only :setting:`!board_size` and :setting:`!komi`
|
||||
are required):
|
||||
|
||||
- :setting:`board_size`
|
||||
- :setting:`komi`
|
||||
- :setting:`handicap`
|
||||
- :setting:`handicap_style`
|
||||
- :setting:`move_limit`
|
||||
- :setting:`scorer`
|
||||
|
||||
:setting:`!komi` must be fractional, as the tuning algorithm doesn't currently
|
||||
support :term:`jigos <jigo>`.
|
||||
|
||||
|
||||
The following additional settings (all those without a listed default are
|
||||
required):
|
||||
|
||||
.. mc-setting:: number_of_games
|
||||
|
||||
Integer (default ``None``)
|
||||
|
||||
The total number of games to play in the event. If you leave this unset,
|
||||
there will be no limit.
|
||||
|
||||
|
||||
.. mc-setting:: candidate_colour
|
||||
|
||||
String: ``"b"`` or ``"w"``
|
||||
|
||||
The colour for the candidates to take in every game.
|
||||
|
||||
|
||||
.. mc-setting:: opponent
|
||||
|
||||
Identifier
|
||||
|
||||
The :ref:`player code <player codes>` of the player to use as the
|
||||
candidates' opponent.
|
||||
|
||||
|
||||
.. mc-setting:: parameters
|
||||
|
||||
List of :mc-setting-cls:`Parameter` definitions (see :ref:`mc parameter
|
||||
configuration`).
|
||||
|
||||
Describes the parameter space that the tuner will work in. See :ref:`The
|
||||
parameter model <mc parameter model>` for more details.
|
||||
|
||||
The order of the :mc-setting-cls:`Parameter` definitions is used for the
|
||||
arguments to :mc-setting:`make_candidate`, and whenever parameters are
|
||||
described in reports or game records.
|
||||
|
||||
|
||||
.. mc-setting:: make_candidate
|
||||
|
||||
Python function
|
||||
|
||||
Function to create a :setting-cls:`Player` from its engine parameters.
|
||||
|
||||
This function is passed one argument for each candidate parameter, and must
|
||||
return a :setting-cls:`Player` definition. Each argument is the output of
|
||||
the corresponding :mc-setting-cls:`Parameter`'s :mc-setting:`scale`.
|
||||
|
||||
The function will typically use its arguments to construct command line
|
||||
options or |gtp| commands for the player. For example::
|
||||
|
||||
def make_candidate(param1, param2):
|
||||
return Player(["goplayer", "--param1", str(param1),
|
||||
"--param2", str(param2)])
|
||||
|
||||
def make_candidate(param1, param2):
|
||||
return Player("goplayer", startup_gtp_commands=[
|
||||
["param1", str(param1)],
|
||||
["param2", str(param2)],
|
||||
])
|
||||
|
||||
|
||||
.. mc-setting:: exploration_coefficient
|
||||
|
||||
Float
|
||||
|
||||
The coefficient of the exploration term in the :term:`UCB` algorithm (eg
|
||||
``0.45``). See :ref:`The tuning algorithm <the mcts tuning algorithm>`.
|
||||
|
||||
|
||||
.. mc-setting:: initial_visits
|
||||
|
||||
Positive integer
|
||||
|
||||
The number of games to initialise each candidate with. At the start of the
|
||||
event, the tuner will behave as if each candidate has already played this
|
||||
many games. See :ref:`The tuning algorithm <the mcts tuning algorithm>`.
|
||||
|
||||
|
||||
.. mc-setting:: initial_wins
|
||||
|
||||
Positive integer
|
||||
|
||||
The number of wins to initialise each candidate with. At the start of the
|
||||
event, the tuner will behave as if each candidate has already won this many
|
||||
games. See :ref:`The tuning algorithm <the mcts tuning algorithm>`.
|
||||
|
||||
.. tip:: It's best to set :mc-setting:`initial_wins` so that
|
||||
:mc-setting:`initial_wins` / :mc-setting:`initial_visits` is close to the
|
||||
typical candidate's expected win rate.
|
||||
|
||||
|
||||
.. mc-setting:: max_depth
|
||||
|
||||
Positive integer (default 1)
|
||||
|
||||
See :ref:`tree search` below.
|
||||
|
||||
|
||||
The remaining settings only affect reporting and logging; they have no effect
|
||||
on the tuning algorithm.
|
||||
|
||||
.. mc-setting:: summary_spec
|
||||
|
||||
List of integers (default [30])
|
||||
|
||||
Number of candidates to describe in the runtime display and reports (the
|
||||
candidates with most visits are described).
|
||||
|
||||
(This list should have :mc-setting:`max_depth` elements; if
|
||||
:mc-setting:`max_depth` is greater than 1, it specifies how many candidates
|
||||
to show from each level of the tree, starting with the highest.)
|
||||
|
||||
|
||||
.. mc-setting:: log_tree_to_history_period
|
||||
|
||||
Positive integer (default None)
|
||||
|
||||
If this is set, a detailed description of the :term:`UCT` tree is written to
|
||||
the :ref:`history file <logging>` periodically (after every
|
||||
:mc-setting:`!log_tree_to_history_period` games).
|
||||
|
||||
|
||||
.. mc-setting:: number_of_running_simulations_to_show
|
||||
|
||||
Positive integer (default 12)
|
||||
|
||||
The maximum number of games in progress to describe on the runtime display.
|
||||
|
||||
|
||||
.. _mc parameter configuration:
|
||||
|
||||
Parameter configuration
|
||||
"""""""""""""""""""""""
|
||||
|
||||
.. mc-setting-cls:: Parameter
|
||||
|
||||
A :mc-setting-cls:`!Parameter` definition has the same syntax as a Python
|
||||
function call: :samp:`Parameter({arguments})`. Apart from :mc-setting:`!code`,
|
||||
the arguments should be specified using keyword form (see
|
||||
:ref:`sample_mcts_control_file`).
|
||||
|
||||
All arguments other than :mc-setting:`format` are required.
|
||||
|
||||
The arguments are:
|
||||
|
||||
|
||||
.. mc-setting:: code
|
||||
|
||||
Identifier
|
||||
|
||||
A short string used to identify the parameter. This is used in error
|
||||
messages, and in the default for :mc-setting:`format`.
|
||||
|
||||
|
||||
.. mc-setting:: scale
|
||||
|
||||
Python function
|
||||
|
||||
Function mapping an optimiser parameter to an engine parameter; see :ref:`mc
|
||||
parameter model`.
|
||||
|
||||
Although this can be defined explicitly, in most cases you should be able
|
||||
to use one of the :ref:`predefined scales <predefined scales>`.
|
||||
|
||||
Examples::
|
||||
|
||||
Parameter('p1', split = 8,
|
||||
scale = LINEAR(-1.0, 1.0))
|
||||
|
||||
Parameter('p2', split = 8,
|
||||
scale = LOG(10, 10000, integer=True))
|
||||
|
||||
Parameter('p3', split = 3,
|
||||
scale = EXPLICIT(['low', 'medium', 'high']))
|
||||
|
||||
def scale_p3(f):
|
||||
return int(1000 * math.sqrt(f))
|
||||
Parameter('p3', split = 20, scale = scale_p3)
|
||||
|
||||
|
||||
|
||||
.. mc-setting:: split
|
||||
|
||||
Positive integer
|
||||
|
||||
The number of samples from this parameter to use to make candidates. See
|
||||
:ref:`The tuning algorithm <the mcts tuning algorithm>`.
|
||||
|
||||
|
||||
.. mc-setting:: format
|
||||
|
||||
String (default :samp:`"{parameter_code}: %s"`)
|
||||
|
||||
Format string used to display the parameter value. This should include a
|
||||
short abbreviation to indicate which parameter is being displayed, and also
|
||||
contain ``%s``, which will be replaced with the engine parameter value.
|
||||
|
||||
You can use any Python conversion specifier instead of ``%s``. For example,
|
||||
``%.2f`` will format a floating point number to two decimal places. ``%s``
|
||||
should be safe to use for all types of value. See `string formatting
|
||||
operations`__ for details.
|
||||
|
||||
.. __: http://docs.python.org/release/2.7/library/stdtypes.html#string-formatting-operations
|
||||
|
||||
Format strings should be kept short, as screen space is limited.
|
||||
|
||||
Examples::
|
||||
|
||||
Parameter('parameter_1', split = 8,
|
||||
scale = LINEAR(-1.0, 1.0),
|
||||
format = "p1: %.2f")
|
||||
|
||||
Parameter('parameter_2', split = 8,
|
||||
scale = LOG(10, 10000, integer=True),
|
||||
format = "p2: %d")
|
||||
|
||||
Parameter('parameter_3', split = 3,
|
||||
scale = EXPLICIT(['low', 'medium', 'high']),
|
||||
format = "p3: %s")
|
||||
|
||||
|
||||
.. index:: predefined scale
|
||||
.. index:: scale; predefined
|
||||
|
||||
.. _predefined scales:
|
||||
|
||||
Predefined scales
|
||||
"""""""""""""""""
|
||||
|
||||
There are three kinds of predefined scale which you can use in a
|
||||
:mc-setting:`scale` definition:
|
||||
|
||||
.. index:: LINEAR
|
||||
|
||||
.. object:: LINEAR
|
||||
|
||||
A linear scale between specified bounds. This takes two arguments:
|
||||
``lower_bound`` and ``upper_bound``.
|
||||
|
||||
Optionally, you can also pass ``integer=True``, in which case the result is
|
||||
rounded to the nearest integer.
|
||||
|
||||
Examples::
|
||||
|
||||
LINEAR(0, 100)
|
||||
LINEAR(-64.0, 256.0, integer=True)
|
||||
|
||||
.. tip:: To make candidates which take each value from a simple integer range
|
||||
from (say) 0 to 10 inclusive, use::
|
||||
|
||||
Parameter('p1', split = 11,
|
||||
scale = LINEAR(-0.5, 10.5, integer=True))
|
||||
|
||||
(or use EXPLICIT)
|
||||
|
||||
|
||||
.. index:: LOG
|
||||
|
||||
.. object:: LOG
|
||||
|
||||
A 'logarithmic scale' (ie, an exponential function) between specified
|
||||
bounds. This takes two arguments: ``lower_bound`` and ``upper_bound``.
|
||||
|
||||
Optionally, you can also pass ``integer=True``, in which case the result is
|
||||
rounded to the nearest integer.
|
||||
|
||||
Example::
|
||||
|
||||
LOG(0.01, 1000)
|
||||
LOG(1e2, 1e9, integer=True)
|
||||
|
||||
|
||||
.. index:: EXPLICIT
|
||||
|
||||
.. object:: EXPLICIT
|
||||
|
||||
This scale makes the engine parameters take values from an explicitly
|
||||
specified list. You should normally use this with :mc-setting:`split` equal
|
||||
to the length of the list.
|
||||
|
||||
Examples::
|
||||
|
||||
EXPLICIT([0, 1, 2, 4, 6, 8, 10, 15, 20])
|
||||
EXPLICIT(['low', 'medium', 'high'])
|
||||
|
||||
|
||||
.. note:: if :mc-setting:`max_depth` is greater than 1, :mc-setting:`split`
|
||||
^ :mc-setting:`max_depth` should equal the length of the list.
|
||||
|
||||
|
||||
Writing scale functions
|
||||
"""""""""""""""""""""""
|
||||
|
||||
The following built-in Python functions might be useful: :func:`abs`,
|
||||
:func:`min`, :func:`max`, :func:`round`.
|
||||
|
||||
More functions are available from the :mod:`math` module. Put a line like ::
|
||||
|
||||
from math import log, exp, sqrt
|
||||
|
||||
in the control file to use them.
|
||||
|
||||
Dividing two integers with ``/`` gives a floating point number (that is,
|
||||
'Future division' is in effect).
|
||||
|
||||
You can use scientific notation like ``1.3e-2`` to specify floating point
|
||||
numbers.
|
||||
|
||||
Here are scale functions equivalent to ``LINEAR(3, 3000)`` and
|
||||
``LOG(3, 3000)``::
|
||||
|
||||
def scale_linear(f):
|
||||
return 2997 * f + 3
|
||||
|
||||
def scale_log(f):
|
||||
return exp(log(1000) * f) * 3
|
||||
|
||||
|
||||
Reporting
|
||||
"""""""""
|
||||
|
||||
Currently, there aren't any sophisticated reports.
|
||||
|
||||
The standard report shows the candidates which have played most games; the
|
||||
:mc-setting:`summary_spec` setting defines how many to show.
|
||||
|
||||
In a line like::
|
||||
|
||||
(0,1) I: 0.01; F: 365.17 0.537 70
|
||||
|
||||
The ``(0,1)`` are the 'coordinates' of the candidate, ``I: 0.01; F: 365.17``
|
||||
are the engine parameters (identified using the :mc-setting:`format` setting),
|
||||
``0.537`` is the win rate (including the :mc-setting:`initial_wins` and
|
||||
:mc-setting:`initial_visits`), and ``70`` is the number of games (excluding
|
||||
the :mc-setting:`initial_visits`).
|
||||
|
||||
Also, after every :mc-setting:`log_tree_to_history_period` games, the status
|
||||
of all candidates is written to the :ref:`history file <logging>` (if
|
||||
:mc-setting:`max_depth` > 1, the first two generations of candidates are
|
||||
written).
|
||||
|
||||
|
||||
.. _tree search:
|
||||
|
||||
Tree search
|
||||
"""""""""""
|
||||
|
||||
As a further (and even more experimental) refinement, it's possible to arrange
|
||||
the candidates in the form of a tree and use the :term:`UCT` algorithm instead
|
||||
of plain :term:`UCB`. To do this, set the :mc-setting:`max_depth` setting to a
|
||||
value greater than 1.
|
||||
|
||||
Initially, this behaves as described in :ref:`The tuning algorithm <the mcts
|
||||
tuning algorithm>`. But whenever a candidate is chosen for the second time, it
|
||||
is :dfn:`expanded`: a new generation of candidates is created and placed as
|
||||
that candidate's children in a tree structure.
|
||||
|
||||
The new candidates are created by sampling their parent's 'division' of
|
||||
optimiser parameter space in the same way as the full space was sampled to
|
||||
make the first-generation candidates (so the number of children is again the
|
||||
product of the :mc-setting:`split` settings). Their :math:`g_c` and :math:`w_c`
|
||||
values are initialised to :mc-setting:`initial_visits` and
|
||||
:mc-setting:`initial_wins` as usual.
|
||||
|
||||
Then one of these child candidates is selected using the usual formula, where
|
||||
|
||||
- :math:`g_c` is now the number of games the child has played
|
||||
|
||||
- :math:`w_c` is now the number of games the child has won
|
||||
|
||||
- :math:`g_p` is now the number of games the parent has played
|
||||
|
||||
If :mc-setting:`max_depth` is greater than 2, then when a second-generation
|
||||
candidate is chosen for the second time, it is expanded itself, and so on
|
||||
until :mc-setting:`max_depth` is reached.
|
||||
|
||||
Each time the tuner starts a new game, it walks down the tree using this
|
||||
formula to choose a child node at each level, until it reaches a 'leaf' node.
|
||||
|
||||
Once a candidate has been expanded, it does not play any further games; only
|
||||
candidates which are 'leaf' nodes of the tree are used as players. The
|
||||
:math:`g_c` and :math:`w_c` values for non-leaf candidates count the games and
|
||||
wins played by the candidate's descendants, as well as by the candidate
|
||||
itself.
|
||||
|
||||
The 'best' candidate is determined by walking down the tree and choosing the
|
||||
child with the most wins at each step (which may not end up with the leaf
|
||||
candidate with the most wins in the entire tree).
|
||||
|
||||
|
||||
.. note:: It isn't clear that using UCT for a continuous parameter space like
|
||||
this is a wise (or valid) thing to do. I suspect it needs some form of RAVE
|
||||
to perform well.
|
||||
|
||||
|
||||
.. caution:: If you use a high :option:`--parallel <ringmaster --parallel>`
|
||||
value, note that the Monte Carlo tuner doesn't currently take any action to
|
||||
prevent the same unpromising branch of the tree being explored by multiple
|
||||
processes simultaneously, which might lead to odd results (particularly if
|
||||
you stop the competition and restart it).
|
||||
|
||||
|
||||
|
||||
|
||||
Changing the control file between runs
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
In general, you shouldn't change the :mc-setting-cls:`Parameter` definitions
|
||||
or the settings which control the tuning algorithm between runs. The
|
||||
ringmaster will normally notice and refuse to start, but it's possible to fool
|
||||
it and so get meaningless results.
|
||||
|
||||
Changing the :mc-setting:`exploration_coefficient` is ok. Increasing
|
||||
:mc-setting:`max_depth` is ok (decreasing it is ok too, but it won't stop the
|
||||
tuner exploring parts of the tree that it has already expanded).
|
||||
|
||||
Changing :mc-setting:`make_candidate` is ok, though if this affects player
|
||||
behaviour it will probably be unhelpful.
|
||||
|
||||
Changing :mc-setting:`initial_wins` or :mc-setting:`initial_visits` will have
|
||||
no effect if :mc-setting:`max_depth` is 1; otherwise it will affect only
|
||||
candidates created in future.
|
||||
|
||||
Changing the settings which control reporting, including :mc-setting:`format`,
|
||||
is ok.
|
||||
|
||||
Changing :mc-setting:`number_of_games` is ok.
|
||||
|
214
gomill/docs/playoffs.rst
Normal file
214
gomill/docs/playoffs.rst
Normal file
@ -0,0 +1,214 @@
|
||||
.. index:: playoffs
|
||||
|
||||
.. _playoff tournament:
|
||||
|
||||
Playoff tournaments
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
:setting:`competition_type` string: ``"playoff"``.
|
||||
|
||||
In a playoff tournament the control file explicitly describes one or more
|
||||
pairings of players (:dfn:`matchups`).
|
||||
|
||||
Each matchup is treated independently: different matchups can use different
|
||||
board sizes, handicap arrangements, and so on.
|
||||
|
||||
The tournament runs until :pl-setting:`number_of_games` have been played for
|
||||
each matchup (indefinitely, if :pl-setting:`number_of_games` is unset).
|
||||
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
.. _sample_playoff_control_file:
|
||||
|
||||
Sample control file
|
||||
"""""""""""""""""""
|
||||
|
||||
Here is a sample control file, illustrating how matchups are specified::
|
||||
|
||||
competition_type = 'playoff'
|
||||
|
||||
players = {
|
||||
'gnugo-l1' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=1"),
|
||||
|
||||
'gnugo-l2' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=2"),
|
||||
}
|
||||
|
||||
board_size = 9
|
||||
komi = 6
|
||||
|
||||
matchups = [
|
||||
Matchup('gnugo-l1', 'gnugo-l2', board_size=13,
|
||||
handicap=2, handicap_style='free', komi=0,
|
||||
scorer='players', number_of_games=5),
|
||||
|
||||
Matchup('gnugo-l1', 'gnugo-l2', alternating=True,
|
||||
scorer='players', move_limit=200),
|
||||
|
||||
Matchup('gnugo-l1', 'gnugo-l2',
|
||||
komi=0.5,
|
||||
scorer='internal'),
|
||||
]
|
||||
|
||||
|
||||
.. _playoff_control_file_settings:
|
||||
|
||||
Control file settings
|
||||
"""""""""""""""""""""
|
||||
|
||||
The following settings can be set at the top level of the control file:
|
||||
|
||||
All :ref:`common settings <common settings>`.
|
||||
|
||||
All :ref:`game settings <game settings>`, and the matchup settings
|
||||
:pl-setting:`alternating` and :pl-setting:`number_of_games` described below;
|
||||
these will be used for any matchups which don't explicitly override them.
|
||||
|
||||
.. pl-setting:: matchups
|
||||
|
||||
List of :pl-setting-cls:`Matchup` definitions (see :ref:`matchup
|
||||
configuration`).
|
||||
|
||||
This defines which players will compete against each other, and the game
|
||||
settings they will use.
|
||||
|
||||
The only required settings are :setting:`competition_type`,
|
||||
:setting:`players`, and :pl-setting:`matchups`.
|
||||
|
||||
|
||||
|
||||
.. _matchup configuration:
|
||||
|
||||
Matchup configuration
|
||||
"""""""""""""""""""""
|
||||
|
||||
.. pl-setting-cls:: Matchup
|
||||
|
||||
A :pl-setting-cls:`!Matchup` definition has the same syntax as a Python
|
||||
function call: :samp:`Matchup({arguments})`.
|
||||
|
||||
The first two arguments should be the :ref:`player codes <player codes>` for
|
||||
the two players involved in the matchup. The remaining arguments should be
|
||||
specified in keyword form. For example::
|
||||
|
||||
Matchup('gnugo-l1', 'fuego-5k', board_size=13, komi=6)
|
||||
|
||||
Defaults for matchup arguments (other than :pl-setting:`id` and
|
||||
:pl-setting:`name`) can be specified at the top level of the control file.
|
||||
|
||||
The :setting:`board_size` and :setting:`komi` arguments must be given for all
|
||||
matchups (either explicitly or as defaults); the rest are all optional.
|
||||
|
||||
.. caution:: a default :setting:`komi` or :pl-setting:`alternating` setting
|
||||
will be applied even to handicap games.
|
||||
|
||||
|
||||
All :ref:`game settings <game settings>` can be used as matchup arguments, and
|
||||
also the following:
|
||||
|
||||
|
||||
.. _matchup id:
|
||||
|
||||
.. pl-setting:: id
|
||||
|
||||
Identifier
|
||||
|
||||
A short string (usually one to three characters) which is used to identify
|
||||
the matchup. Matchup ids appear in the :ref:`game ids <game id>` (and so in
|
||||
the |sgf| filenames), and are used in the :doc:`tournament results API
|
||||
<tournament_results>`.
|
||||
|
||||
If this is left unspecified, the matchup id will be the index of the matchup
|
||||
in the :pl-setting:`matchups` list (formatted as a decimal string, starting
|
||||
from ``"0"``).
|
||||
|
||||
|
||||
.. pl-setting:: name
|
||||
|
||||
String
|
||||
|
||||
A string used to describe the matchup in reports. By default, this has the
|
||||
form :samp:`{player code} vs {player code}`; you may wish to change it if you
|
||||
have more than one matchup between the same pair of players (perhaps with
|
||||
different komi or handicap).
|
||||
|
||||
|
||||
.. pl-setting:: alternating
|
||||
|
||||
Boolean (default ``False``)
|
||||
|
||||
If this is ``True``, the players will swap colours in successive games.
|
||||
Otherwise, the player given as the first argument always takes Black.
|
||||
|
||||
|
||||
.. pl-setting:: number_of_games
|
||||
|
||||
Integer (default ``None``)
|
||||
|
||||
The total number of games to play in the matchup. If you leave this unset,
|
||||
there will be no limit.
|
||||
|
||||
Changing :pl-setting:`!number_of_games` to ``0`` provides a way to effectively
|
||||
disable a matchup in future runs, without forgetting its results.
|
||||
|
||||
|
||||
Reporting
|
||||
"""""""""
|
||||
|
||||
The :ref:`live display <live_display>` and :ref:`competition report
|
||||
<competition report file>` show each matchup's results in the following form::
|
||||
|
||||
gnugo-l1 v gnugo-l2 (5/5 games)
|
||||
board size: 9 komi: 7.5
|
||||
wins black white avg cpu
|
||||
gnugo-l1 2 40.00% 1 33.33% 1 50.00% 1.23
|
||||
gnugo-l2 3 60.00% 1 50.00% 2 66.67% 1.39
|
||||
2 40.00% 3 60.00%
|
||||
|
||||
or, if the players have not alternated colours::
|
||||
|
||||
gnugo-l1 v gnugo-l2 (5/5 games)
|
||||
board size: 9 komi: 7.5
|
||||
wins avg cpu
|
||||
gnugo-l1 0 0.00% (black) 0.49
|
||||
gnugo-l2 5 100.00% (white) 0.48
|
||||
|
||||
Any :term:`jigos <jigo>` are counted as half a win for each player. If any
|
||||
games have been lost by forfeit, a count will be shown for each player. If any
|
||||
games have unknown results (because they could not be scored, or reached the
|
||||
:setting:`move_limit`), a count will be shown for each matchup. :ref:`void
|
||||
games` are not shown in these reports.
|
||||
|
||||
If there is more than one matchup between the same pair of players, use the
|
||||
matchup :pl-setting:`name` setting to distinguish them.
|
||||
|
||||
|
||||
Changing the control file between runs
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
If you change a :pl-setting-cls:`Matchup` definition, the new definition will
|
||||
be used when describing the matchup in reports; there'll be no record of the
|
||||
earlier definition, or which games were played under it.
|
||||
|
||||
If you change a :pl-setting-cls:`Matchup` definition to have different players
|
||||
(ie, player codes), the ringmaster will refuse to run the competition.
|
||||
|
||||
If you delete a :pl-setting-cls:`Matchup` definition, results from that
|
||||
matchup won't be displayed during future runs, but will be included (with some
|
||||
missing information) in the :action:`report` and :action:`show` output.
|
||||
|
||||
If you add a :pl-setting-cls:`Matchup` definition, put it at the end of the
|
||||
list (or else explicitly specify the matchup ids).
|
||||
|
||||
It's safe to increase or decrease a matchup's :pl-setting:`number_of_games`.
|
||||
If more games have been played than the new limit, they will not be forgotten.
|
||||
|
||||
In practice, you shouldn't delete :pl-setting-cls:`Matchup` definitions (if
|
||||
you don't want any more games to be played, set :pl-setting:`number_of_games`
|
||||
to ``0``).
|
||||
|
12
gomill/docs/python-inv.txt
Normal file
12
gomill/docs/python-inv.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# Sphinx inventory version 1
|
||||
# Project: Python
|
||||
# Version: 2.7
|
||||
os.path.expanduser function library/os.path.html
|
||||
shlex.split function library/shlex.html
|
||||
termios mod library/termios.html
|
||||
math mod library/math.html
|
||||
abs function library/functions.html
|
||||
max function library/functions.html
|
||||
min function library/functions.html
|
||||
round function library/functions.html
|
||||
datetime.date class library/datetime.html
|
106
gomill/docs/results.rst
Normal file
106
gomill/docs/results.rst
Normal file
@ -0,0 +1,106 @@
|
||||
Viewing results
|
||||
---------------
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
.. _competition report file:
|
||||
.. index:: report file
|
||||
|
||||
Reports
|
||||
^^^^^^^
|
||||
|
||||
The competition :dfn:`report file` (:file:`{code}.report`) file is a plain
|
||||
text description of the competition results. This is similar to the live
|
||||
report that is displayed while the competition is running. It includes the
|
||||
contents of the competition's :setting:`description` setting.
|
||||
|
||||
For tournaments, it also shows descriptions of the players. These are obtained
|
||||
using the |gtp| :gtp:`!name` and :gtp:`!version` commands, or using
|
||||
:gtp:`gomill-describe_engine` if the engine provides it.
|
||||
|
||||
For example, in a playoff tournament with a single matchup::
|
||||
|
||||
playoff: example
|
||||
|
||||
Testing GNU Go level 1 vs level 2, 2010-10-14
|
||||
|
||||
gnugo-l1 v gnugo-l2 (5/5 games)
|
||||
board size: 9 komi: 7.5
|
||||
wins black white avg cpu
|
||||
gnugo-l1 2 40.00% 1 33.33% 1 50.00% 1.23
|
||||
gnugo-l2 3 60.00% 1 50.00% 2 66.67% 1.39
|
||||
2 40.00% 3 60.00%
|
||||
|
||||
player gnugo-l1: GNU Go:3.8
|
||||
player gnugo-l2: GNU Go:3.8
|
||||
|
||||
|
||||
The report file is written automatically at the end of each run. The
|
||||
:action:`report` command line action forces it to be rewritten; this can be
|
||||
useful if you have changed descriptive text in the control file, or if a run
|
||||
stopped ungracefully.
|
||||
|
||||
The :action:`show` command line action prints the same report to standard
|
||||
output.
|
||||
|
||||
It's safe to run :action:`show` or :action:`report` on a competition which is
|
||||
currently being run.
|
||||
|
||||
|
||||
.. _game records:
|
||||
|
||||
Game records
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The ringmaster writes an |sgf| record of each game it plays to the
|
||||
:file:`{code}.games/` directory (which it will create if necessary). This can
|
||||
be disabled with the :setting:`record_games` setting. The filename is based on
|
||||
the game's :ref:`game_id <game id>`.
|
||||
|
||||
(You might also see game records in a :file:`{code}.void/` directory; these
|
||||
are games which were abandoned due to software failure; see :ref:`void
|
||||
games`.)
|
||||
|
||||
The ringmaster supports a protocol for engines to provide text to be placed in
|
||||
the comment section for individual moves: see :gtp:`gomill-explain_last_move`.
|
||||
|
||||
The game record includes a description of the players in the root node comment
|
||||
[#]_. If an engine implements :gtp:`gomill-describe_engine`, its output is
|
||||
included.
|
||||
|
||||
.. [#] The root node comment is used rather than the game comment because (in
|
||||
my experience) |sgf| viewers tend to make it easier to see information
|
||||
there.
|
||||
|
||||
|
||||
.. index:: CPU time
|
||||
.. index:: time; CPU
|
||||
|
||||
.. _cpu time:
|
||||
|
||||
CPU time
|
||||
^^^^^^^^
|
||||
|
||||
The reports and game records show the CPU time taken by the players, when
|
||||
available.
|
||||
|
||||
If an engine implements the :gtp:`gomill-cpu_time` command, its output is
|
||||
used. Otherwise, the ringmaster uses the CPU time of the engine process that
|
||||
it created, as returned by the :c:func:`!wait4()` system call (user plus system
|
||||
time); unfortunately, this may not be meaningful, if the engine's work isn't
|
||||
all done directly in that process.
|
||||
|
||||
|
||||
.. _querying the results:
|
||||
|
||||
Querying the results
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Gomill provides a Python library interface for processing the game results
|
||||
stored in a tournament's :ref:`state file <competition state>`.
|
||||
|
||||
This is documented in :doc:`tournament_results`. See also the
|
||||
:script:`find_forfeits.py` example script.
|
||||
|
71
gomill/docs/ringmaster.rst
Normal file
71
gomill/docs/ringmaster.rst
Normal file
@ -0,0 +1,71 @@
|
||||
The ringmaster
|
||||
==============
|
||||
|
||||
The ringmaster is a command line program which arranges games between |gtp|
|
||||
engines and keeps track of the results. See :doc:`ringmaster_cmdline` below
|
||||
for details of the command line options.
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
Competitions and runs
|
||||
---------------------
|
||||
|
||||
.. index:: competition
|
||||
|
||||
The ringmaster takes its instructions from a single configuration file known
|
||||
as the :doc:`control file <settings>`. Each control file defines a
|
||||
:term:`competition`; the :ref:`output files <output files>` for that
|
||||
competition are written to the directory containing the control file.
|
||||
|
||||
|
||||
.. index:: run
|
||||
|
||||
A competition can take place over multiple invocations of the ringmaster
|
||||
(:dfn:`runs`). For example, a run can be halted from the console, in which
|
||||
case starting the ringmaster again will make it continue from where it left
|
||||
off.
|
||||
|
||||
|
||||
Competition types
|
||||
-----------------
|
||||
|
||||
The ringmaster supports a number of different :dfn:`competition types`.
|
||||
These are divided into :dfn:`tournaments` and :dfn:`tuning events`.
|
||||
|
||||
In a tournament, the ringmaster plays games between predefined players, in
|
||||
order to compare their strengths. The types of tournament are:
|
||||
|
||||
Playoff tournaments
|
||||
In a playoff tournament the control file explicitly describes one or more
|
||||
pairings of players (:dfn:`matchups`). Each matchup can have separate
|
||||
settings.
|
||||
|
||||
All-play-all tournaments
|
||||
In an all-play-all tournament the control file lists a number of players, and
|
||||
games are played with the same settings between each possible pairing.
|
||||
|
||||
In a tuning event, the ringmaster runs an algorithm for adjusting player
|
||||
parameters to try to find the values which give strongest play.
|
||||
|
||||
See :ref:`competition types` for full details of the types of tournament and
|
||||
tuning event.
|
||||
|
||||
|
||||
|
||||
|
||||
Using the ringmaster
|
||||
--------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:titlesonly:
|
||||
|
||||
competitions
|
||||
results
|
||||
ringmaster_cmdline
|
||||
settings
|
||||
competition_types
|
||||
Error handling… <errors>
|
||||
|
80
gomill/docs/ringmaster_cmdline.rst
Normal file
80
gomill/docs/ringmaster_cmdline.rst
Normal file
@ -0,0 +1,80 @@
|
||||
Command line
|
||||
^^^^^^^^^^^^
|
||||
|
||||
.. program:: ringmaster
|
||||
|
||||
.. index:: action; ringmaster
|
||||
|
||||
The ringmaster expects two command line arguments: the pathname of the control
|
||||
file and an :dfn:`action`::
|
||||
|
||||
ringmaster [options] <code>.ctl run
|
||||
ringmaster [options] <code>.ctl show
|
||||
ringmaster [options] <code>.ctl reset
|
||||
ringmaster [options] <code>.ctl check
|
||||
ringmaster [options] <code>.ctl report
|
||||
ringmaster [options] <code>.ctl stop
|
||||
|
||||
The default action is :action:`!run`, so running a competition is normally a
|
||||
simple line like::
|
||||
|
||||
$ ringmaster competitions/test.ctl
|
||||
|
||||
See :ref:`Stopping competitions <stopping competitions>` for the various ways
|
||||
to stop the ringmaster.
|
||||
|
||||
|
||||
The following actions are available:
|
||||
|
||||
.. action:: run
|
||||
|
||||
Starts the competition running. If the competition has been run previously,
|
||||
it continues from where it left off.
|
||||
|
||||
.. action:: show
|
||||
|
||||
Prints a :ref:`report <competition report file>` of the competition's
|
||||
current status. This can be used for both running and stopped competitions.
|
||||
|
||||
.. action:: reset
|
||||
|
||||
Cleans up the competition completely. This deletes all output files,
|
||||
including the competition's :ref:`state file <competition state>`.
|
||||
|
||||
.. action:: check
|
||||
|
||||
Runs a test invocation of the competition's players. This is the same as the
|
||||
:ref:`startup checks`, except that any output the players send to their
|
||||
standard error stream will be printed.
|
||||
|
||||
.. action:: report
|
||||
|
||||
Rewrites the :ref:`competition report file <competition report file>` based
|
||||
on the current status. This can be used for both running and stopped
|
||||
competitions.
|
||||
|
||||
.. action:: stop
|
||||
|
||||
Tells a running ringmaster for the competition to stop as soon as the
|
||||
current games have completed.
|
||||
|
||||
|
||||
The following options are available:
|
||||
|
||||
.. option:: --parallel <N>, -j <N>
|
||||
|
||||
Play N :ref:`simultaneous games <simultaneous games>`.
|
||||
|
||||
.. option:: --quiet, -q
|
||||
|
||||
Disable the on-screen reporting; see :ref:`Quiet mode <quiet mode>`.
|
||||
|
||||
.. option:: --max-games <N>, -g <N>
|
||||
|
||||
Maximum number of games to play in the run; see :ref:`running
|
||||
competitions`.
|
||||
|
||||
.. option:: --log-gtp
|
||||
|
||||
Log all |gtp| traffic; see :ref:`logging`.
|
||||
|
534
gomill/docs/settings.rst
Normal file
534
gomill/docs/settings.rst
Normal file
@ -0,0 +1,534 @@
|
||||
.. _control file:
|
||||
|
||||
The control file
|
||||
----------------
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
.. _sample control file:
|
||||
|
||||
Sample control file
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Here is a sample control file for a playoff tournament::
|
||||
|
||||
competition_type = 'playoff'
|
||||
|
||||
description = """
|
||||
This is a sample control file.
|
||||
|
||||
It illustrates player definitions, common settings, and game settings.
|
||||
"""
|
||||
|
||||
record_games = True
|
||||
stderr_to_log = False
|
||||
|
||||
players = {
|
||||
# GNU Go level 1
|
||||
'gnugo-l1' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=1"),
|
||||
|
||||
# GNU Go level 2
|
||||
'gnugo-l2' : Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=2"),
|
||||
|
||||
# Fuego at 5000 playouts per move
|
||||
'fuego-5k' : Player("fuego --quiet",
|
||||
startup_gtp_commands=[
|
||||
"go_param timelimit 999999",
|
||||
"uct_max_memory 350000000",
|
||||
"uct_param_search number_threads 1",
|
||||
"uct_param_player reuse_subtree 0",
|
||||
"uct_param_player ponder 0",
|
||||
"uct_param_player max_games 5000",
|
||||
]),
|
||||
}
|
||||
|
||||
board_size = 9
|
||||
komi = 6
|
||||
|
||||
matchups = [
|
||||
Matchup('gnugo-l1', 'fuego-5k', board_size=13,
|
||||
handicap=2, handicap_style='free', komi=0,
|
||||
scorer='players', number_of_games=5),
|
||||
|
||||
Matchup('gnugo-l2', 'fuego-5k', alternating=True,
|
||||
scorer='players', move_limit=200),
|
||||
|
||||
Matchup('gnugo-l1', 'gnugo-l2',
|
||||
komi=0.5,
|
||||
scorer='internal'),
|
||||
]
|
||||
|
||||
|
||||
File format
|
||||
^^^^^^^^^^^
|
||||
|
||||
The control file is a plain text configuration file.
|
||||
|
||||
It is interpreted in the same way as a Python source file. See the
|
||||
:ref:`sample control file` above for an example of the syntax.
|
||||
|
||||
.. __: http://docs.python.org/release/2.7/reference/index.html
|
||||
|
||||
The control file is made up of a series of top-level :dfn:`settings`, in the
|
||||
form of assignment statements: :samp:`{setting_name} = {value}`.
|
||||
|
||||
Each top-level setting should begin on a new line, in the leftmost column of
|
||||
the file. Settings which use brackets of any kind can be split over multiple
|
||||
lines between elements (for example, lists can be split at the commas).
|
||||
|
||||
Comments are introduced by the ``#`` character, and continue until the end of
|
||||
the line.
|
||||
|
||||
In general, the order of settings in the control file isn't significant
|
||||
(except for list members). But note that :setting:`competition_type` must come
|
||||
first.
|
||||
|
||||
See :ref:`data types` below for the representation of values. See the `Python
|
||||
language reference`__ for a formal specification.
|
||||
|
||||
The settings which are common to all competition types are listed below.
|
||||
Further settings are given on the page documenting each competition type.
|
||||
|
||||
.. caution:: while the ringmaster will give error messages for unacceptable
|
||||
setting values, it will ignore attempts to set a nonexistent setting (this
|
||||
is because you're allowed to define variables of your own in the control
|
||||
file and use them in later setting definitions).
|
||||
|
||||
If you wish, you can use arbitrary Python expressions in the control file; see
|
||||
:ref:`control file techniques` below.
|
||||
|
||||
.. caution:: all Python code in the control file will be executed; a hostile
|
||||
party with write access to a control file can cause the ringmaster to
|
||||
execute arbitrary code. On a shared system, do not make the competition
|
||||
directory or the control file world-writeable.
|
||||
|
||||
The recommended filename extension for the control file is :file:`.ctl`.
|
||||
|
||||
.. _data types:
|
||||
|
||||
Data types
|
||||
^^^^^^^^^^
|
||||
|
||||
The following data types are used for values of settings:
|
||||
|
||||
String
|
||||
A literal string of characters in single or double quotes, eg ``'gnugo-l1'``
|
||||
or ``"free"``.
|
||||
|
||||
Strings containing non-ASCII characters should be encoded as UTF-8 (Python
|
||||
unicode objects are also accepted).
|
||||
|
||||
Strings can be broken over multiple lines by writing adjacent literals
|
||||
separated only by whitespace; see the :setting-cls:`Player` definitions in
|
||||
the example above.
|
||||
|
||||
Backslash escapes can be used in strings, such as ``\n`` for a newline.
|
||||
Alternatively, three (single or double) quotes can be used for a multi-line
|
||||
string; see ``description`` in the example above.
|
||||
|
||||
Identifier
|
||||
A (short) string made up of any combination of ASCII letters, numerals, and
|
||||
the punctuation characters ``- ! $ % & * + - . : ; < = > ? ^ _ ~``.
|
||||
|
||||
Boolean
|
||||
A truth value, written as ``True`` or ``False``.
|
||||
|
||||
Integer
|
||||
A whole number, written as a decimal literal, eg ``19`` or ``-1``.
|
||||
|
||||
Float
|
||||
A floating-point number, written as a decimal literal, eg ``6`` or ``6.0``
|
||||
or ``6.5``.
|
||||
|
||||
List
|
||||
A sequence of values of uniform type, written with square brackets separated
|
||||
by commas, eg ``["max_playouts 3000", "initial_wins 5"]``. An extra comma
|
||||
after the last item is harmless.
|
||||
|
||||
Dictionary
|
||||
An explicit map of keys of uniform type to values of uniform type, written
|
||||
with curly brackets, colons, and commas, eg ``{'p1' : True, 'p2' : False}``.
|
||||
An extra comma after the last item is harmless.
|
||||
|
||||
|
||||
.. _file and directory names:
|
||||
|
||||
File and directory names
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When values in the control file are file or directory names, non-absolute
|
||||
names are interpreted relative to the :ref:`competition directory <competition
|
||||
directory>`.
|
||||
|
||||
If a file or directory name begins with ``~``, home directory expansion is
|
||||
applied (see :func:`os.path.expanduser`).
|
||||
|
||||
|
||||
.. _common settings:
|
||||
|
||||
Common settings
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following settings can appear at the top level of the control file for all
|
||||
competition types.
|
||||
|
||||
.. setting:: competition_type
|
||||
|
||||
String: ``"playoff"``, ``"allplayall"``, ``"mc_tuner"``, or ``"ce_tuner"``
|
||||
|
||||
Determines the type of tournament or tuning event. This must be set on the
|
||||
first line in the control file (not counting blank lines and comments).
|
||||
|
||||
|
||||
.. setting:: description
|
||||
|
||||
String (default ``None``)
|
||||
|
||||
A text description of the competition. This will be included in the
|
||||
:ref:`competition report file <competition report file>`. Leading and
|
||||
trailing whitespace is ignored.
|
||||
|
||||
|
||||
.. setting:: record_games
|
||||
|
||||
Boolean (default ``True``)
|
||||
|
||||
Write |sgf| :ref:`game records <game records>`.
|
||||
|
||||
|
||||
.. setting:: stderr_to_log
|
||||
|
||||
Boolean (default ``True``)
|
||||
|
||||
Redirect all players' standard error streams to the :ref:`event log
|
||||
<logging>`. See :ref:`standard error`.
|
||||
|
||||
|
||||
.. _player codes:
|
||||
|
||||
.. index:: player code
|
||||
|
||||
.. setting:: players
|
||||
|
||||
Dictionary mapping identifiers to :setting-cls:`Player` definitions (see
|
||||
:ref:`player configuration`).
|
||||
|
||||
Describes the |gtp| engines that can be used in the competition. If you wish
|
||||
to use the same program with different settings, each combination of
|
||||
settings must be given its own :setting-cls:`Player` definition. See
|
||||
:ref:`control file techniques` below for a compact way to define several
|
||||
similar Players.
|
||||
|
||||
The dictionary keys are the :dfn:`player codes`; they are used to identify
|
||||
the players in reports and the |sgf| game records, and elsewhere in the
|
||||
control file to specify how players take part in the competition.
|
||||
|
||||
See the pages for specific competition types for the way in which players
|
||||
are selected from the :setting:`!players` dictionary.
|
||||
|
||||
It's fine to have player definitions here which aren't used in the
|
||||
competition. These definitions will be ignored, and no corresponding engines
|
||||
will be run.
|
||||
|
||||
|
||||
|
||||
.. _player configuration:
|
||||
|
||||
Player configuration
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. setting-cls:: Player
|
||||
|
||||
A :setting-cls:`!Player` definition has the same syntax as a Python function
|
||||
call: :samp:`Player({arguments})`. Apart from :setting:`command`, the
|
||||
arguments should be specified using keyword form (see the examples for
|
||||
particular arguments below).
|
||||
|
||||
All arguments other than :setting:`command` are optional.
|
||||
|
||||
.. tip:: For results to be meaningful, you should normally configure players
|
||||
to use a fixed amount of computing power, paying no attention to the amount
|
||||
of real time that passes, and make sure :term:`pondering` is not turned on.
|
||||
|
||||
The arguments are:
|
||||
|
||||
|
||||
.. setting:: command
|
||||
|
||||
String or list of strings
|
||||
|
||||
This is the only required :setting-cls:`Player` argument. It can be
|
||||
specified either as the first argument, or using a keyword
|
||||
:samp:`command="{...}"`. It specifies the executable which will provide the
|
||||
player, and its command line arguments.
|
||||
|
||||
The player subprocess is executed directly, not run via a shell.
|
||||
|
||||
The :setting:`!command` can be either a string or a list of strings. If it
|
||||
is a string, it is split using rules similar to a Unix shell's (see
|
||||
:func:`shlex.split`).
|
||||
|
||||
In either case, the first element is taken as the executable name and the
|
||||
remainder as its arguments.
|
||||
|
||||
If the executable name does not contain a ``/``, it is searched for on the
|
||||
the :envvar:`!PATH`. Otherwise it is handled as described in :ref:`file and
|
||||
directory names <file and directory names>`.
|
||||
|
||||
Example::
|
||||
|
||||
Player("~/src/fuego-svn/fuegomain/fuego --quiet")
|
||||
|
||||
|
||||
.. setting:: cwd
|
||||
|
||||
String (default ``None``)
|
||||
|
||||
The working directory for the player.
|
||||
|
||||
If this is left unset, the player's working directory will be the working
|
||||
directory from when the ringmaster was launched (which may not be the
|
||||
competition directory). Use ``cwd="."`` to specify the competition
|
||||
directory.
|
||||
|
||||
.. tip::
|
||||
If an engine writes debugging information to its working directory, use
|
||||
:setting:`cwd` to get it out of the way::
|
||||
|
||||
Player('mogo', cwd='~/tmp')
|
||||
|
||||
|
||||
.. setting:: environ
|
||||
|
||||
Dictionary mapping strings to strings (default ``None``)
|
||||
|
||||
This specifies environment variables to be set in the player process, in
|
||||
addition to (or overriding) those inherited from its parent.
|
||||
|
||||
Note that there is no special handling in this case for values which happen
|
||||
to be file or directory names.
|
||||
|
||||
Example::
|
||||
|
||||
Player('goplayer', environ={'GOPLAYER-DEBUG' : 'true'})
|
||||
|
||||
|
||||
.. setting:: discard_stderr
|
||||
|
||||
Boolean (default ``False``)
|
||||
|
||||
Redirect the player's standard error stream to :file:`/dev/null`. See
|
||||
:ref:`standard error`.
|
||||
|
||||
Example::
|
||||
|
||||
Player('mogo', discard_stderr=True)
|
||||
|
||||
|
||||
.. setting:: startup_gtp_commands
|
||||
|
||||
List of strings, or list of lists of strings (default ``None``)
|
||||
|
||||
|gtp| commands to send at the beginning of each game. See :ref:`playing
|
||||
games`.
|
||||
|
||||
Each command can be specified either as a single string or as a list of
|
||||
strings (with each |gtp| argument in a single string). For example, the
|
||||
following are equivalent::
|
||||
|
||||
Player('fuego', startup_gtp_commands=[
|
||||
"uct_param_player ponder 0",
|
||||
"uct_param_player max_games 5000"])
|
||||
|
||||
Player('fuego', startup_gtp_commands=[
|
||||
["uct_param_player", "ponder", "0"],
|
||||
["uct_param_player", "max_games", "5000"]])
|
||||
|
||||
|
||||
.. setting:: gtp_aliases
|
||||
|
||||
Dictionary mapping strings to strings (default ``None``)
|
||||
|
||||
This is a map of |gtp| command names to command names, eg::
|
||||
|
||||
Player('fuego', gtp_aliases={'gomill-cpu_time' : 'cputime'})
|
||||
|
||||
When the ringmaster would normally send :gtp:`gomill-cpu_time`, it will send
|
||||
:gtp:`!cputime` instead.
|
||||
|
||||
The command names are case-sensitive. There is no mechanism for altering
|
||||
arguments.
|
||||
|
||||
|
||||
.. setting:: is_reliable_scorer
|
||||
|
||||
Boolean (default ``True``)
|
||||
|
||||
If the :setting:`scorer` setting is ``players``, the ringmaster normally
|
||||
asks each player that implements the :gtp:`!final_score` |gtp| command to
|
||||
report the game result. Setting :setting:`!is_reliable_scorer` to ``False``
|
||||
for a player causes that player never to be asked.
|
||||
|
||||
|
||||
.. setting:: allow_claim
|
||||
|
||||
Boolean (default ``False``)
|
||||
|
||||
Permits the player to claim a win (using the |gtp| extension
|
||||
:gtp:`gomill-genmove_ex`). See :ref:`claiming wins`.
|
||||
|
||||
|
||||
.. _game settings:
|
||||
|
||||
Game settings
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The following settings describe how a particular game is to be played.
|
||||
|
||||
They are not all used in every competition type, and may be specified in some
|
||||
other way than a top level control file setting; see the page documenting a
|
||||
particular competition type for details.
|
||||
|
||||
|
||||
.. setting:: board_size
|
||||
|
||||
Integer
|
||||
|
||||
The size of Go board to use for the game (eg ``19`` for a 19x19 game). The
|
||||
ringmaster is willing to use board sizes from 2 to 25.
|
||||
|
||||
|
||||
.. setting:: komi
|
||||
|
||||
Float
|
||||
|
||||
The :term:`komi` to use for the game. You can specify any floating-point
|
||||
value, and it will be passed on to the |gtp| engines unchanged, but normally
|
||||
only integer or half-integer values will be useful. Negative values are
|
||||
allowed.
|
||||
|
||||
|
||||
.. setting:: handicap
|
||||
|
||||
Integer (default ``None``)
|
||||
|
||||
The number of handicap stones to give Black at the start of the game. See
|
||||
also :setting:`handicap_style`.
|
||||
|
||||
See the `GTP specification`_ for the rules about what handicap values
|
||||
are permitted for different board sizes (in particular, values less than 2
|
||||
are never allowed).
|
||||
|
||||
|
||||
.. setting:: handicap_style
|
||||
|
||||
String: ``"fixed"`` or ``"free"`` (default ``"fixed"``)
|
||||
|
||||
Determines whether the handicap stones are placed on prespecified points, or
|
||||
chosen by the Black player. See the `GTP specification`_ for more details.
|
||||
|
||||
This is ignored if :setting:`handicap` is unset.
|
||||
|
||||
.. _GTP specification: http://www.lysator.liu.se/~gunnar/gtp/gtp2-spec-draft2/gtp2-spec.html#SECTION00051000000000000000
|
||||
|
||||
|
||||
|
||||
.. setting:: move_limit
|
||||
|
||||
Integer (default ``1000``)
|
||||
|
||||
The maximum number of moves to allow in a game. If this limit is reached,
|
||||
the game is stopped; see :ref:`playing games`.
|
||||
|
||||
|
||||
.. setting:: scorer
|
||||
|
||||
String: ``"players"`` or ``"internal"`` (default ``"players"``)
|
||||
|
||||
Determines whether the game result is determined by the engines, or by the
|
||||
ringmaster. See :ref:`Scoring <scoring>` and :setting:`is_reliable_scorer`.
|
||||
|
||||
|
||||
.. setting:: internal_scorer_handicap_compensation
|
||||
|
||||
String: ``"no"``, ``"full"`` or ``"short"`` (default ``"full"``)
|
||||
|
||||
Specifies whether White is given extra points to compensate for Black's
|
||||
handicap stones; see :ref:`Scoring <scoring>` for details. This setting has
|
||||
no effect for games which are played without handicap, and it has no effect
|
||||
when :setting:`scorer` is set to ``"players"``.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Changing the control file between runs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Changing the control file between runs of the same competition (or after the
|
||||
final run) is allowed. For example, in a playoff tournament it's fine to
|
||||
increase a completed matchup's :pl-setting:`number_of_games` and set the
|
||||
competition off again.
|
||||
|
||||
The intention is that nothing surprising should happen if you change the
|
||||
control file; of course if you change settings which affect player behaviour
|
||||
then result summaries might not be meaningful.
|
||||
|
||||
In particular, if you change a :setting-cls:`Player` definition, the new
|
||||
definition will be used when describing the player in reports; there'll be no
|
||||
record of the earlier definition, or which games were played under it.
|
||||
|
||||
If you change descriptive text, you can use the :action:`report` command line
|
||||
action to remake the report file.
|
||||
|
||||
The page documenting each competition type has more detail on what it is safe
|
||||
to change.
|
||||
|
||||
|
||||
.. _control file techniques:
|
||||
|
||||
Control file techniques
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As the control file is just Python code, it's possible to use less direct
|
||||
methods to specify the values of settings.
|
||||
|
||||
One convenient way to define a number of similar players is to define a
|
||||
function which returns a :setting-cls:`Player` object. For example, the player
|
||||
definitions in the sample control file could be rewritten as follows::
|
||||
|
||||
def gnugo(level):
|
||||
return Player("gnugo --mode=gtp --chinese-rules "
|
||||
"--capture-all-dead --level=%d" % level)
|
||||
|
||||
def fuego(playouts_per_move, additional_commands=[]):
|
||||
commands = [
|
||||
"go_param timelimit 999999",
|
||||
"uct_max_memory 350000000",
|
||||
"uct_param_search number_threads 1",
|
||||
"uct_param_player reuse_subtree 0",
|
||||
"uct_param_player ponder 0",
|
||||
"uct_param_player max_games %d" % playouts_per_move,
|
||||
]
|
||||
return Player(
|
||||
"fuego --quiet",
|
||||
startup_gtp_commands=commands+additional_commands)
|
||||
|
||||
players = {
|
||||
'gnugo-l1' : gnugo(level=1),
|
||||
'gnugo-l2' : gnugo(level=2),
|
||||
'fuego-5k' : fuego(playouts_per_move=5000)
|
||||
}
|
||||
|
||||
If you assign to a setting more than once, the final value is the one that
|
||||
counts. Settings specified above as having default ``None`` can be assigned
|
||||
the value ``None``, which will be equivalent to leaving them unset.
|
||||
|
||||
Importing parts of the Python standard library (or other Python libraries that
|
||||
you have installed) is allowed.
|
||||
|
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.
|
||||
|
401
gomill/docs/tournament_results.rst
Normal file
401
gomill/docs/tournament_results.rst
Normal file
@ -0,0 +1,401 @@
|
||||
Tournament results API
|
||||
----------------------
|
||||
|
||||
.. module:: gomill.tournament_results
|
||||
:synopsis: Retrieving and reporting on tournament results.
|
||||
|
||||
This is a Python interface for processing the game results stored in a
|
||||
tournament's :ref:`state file <competition state>`. It can be used to write
|
||||
custom reports, or to find games with particular results.
|
||||
|
||||
Note that it can be used only for :ref:`tournaments <tournaments>` (not for
|
||||
:ref:`tuning events <tuners>`).
|
||||
|
||||
.. contents:: Page contents
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
|
||||
In this interface, players are identified using their player codes (that is,
|
||||
their keys in the control file's :setting:`players` dictionary).
|
||||
|
||||
.. note:: In a :doc:`playoff tournament <playoffs>`, it is possible
|
||||
to define a matchup in which the same player takes both colours. In this
|
||||
case, the player code used for the second player will be the player code
|
||||
from the control file with ``'#2'`` appended.
|
||||
|
||||
The classes described here are implemented in the
|
||||
:mod:`!gomill.tournament_results` and :mod:`!gomill.gtp_games` modules, but
|
||||
you should not normally import these directly. See
|
||||
:ref:`using_the_api_in_scripts`.
|
||||
|
||||
|
||||
Tournament_results objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. class:: Tournament_results
|
||||
|
||||
A Tournament_results object provides access to the game results and
|
||||
statistics for a single tournament.
|
||||
|
||||
The tournament results are catalogued in terms of :dfn:`matchups`, with
|
||||
each matchup corresponding to a series of games which had the same players
|
||||
and settings. Each matchup has an id, which is a short string.
|
||||
|
||||
Tournament_results objects are normally retrieved from :class:`!Competition`
|
||||
or :class:`!Ringmaster` objects; see :ref:`using_the_api_in_scripts`.
|
||||
|
||||
Tournament_results objects support the following methods:
|
||||
|
||||
.. method:: get_matchup_ids()
|
||||
|
||||
:rtype: list of strings
|
||||
|
||||
Return the tournament's matchup ids.
|
||||
|
||||
.. method:: get_matchup(matchup_id)
|
||||
|
||||
:rtype: :class:`Matchup_description`
|
||||
|
||||
Describe the matchup with the specified id.
|
||||
|
||||
.. method:: get_matchups()
|
||||
|
||||
:rtype: map *matchup id* → :class:`Matchup_description`
|
||||
|
||||
Describe all matchups.
|
||||
|
||||
.. method:: get_matchup_stats(matchup_id)
|
||||
|
||||
:rtype: :class:`Matchup_stats` object
|
||||
|
||||
Return statistics for the matchup with the specified id.
|
||||
|
||||
.. method:: get_matchup_results(matchup_id)
|
||||
|
||||
:rtype: list of :class:`~.Game_result` objects
|
||||
|
||||
Return the individual game results for the matchup with the specified id.
|
||||
|
||||
The list is in unspecified order (in particular, the colours don't
|
||||
necessarily alternate, even if :attr:`~Matchup_description.alternating`
|
||||
is ``True`` for the matchup).
|
||||
|
||||
:ref:`void games` do not appear in these results.
|
||||
|
||||
|
||||
Matchup_description objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. class:: Matchup_description
|
||||
|
||||
A Matchup_description describes a series of games which had the same
|
||||
players and settings. The information comes from the current contents of
|
||||
the tournament's control file.
|
||||
|
||||
Matchup_descriptions are normally retrieved from
|
||||
:class:`Tournament_results` objects.
|
||||
|
||||
Matchup_descriptions have the following attributes (which should be treated
|
||||
as read-only):
|
||||
|
||||
.. attribute:: id
|
||||
|
||||
The :ref:`matchup id <matchup id>` (a string, usually 1 to 3 characters).
|
||||
|
||||
.. attribute:: player_1
|
||||
player_2
|
||||
|
||||
The :ref:`player codes <player codes>` of the two players. These are
|
||||
never equal.
|
||||
|
||||
.. attribute:: name
|
||||
|
||||
String describing the matchup (eg ``'xxx v yyy'``).
|
||||
|
||||
.. attribute:: board_size
|
||||
|
||||
Integer (eg ``19``).
|
||||
|
||||
.. attribute:: komi
|
||||
|
||||
Float (eg ``7.0``).
|
||||
|
||||
.. attribute:: alternating
|
||||
|
||||
Bool. If this is ``False``, :attr:`player_1` played black and
|
||||
:attr:`player_2` played white; otherwise they alternated.
|
||||
|
||||
.. attribute:: handicap
|
||||
|
||||
Integer or ``None``.
|
||||
|
||||
.. attribute:: handicap_style
|
||||
|
||||
String: ``'fixed'`` or ``'free'``.
|
||||
|
||||
.. attribute:: move_limit
|
||||
|
||||
Integer or ``None``. See :ref:`playing games`.
|
||||
|
||||
.. attribute:: scorer
|
||||
|
||||
String: ``'internal'`` or ``'players'``. See :ref:`scoring`.
|
||||
|
||||
.. attribute:: number_of_games
|
||||
|
||||
Integer or ``None``. This is the number of games requested in the
|
||||
control file; it may not match the number of game results that are
|
||||
available.
|
||||
|
||||
|
||||
Matchup_descriptions support the following method:
|
||||
|
||||
.. method:: describe_details()
|
||||
|
||||
:rtype: string
|
||||
|
||||
Return a text description of the matchup's game settings.
|
||||
|
||||
This covers the most important game settings which can't be observed in
|
||||
the results table (board size, handicap, and komi).
|
||||
|
||||
|
||||
Matchup_stats objects
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. class:: Matchup_stats
|
||||
|
||||
A Matchup_stats object provides basic summary information for a matchup.
|
||||
The information comes from the tournament's :ref:`state file <competition
|
||||
state>`.
|
||||
|
||||
Matchup_stats objects are normally retrieved from
|
||||
:class:`Tournament_results` objects.
|
||||
|
||||
Matchup_stats objects have the following attributes (which should be
|
||||
treated as read-only):
|
||||
|
||||
.. attribute:: player_1
|
||||
player_2
|
||||
|
||||
The :ref:`player codes <player codes>` of the two players. These are
|
||||
never equal.
|
||||
|
||||
.. attribute:: total
|
||||
|
||||
Integer. The number of games played in the matchup.
|
||||
|
||||
.. attribute:: wins_1
|
||||
wins_2
|
||||
|
||||
Integer. The number of games won by each player.
|
||||
|
||||
.. attribute:: forfeits_1
|
||||
forfeits_2
|
||||
|
||||
Integer. The number of games in which each player lost by forfeit.
|
||||
|
||||
.. attribute:: unknown
|
||||
|
||||
Integer. The number of games whose result is unknown.
|
||||
|
||||
.. attribute:: average_time_1
|
||||
average_time_2
|
||||
|
||||
float or ``None``. The average CPU time taken by each player.
|
||||
|
||||
If CPU times are available for only some games, the average is taken
|
||||
over the games for which they are available. If they aren't available
|
||||
for any games, the average is given as ``None``. See :ref:`cpu time`
|
||||
for notes on how CPU times are obtained.
|
||||
|
||||
.. attribute:: played_1b
|
||||
played_2b
|
||||
|
||||
Integer. The number of games in which each player took Black.
|
||||
|
||||
.. attribute:: played_1w
|
||||
played_2w
|
||||
|
||||
Integer. The number of games in which each player took White.
|
||||
|
||||
.. attribute:: alternating
|
||||
|
||||
Bool. This is true if each player played at least one game as Black and
|
||||
at least one game as White.
|
||||
|
||||
This doesn't always equal the :attr:`~Matchup_description.alternating`
|
||||
attribute from the corresponding :class:`Matchup_description` object (in
|
||||
particular, if only one game was played in the matchup, it will always
|
||||
be ``False``).
|
||||
|
||||
If :attr:`alternating` is ``True``, the following attributes are also
|
||||
available:
|
||||
|
||||
.. attribute:: wins_b
|
||||
|
||||
Integer. The number of games in which Black won.
|
||||
|
||||
.. attribute:: wins_w
|
||||
|
||||
Integer. The number of games in which White won.
|
||||
|
||||
.. attribute:: wins_1b
|
||||
wins_2b
|
||||
|
||||
Integer. The number of games in which each player won with Black.
|
||||
|
||||
.. attribute:: wins_1w
|
||||
wins_2w
|
||||
|
||||
Integer. The number of games in which each player won with White.
|
||||
|
||||
|
||||
If :attr:`alternating` is ``False``, the following attributes are also
|
||||
available:
|
||||
|
||||
.. attribute:: colour_1
|
||||
colour_2
|
||||
|
||||
The *colour* taken by each player.
|
||||
|
||||
|
||||
.. currentmodule:: gomill.gtp_games
|
||||
|
||||
Game_result objects
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. class:: Game_result
|
||||
|
||||
A Game_result contains the information recorded for an individual game. The
|
||||
information comes from the tournament's :ref:`state file <competition
|
||||
state>`.
|
||||
|
||||
.. note:: If an |sgf| :ref:`game record <game records>` has been written
|
||||
for the game, you can retrieve its location in the filesystem from a
|
||||
:class:`!Ringmaster` object using
|
||||
:samp:`ringmaster.get_sgf_pathname({game_id})`.
|
||||
|
||||
The :ref:`player codes <player codes>` used here are the same as the ones
|
||||
in the corresponding :class:`.Matchup_description`'s
|
||||
:attr:`~.Matchup_description.player_1` and
|
||||
:attr:`~.Matchup_description.player_2` attributes.
|
||||
|
||||
See :ref:`playing games` and :ref:`details of scoring` for an explanation
|
||||
of the possible game results. Games with unknown result can be
|
||||
distinguished as having :attr:`winning_player` ``None`` but :attr:`is_jigo`
|
||||
``False``.
|
||||
|
||||
Game_results can be retrieved from
|
||||
:class:`.Tournament_results` objects.
|
||||
|
||||
Game_results have the following attributes (which should be treated as
|
||||
read-only):
|
||||
|
||||
.. attribute:: game_id
|
||||
|
||||
Short string uniquely identifying the game within the tournament. See
|
||||
:ref:`game id`.
|
||||
|
||||
.. Game_results returned via Tournament_results always have game_id set,
|
||||
so documenting it that way here.
|
||||
|
||||
.. attribute:: players
|
||||
|
||||
Map *colour* → :ref:`player code <player codes>`.
|
||||
|
||||
.. attribute:: player_b
|
||||
|
||||
:ref:`player code <player codes>` of the Black player.
|
||||
|
||||
.. attribute:: player_w
|
||||
|
||||
:ref:`player code <player codes>` of the White player.
|
||||
|
||||
.. attribute:: winning_player
|
||||
|
||||
:ref:`player code <player codes>` or ``None``.
|
||||
|
||||
.. attribute:: losing_player
|
||||
|
||||
:ref:`player code <player codes>` or ``None``.
|
||||
|
||||
.. attribute:: winning_colour
|
||||
|
||||
*colour* or ``None``.
|
||||
|
||||
.. attribute:: losing_colour
|
||||
|
||||
*colour* or ``None``.
|
||||
|
||||
.. attribute:: is_jigo
|
||||
|
||||
Bool: ``True`` if the game was a :term:`jigo`.
|
||||
|
||||
.. attribute:: is_forfeit
|
||||
|
||||
Bool: ``True`` if one of the players lost the game by forfeit; see
|
||||
:ref:`playing games`.
|
||||
|
||||
.. attribute:: sgf_result
|
||||
|
||||
String describing the game's result. This is in the format used for the
|
||||
:term:`SGF` ``RE`` property (eg ``'B+1.5'``).
|
||||
|
||||
.. attribute:: detail
|
||||
|
||||
Additional information about the game result (string or ``None``).
|
||||
|
||||
This is present (not ``None``) for those game results which are not wins
|
||||
on points, jigos, or wins by resignation.
|
||||
|
||||
.. (leaving cpu_times undocumented, as I don't want to say it's stable)
|
||||
|
||||
.. attribute:: cpu_times
|
||||
|
||||
Map :ref:`player code <player codes>` → *time*.
|
||||
|
||||
The time is a float representing a number of seconds, or ``None`` if
|
||||
time is not available, or ``'?'`` if :gtp:`gomill-cpu_time` is
|
||||
implemented but returned a failure response.
|
||||
|
||||
See :ref:`cpu time` for more details.
|
||||
|
||||
|
||||
Game_results support the following method:
|
||||
|
||||
.. method:: describe()
|
||||
|
||||
:rtype: string
|
||||
|
||||
Return a short human-readable description of the result.
|
||||
|
||||
For example, ``'xxx beat yyy (W+2.5)'``.
|
||||
|
||||
|
||||
.. currentmodule:: tournament_results
|
||||
|
||||
.. _using_the_api_in_scripts:
|
||||
|
||||
Using the API in scripts
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To write a standalone script using the tournaments results API, obtain a
|
||||
:class:`.Tournament_results` object from a :class:`!Ringmaster` object as
|
||||
follows::
|
||||
|
||||
from gomill import ringmasters
|
||||
ringmaster = ringmasters.Ringmaster(control_file_pathname)
|
||||
ringmaster.load_status()
|
||||
tournament_results = ringmaster.tournament_results()
|
||||
|
||||
All of these calls report problems by raising the :exc:`!RingmasterError`
|
||||
exception defined in the :mod:`!ringmasters` module.
|
||||
|
||||
See the :script:`find_forfeits.py` example script for a more fleshed-out
|
||||
example.
|
||||
|
Reference in New Issue
Block a user