Initial commit of GNU Go v3.8.
[sgk-go] / doc / move_generation.texi
@menu
* Move generation Intro:: Introduction.
* Move Reasons:: Generation of move reasons.
* Move Reason Details:: Detailed Descriptions of Move Reasons
* Valuation:: Valuating the moves
* End Game:: Endgame move generation
@end menu
@node Move generation Intro
@section Introduction
GNU Go 3.0 introduced a move generation scheme substantially different
from earlier versions. In particular, it was different from the method of move
generation in GNU Go 2.6.
In the old scheme, various move generators suggested different moves with
attached values. The highest such value then decided the move. There were two
important drawbacks with this scheme:
@itemize @bullet
@item
Efficient multipurpose moves could only be found by patterns which
explicitly looked for certain combinations, such as a simultaneous
connection and cut. There was also no good way to e.g. choose among
several attacking moves.
@item
The absolute move values were increasingly becoming harder to tune with
the increasing number of patterns. They were also fairly subjective and
the tuning could easily break in unexpected ways when something changed,
e.g. the worm valuation.
@end itemize
The basic idea of the new move generation scheme is that the various
move generators suggest reasons for moves, e.g. that a move captures
something or connects two strings, and so on. When all reasons for the
different moves have been found, the valuation starts. The primary
advantages are
@itemize @bullet
@item
The move reasons are objective, in contrast to the move values in
the old scheme. Anyone can verify whether a suggested move reason is
correct.
@item
The centralized move valuation makes tuning easier. It also allows
for style dependent tuning, e.g. how much to value influence
compared to territory. Another possibility is to increase the value
of safe moves in a winning position.
@end itemize
@node Move Reasons
@section Generation of move reasons
@cindex move reasons
Each move generator suggests a number of moves. It justifies each move
suggestion with one or move @dfn{move reasons}. These move reasons
are collected at each intersection where the moves are suggested for
later valuation. Here is a partial list of of move reasons considered by GNU
Go. (The complete list may be found in @file{move_reasons.h}.)
@table @code
@item ATTACK_MOVE
@itemx DEFEND_MOVE
Attack or defend a worm.
@item ATTACK_THREAT_MOVE
@itemx DEFEND_THREAT_MOVE
Threaten to attack or defend a worm.
@item EITHER_MOVE
A move that either achieves one goal or another (at the moment this only
used for attacks on worms).
@item ALL_MOVE
At the moment this is used for a move that defends two worms threatened
by a double attack.
@item CONNECT_MOVE
@itemx CUT_MOVE
Connect or cut two worms.
@item ANTISUJI_MOVE
Declare an antisuji or forbidden move.
@item SEMEAI_MOVE
@itemx SEMEAI_THREAT
Win or threaten to win a semeai.
@item EXPAND_TERRITORY_MOVE
@item EXPAND_MOYO_MOVE
Move expanding our territory/moyo. These reasons are at the moment
treated identically.
@item VITAL_EYE_MOVE
A vital point for life and death.
@item STRATEGIC_ATTACK_MOVE
@itemx STRATEGIC_DEFEND_MOVE
Moves added by 'a' and 'd' class patterns (@pxref{Pattern Classification})
which (perhaps intangibly) attack or defend a dragon.
@item OWL_ATTACK_MOVE
@itemx OWL_DEFEND_MOVE
An owl attack or defense move.
@item OWL_ATTACK_THREAT
@itemx OWL_DEFEND_THREAT
A threat to owl attack or defend a group.
@item OWL_PREVENT_THREAT
A move to remove an owl threat.
@item UNCERTAIN_OWL_ATTACK
@itemx UNCERTAIN_OWL_DEFENSE
An uncertain owl attack or defense. This means that the owl code could
not decide the outcome, because the owl node limit was reached.
@item MY_ATARI_ATARI_MOVE
A move that starts a chain of ataris, eventually leading to a
capture.
@item YOUR_ATARI_ATARI_MOVE
A move that if played by the opponent starts a chain of ataris for the
opponent, leading to capture, which is also a safe move for us. Preemptively
playing such a move almost always defends the threat.
@end table
The attack and defend move types can have a suffix to denote moves whose
result depends on a ko, e.g. @code{OWL_ATTACK_MOVE_GOOD_KO}. Here
@code{..._GOOD_KO} and @code{..._BAD_KO} correspond to @code{KO_A} and
@code{KO_B} as explained in @ref{Ko}.
See @file{engine/move_reasons.h} for the full of move reasons.
@strong{NOTICE:} Some of these are reasons for @strong{not} playing a move.
More detailed discussion of these move reasons will be found in the
next section.
@node Move Reason Details
@section Detailed Descriptions of various Move Reasons
@menu
* Attack and Defense:: Worm Attack and Defense
* Threats to Attack or Defend:: Worm Threats
* Multi Attack or Defense:: Combined Attacks and Defenses
* Cutting and Connecting:: Cutting and Connecting moves
* Semeai:: Semeai winning moves
* Making eyes:: Vital eye moves
* Antisuji moves:: Never play these!
* Territorial moves:: Block or expand territory
* Owl attack and defense:: Owl Attack and Defense
* Combination Attacks:: Coordinated threats such as double ataris
@end menu
@node Attack and Defense
@subsection Attacking and defending moves
A move which tactically captures a worm is called an @dfn{attack move} and a
move which saves a worm from being tactically captured is called a
@dfn{defense move}. It is understood that a defense move can only exist if
the worm can be captured, and that a worm without defense only is
attacked by moves that decrease the liberty count or perform necessary
backfilling.
It is important that all moves which attack or defend a certain string
are found, so that the move generation can make an informed choice
about how to perform a capture, or find moves which capture and/or
defend several worms.
Attacking and defending moves are first found in @code{make_worms} while it
evaluates the tactical status of all worms, although this step only
gives one attack and defense (if any) move per worm. Immediately
after, still in @code{make_worms}, all liberties of the attacked worms are
tested for additional attack and defense moves. More indirect moves
are found by @code{find_attack_patterns} and @code{find_defense_patterns},
which match the A (attack) and D (defense) class patterns in
@file{patterns/attack.db} and @file{patterns/defense.db} As a final step, all
moves which fill some purpose at all are tested whether they additionally
attacks or defends some worm. (Only unstable worms are analyzed.)
@node Threats to Attack or Defend
@subsection Threats to Attack or Defend
A threat to attack a worm, but where the worm can be defended is used as
a secondary move reason. This move reason can enhance the value of a
move so that it becomes sente. A threatening move without any other
justification can also be used as a ko threat. The same is true for a
move that threatens defense of a worm, but where the worm can still be
captured if the attacker doesn't tenuki.
Threats found by the owl code are called @strong{owl threats} and they
have their own owl reasons.
@node Multi Attack or Defense
@subsection Multiple attack or defense moves
Sometimes a move attacks at least one of a number of worms or
simultaneously defends all of several worms. These moves are noted
by their own move reasons.
@node Cutting and Connecting
@subsection Cutting and connecting moves
Moves which connect two distinct dragons are called @code{connecting moves}.
Moves which prevent such connections are called @dfn{cutting moves}. Cutting
and connecting moves are primarily found by pattern matching, the @code{C}
and @code{B} class patterns.
A second source of cutting and connecting moves comes from the attack
and defense of cutting stones. A move which attacks a worm
automatically counts as a connecting move if there are multiple
dragons adjacent to the attacked worm. Similarly a defending move
counts as a cutting move. The action taken when a pattern of
this type is found is to induce a connect or cut move reason.
When a cut or connect move reason is registered, the involved dragons
are of course stored. Thus the same move may cut and/or connect
several pairs of dragons.
@node Semeai
@subsection Semeai winning moves
A move which is necessary to win a capturing race is called a @dfn{semeai
move}. These are similar to attacking moves, except that they involve
the simultaneous attack of one worm and the defense of another. As for
attack and defense moves, it's important that all moves which win a
semeai are found, so an informed choice can be made between them.
Semeai move reasons should be set by the semeai module. However this
has not been implemented yet. One might also wish to list moves
which increase the lead in a semeai race (removes ko threats) for use
as secondary move reasons. Analogously if we are behind in the race.
@node Making eyes
@subsection Making or destroying eyes
A move which makes a difference in the number of eyes produced from an
eye space is called an @dfn{eye move}. It's not necessary that the eye is
critical for the life and death of the dragon in question, although it
will be valued substantially higher if this is the case. As usual it's
important to find all moves that change the eye count.
(This is part of what eye_finder was doing. Currently it only finds
one vital point for each unstable eye space.)
@node Antisuji moves
@subsection Antisuji moves
Moves which are locally inferior or for some other reason must not be
played are called @dfn{antisuji moves}. These moves are generated by pattern
matching. Care must be taken with this move reason as the move under
no circumstances will be played.
@node Territorial moves
@subsection Territorial moves
Any move that increases territory gets a move reason. This is the expand
territory move reason. That move reason is added by the @samp{e}
patterns in @file{patterns/patterns.db}. Similarly the @samp{E} patterns
attempt to generate or mitigate a moyo, which is a region of influence
not yet secure territory, yet valuable. Such a pattern sets the ``expand
moyo'' move reason.
@node Owl attack and defense
@subsection Attacking and Defending Dragons
@findex owl_reasons
Just as the tactical reading code tries to determine when a worm
can be attacked or defended, the owl code tries to determine
when a dragon can get two eyes and live. The function @code{owl_reasons()}
generates the corresponding move reasons.
The owl attack and owl defense move reasons are self explanatory.
The owl attack threat reason is generated if owl attack on an
opponent's dragon fails but the owl code determines that the
dragon can be killed with two consecutive moves. The killing
moves are stored in @code{dragon[pos].owl_attack_point}
and @code{dragon[pos].owl_second_attack_point}.
Similarly if a friendly dragon is dead but two moves can revive it,
an owl defense threat move reason is generated.
The prevent threat reasons are similar but with the colors
reversed: if the opponent has an attack threat move then a
move which removes the threat gets a prevent threat move
reason.
The owl uncertain move reasons are generated when the owl
code runs out of nodes. In order to prevent the owl code from
running too long, a cap is put on the number of nodes one owl
read can generate. If this is exceeded, the reading is cut
short and the result is cached as usual, but marked uncertain.
In this case an owl uncertain move reason may be generated.
For example, if the owl code finds the dragon alive but is
unsure, a move to defend may still be generated.
@node Combination Attacks
@subsection Combination Attacks
@findex atari_atari
The function @code{atari_atari} tries to find a sequence of ataris
culminating in an unexpected change of status of any opponent string,
from @code{ALIVE} to @code{CRITICAL}. Once such a sequence of ataris
is found, it tries to shorten it by rejecting irrelevant moves.
@node Valuation
@section Valuation of suggested moves
@findex value_move_reasons()
At the end of the move generation process, the function
@code{value_move_reasons()} tries to assign values to the
moves for the purpose of selecting the best move. The
single purpose of the move valuation is to try to rank
the moves so that the best move gets the highest
score. In principle these values could be arbitrary,
but in order to make it easier to evaluate how well the
valuation performs, not to mention simplify the tuning,
we try to assign values which are consistent with the
usual methods of counting used by human Go players,
as explained for example in @emph{The Endgame} by Ogawa
and Davies.
Moves are valued with respect to four different criteria. These are
@itemize @bullet
@item territorial value
@item strategical value
@item shape value,
@item secondary value.
@end itemize
All of these are floats and should be measured in terms of actual
points.
The territorial value is the total change of expected territory caused
by this move. This includes changes in the status of groups if the move
is an attack or a defense move.
Beginning with GNU Go 3.0, the influence function plays an important role
in estimating territory (@pxref{Influence and Territory}). It is used
to make a guess at each intersection how likely it is that it will become
black or white territory. The territorial value sums up the changes
in these valuations.
Strategical value is a measure of the effect the move has on the
safety of all groups on the board. Typically cutting and connecting
moves have their main value here. Also edge extensions, enclosing
moves and moves towards the center have high strategical value. The
strategical value should be the sum of a fraction of the territorial
value of the involved dragons. The fraction is determined by the
change in safety of the dragon.
Shape value is a purely local shape analysis. An
important role of this measure is to offset mistakes made by the
estimation of territorial values. In open positions it's
often worth sacrificing a few points of (apparent) immediate profit to
make good shape. Shape value is implemented by pattern matching, the
Shape patterns.
Secondary value is given for move reasons which by themselves are not
sufficient to play the move. One example is to reduce the number of
eyes for a dragon that has several or to attack a defenseless worm.
When all these values have been computed, they are summed, possibly
weighted (secondary value should definitely have a small weight), into
a final move value. This value is used to decide the move.
@menu
* Territorial value:: How much territory does a move gain
* Strategical value:: Strategical gains from a move
* Shape factor:: Local shape
* Minimum Value:: Minimum value
* Secondary Value:: Other, more indirect, gains from a move
* Threats and Followup Value:: Valuation of attack and defense threats
@end menu
@node Territorial value
@subsection Territorial Value
@findex estimate_territorial_value
The algorithm for computing territorial value is in the function
@code{estimate_territorial_value}. As the name suggests, it seeks
to estimate the change in territory.
It considers all groups that are changed from alive to death or vice-versa
due to this move. Also, it makes an assumption whether the move should be
considered safe. If so, the influence module is called: The function
@code{influence_delta_territory} estimates the territorial effect of
both the stone played and of the changes of group status'.
The result returned by the influence module is subject to a number of
corrections. This is because some move reasons cannot be evaluated by a
single call to the influence function, such as moves depending on a ko.
@node Strategical value
@subsection Strategical Value
Strategical defense or attack reasons are assigned to any move
which matches a pattern of type @samp{a} or @samp{d}. These are
moves which in some (often intangible) way tend to help
strengthen or weaken a dragon. Of course strengthening a
dragon which is already alive should not be given much value,
but when the move reason is generated it is not necessary
to check its status or safety. This is done later, during
the valuation phase.
@node Shape factor
@subsection Shape Factor
In the value field of a pattern (@pxref{Pattern Values}) one may
specify a shape value.
This is used to compute the shape factor, which multiplies the
score of a move. We take the largest positive contribution to
shape and add 1 for each additional positive contribution
found. Then we take the largest negative contribution to
shape, and add 1 for each additional negative contribution. The
resulting number is raised to the power 1.05 to obtain the
shape factor.
The rationale behind this complicated scheme is that every
shape point is very significant. If two shape contributions
with values (say) 5 and 3 are found, the second contribution
should be devalued to 1. Otherwise the engine is too difficult
to tune since finding multiple contributions to shape can cause
significant overvaluing of a move.
@node Minimum Value
@subsection Minimum Value
A pattern may assign a minimum (and sometimes also a maximum)
value. For example the Joseki patterns have values which are
prescribed in this way, or ones with a @code{value} field.
One prefers not to use this approach but in practice it is
sometimes needed.
In the fuseki, there are often several moves with identical minimum
value. GNU Go chooses randomly between such moves, which ensures
some indeterminacy of GNU Go's play. Later in the game, GNU Go's
genuine valuation of such a move is used as a secondary criterion.
@node Secondary Value
@subsection Secondary Value
Secondary move reasons are weighed very slightly. Such a move
can tip the scales if all other factors are equal.
@node Threats and Followup Value
@subsection Threats and Followup Value
Followup value refers to value which may acrue if we get two
moves in a row in a local area. It is assigned for moves that threaten
to attack or defend a worm or dragon. Also, since GNU Go 3.2 the influence
module makes an assessment of the possible purely territorial followup
moves. In cases where these two heuristics are not sufficient we
add patterns with a @code{followup_value} autohelper macro.
Usually, the followup value gives only a small contribution; e.g. if
it the followup value is very large, then GNU Go treats the move as sente by
doubling its value. However, if the largest move on the board is a ko
which we cannot legally take, then such a move becomes attractive as a ko
threat and the full followup value is taken into account.
@node End Game
@section End Game
Endgame moves are generated just like any other move by GNU Go. In fact,
the concept of endgame does not exist explicitly, but if the largest
move initially found is worth 6 points or less, an extra set of patterns
in @file{endgame.db} is matched and the move valuation is redone.