Initial commit of GNU Go v3.8.
[sgk-go] / engine / unconditional.c
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
* http://www.gnu.org/software/gnugo/ for more information. *
* *
* Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
* 2008 and 2009 by the Free Software Foundation. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation - version 3 or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License in file COPYING for more details. *
* *
* You should have received a copy of the GNU General Public *
* License along with this program; if not, write to the Free *
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02111, USA. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "gnugo.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "liberty.h"
/* Capture as many strings of the given color as we can. Played stones
* are left on the board and the number of played stones is returned.
* Strings marked in the exceptions array are excluded from capturing
* attempts. If all non-excepted strings are successfully captured,
* *none_invincible is set to one. Set none_invincible to NULL if you
* don't need that information.
*/
static int
capture_non_invincible_strings(int color, int exceptions[BOARDMAX],
int *none_invincible)
{
int other = OTHER_COLOR(color);
int something_captured = 1; /* To get into the first turn of the loop. */
int string_found = 0;
int moves_played = 0;
int save_moves;
int libs[MAXLIBS];
int liberties;
int pos;
int k;
while (something_captured) {
/* Nothing captured so far in this turn of the loop. */
something_captured = 0;
/* Is there something left to try to capture? */
string_found = 0;
/* Visit all friendly strings on the board. */
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
if (board[pos] != color || find_origin(pos) != pos)
continue;
if (exceptions && exceptions[pos])
continue;
string_found = 1;
/* Try to capture the string at pos. */
liberties = findlib(pos, MAXLIBS, libs);
save_moves = moves_played;
for (k = 0; k < liberties; k++) {
if (trymove(libs[k], other, "unconditional_life", pos))
moves_played++;
}
/* Successful if already captured or a single liberty remains.
* Otherwise we must rewind and take back the last batch of moves.
*/
if (board[pos] == EMPTY)
something_captured = 1;
else if (findlib(pos, 2, libs) == 1) {
/* Need to use tryko as a defense against the extreme case
* when the only opponent liberty that is not suicide is an
* illegal ko capture, like in this 5x5 position:
* +-----+
* |.XO.O|
* |XXOO.|
* |X.XOO|
* |XXOO.|
* |.XO.O|
* +-----+
*/
int success = tryko(libs[0], other, "unconditional_life");
gg_assert(success);
moves_played++;
something_captured = 1;
}
else
while (moves_played > save_moves) {
popgo();
moves_played--;
}
}
}
if (none_invincible)
*none_invincible = !string_found;
return moves_played;
}
/* Find those worms of the given color that can never be captured,
* even if the opponent is allowed an arbitrary number of consecutive
* moves. The coordinates of the origins of these worms are written to
* the worm arrays and the number of non-capturable worms is
* returned.
*
* The algorithm is to cycle through the worms until none remains or
* no more can be captured. A worm is removed when it is found to be
* capturable, by letting the opponent try to play on all its
* liberties. If the attack fails, the moves are undone. When no more
* worm can be removed in this way, the remaining ones are
* unconditionally alive.
*
* After this, unconditionally dead opponent worms and unconditional
* territory are identified. This is almost, but only almost,
* straightforward. We first present a simple but only almost correct
* solution, then show how to patch up its deficiencies.
*
* - - - - - - -
*
* Algorithm 1, simple but slightly incorrect.
*
* To find unconditionally dead opponent worms and unconditional
* territory, we continue from the position obtained at the end of the
* previous operation (only unconditionally alive strings remain for
* color) with the following steps:
*
* 1. Play opponent stones on all liberties of the unconditionally
* alive strings except where illegal. (That the move order may
* determine exactly which liberties can be played legally is not
* important. Just pick an arbitrary order).
* 2. Recursively extend opponent strings in atari, except where this
* would be suicide.
* 3. Play an opponent stone anywhere it can get two empty
* neighbors. (I.e. split big eyes into small ones).
* 4. Play an opponent stone anywhere it can get one empty
* neighbor. (I.e. reduce two space eyes to one space eyes.)
*
* Remaining opponent strings in atari and remaining liberties of the
* unconditionally alive strings constitute the unconditional
* territory.
*
* Opponent strings from the initial position placed on
* unconditional territory are unconditionally dead.
*
* - - - - - - -
*
* The deficiency with this algorithm is that a certain class of sekis
* are considered as dead, e.g. this position:
*
* .OOOOO.
* OOXXXOO
* OXX.XXO
* OX.O.XO
* OX.O.XO
* OXX.XXO
* OOXXXOO
* .OOOOO.
*
* The problem is that while removing the two O stones, X is reduced
* to a single small eye. Still O cannot capture these stones under
* alternating play since the eyespace is too big.
*
* Before discussing this seki further we make a preliminary
* modification of the algorithm.
*
* - - - - - - -
*
* Algorithm 2. More complex but still slightly incorrect algorithm:
*
* 1. Run algorithm 1.
* 2. Return to the original position.
* 3. Capture all capturable O strings which according to algorithm 1
* do not belong to unconditional territory.
* 4. Play opponent stones on all liberties of the unconditionally
* alive strings except where illegal. (That the move order may
* determine exactly which liberties can be played legally is not
* important. Just pick an arbitrary order).
* 5. Recursively extend opponent strings in atari, except where this
* would be suicide.
* 6. Capture all remaining capturable O strings.
* 7. Repeat 4 and 5 once.
* 8. Play an opponent stone anywhere it can get two empty
* neighbors. (I.e. split big eyes into small ones).
* 9. Play an opponent stone anywhere it can get one empty
* neighbor. (I.e. reduce two space eyes to one space eyes.)
*
* Remaining opponent strings in atari and remaining liberties of the
* unconditionally alive strings constitute the unconditional
* territory.
*
* Opponent strings from the initial position placed on
* unconditional territory are unconditionally dead.
*
* - - - - - - -
*
* We can observe that, after step 5, an X group with at least two
* distinct eyespaces would not risk being reduced to a single small
* eye. Similarly an X group with a capturable O string of size at
* least three would allow the formation of two distinct small eyes
* after being captured. Thus it is easy to see that the only X groups
* which would live in seki but could not be transformed into
* unconditionally alive groups would have a single eyespace with a
* capturable O string of size at most 2. Furthermore the eyespace
* would not be possible to subdivide. Then if the capturable string
* would be of size 1 it would in all cases form a nakade and we would
* not have a seki. The plausible seki positions would all be
* reducable to the following eyeshape:
*
* .OOOOO.
* OOXXXO.
* OXX.XOO
* OX.OXXO
* OXXO.XO
* OOX.XXO
* .OXXXOO
* .OOOOO.
*
* The remaining question is what effects cutting points in the X
* group would have. For example these X groups are dead:
*
* .OOOOO. .OOOOO. .OOOOO. .OOOOO. ..OOOO. ..OOOO.
* .OXXXO. .OXXXO. .OXXXO. .OXXXO. OOOXXO. OOOXXO.
* OOX.XO. OOX.XOO OOX.XOO OOX.XOO OXX.XO. OXX.XOO
* OX.OXOO OX.OXXO OX.OXXO OX.OXXO OX.OXOO OX.OXXO
* OXXO.XO OXXO.XO OXXO.XO OXXO.XO OXXO.XO OXXO.XO
* OOX.XXO OOX.XOO OOX.XXO OOX.XXO OOX.XXO OOX.XXO
* .OXXXOO .OXXXO. .OXXOOO .OOXXOO .OXXXOO .OXXOOO
* .OOOOO. .OOOOO. .OOOO.. ..OOOO. .OOOOO. .OOOO..
*
* while these are alive in seki
*
* ..OOOO. .OOOO.. .OOOO.. ..OOOO. ..OOOO.
* OOOXXO. .OXXOO. OOXXOO. .OOXXO. OOOXXO.
* OXX.XOO OOX.XOO OXX.XOO OOX.XOO OXX.XOO
* OX.OXXO OX.OXXO OX.OXXO OX.OXXO OX.OXXO
* OXXO.XO OXXO.XO OOXO.XO OXXO.XO OOXO.XO
* OOX.XXO OOX.XXO .OX.XXO OOX.XXO .OX.XXO
* .OXXXOO .OXXXOO .OXXOOO .OXXXOO .OXXXOO
* .OOOOO. .OOOOO. .OOOO.. ..OOOO. .OOOOO.
*
* The critical distinction between the dead ones and the seki ones is
* that the stones marked a and b below,
*
* .OOOOO.
* OOXXXO.
* OXX.XOO
* OX.ObXO
* OXaO.XO
* OOX.XXO
* .OXXXOO
* .OOOOO.
*
* belong to different strings for the dead groups and to the same
* string for the seki groups.
*
* The trick to avoid misclassifying areas where the opponent can form
* a seki group but not an invincible group as unconditional territory
* is thus to detect the formation above and add a third stone to the
* O group before the capturing in step 6 above.
*
* This leads to the final algorithm.
*
* - - - - - - -
*
* Algorithm 3. Final and correct algorithm:
*
* 1. Run algorithm 1.
* 2. Return to the original position.
* 3. Capture all capturable O strings which according to algorithm 1
* do not belong to unconditional territory.
* 4. Play opponent stones on all liberties of the unconditionally
* alive strings except where illegal. (That the move order may
* determine exactly which liberties can be played legally is not
* important. Just pick an arbitrary order).
* 5. Recursively extend opponent strings in atari, except where this
* would be suicide.
* 6. Identify eyespaces of the kind described above and extend any
* matching two-stone string with a third stone.
* 7. Capture all remaining capturable O strings.
* 8. Repeat 4 and 5 once.
* 9. Play an opponent stone anywhere it can get two empty
* neighbors. (I.e. split big eyes into small ones).
* 10. Play an opponent stone anywhere it can get one empty
* neighbor. (I.e. reduce two space eyes to one space eyes.)
*
* Remaining opponent strings in atari and remaining liberties of the
* unconditionally alive strings constitute the unconditional
* territory.
*
* Opponent strings from the initial position placed on
* unconditional territory are unconditionally dead.
*
* - - - - - - -
*
* On return, unconditional_territory[][] is 1 where color has
* unconditionally alive stones, 2 where it has unconditional
* territory, and 0 otherwise.
*/
void
unconditional_life(int unconditional_territory[BOARDMAX], int color)
{
int found_one;
int other = OTHER_COLOR(color);
int libs[MAXLIBS];
int liberties;
int pos;
int k, r;
int moves_played;
int potential_sekis[BOARDMAX];
int none_invincible;
/* Initialize unconditional_territory array. */
memset(unconditional_territory, 0,
sizeof(unconditional_territory[0]) * BOARDMAX);
/* Find isolated two-stone strings which might be involved in the
* kind of seki described in the comments.
*/
memset(potential_sekis, 0, sizeof(potential_sekis));
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
int isolated = 1;
int stones[2];
int pos2;
if (board[pos] != color
|| find_origin(pos) != pos
|| countstones(pos) != 2)
continue;
findstones(pos, 2, stones);
for (k = 0; k < 2 && isolated; k++) {
for (r = 0; r < 8 && isolated; r++) {
pos2 = stones[k] + delta[r];
if (!ON_BOARD(pos2)
|| (board[pos2] == color
&& !same_string(pos, pos2)))
isolated = 0;
}
}
if (isolated) {
potential_sekis[stones[0]] = 1;
potential_sekis[stones[1]] = 1;
}
}
moves_played = capture_non_invincible_strings(color, potential_sekis,
&none_invincible);
/* If there are no invincible strings, nothing can be unconditionally
* settled.
*/
if (none_invincible) {
/* Take back all moves. */
while (moves_played > 0) {
popgo();
moves_played--;
}
return;
}
/* The strings still remaining except those marked in
* potential_sekis[] are uncapturable. Now see which opponent
* strings can survive.
*
* 1. Play opponent stones on all liberties of the unconditionally
* alive strings except where illegal.
*/
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
if (board[pos] != color || potential_sekis[pos] || find_origin(pos) != pos)
continue;
/* Play as many liberties as we can. */
liberties = findlib(pos, MAXLIBS, libs);
for (k = 0; k < liberties; k++) {
if (trymove(libs[k], other, "unconditional_life", pos))
moves_played++;
}
}
/* 2. Recursively extend opponent strings in atari, except where this
* would be suicide.
*/
found_one = 1;
while (found_one) {
/* Nothing found so far in this turn of the loop. */
found_one = 0;
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
if (board[pos] != other || countlib(pos) > 1)
continue;
/* Try to extend the string at (m, n). */
findlib(pos, 1, libs);
if (trymove(libs[0], other, "unconditional_life", pos)) {
moves_played++;
found_one = 1;
}
}
}
/* Now see whether there are any significant sekis on the board. */
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
if (!potential_sekis[pos]
|| board[pos] == EMPTY
|| find_origin(pos) != pos)
continue;
for (r = 0; r < 4; r++) {
int up = delta[r];
int right = delta[(r + 1) % 4];
int locally_played_moves = 0;
if (board[pos + up] != color
|| board[pos + up + up] != EMPTY
|| board[pos - up] != EMPTY)
continue;
for (k = 0; k < 2; k++) {
if (k == 1)
right = -right;
if (board[pos + right] != EMPTY || board[pos + up - right] != EMPTY)
continue;
if (board[pos - right] == EMPTY
&& trymove(pos - right, other, "unconditional_life", pos))
locally_played_moves++;
if (board[pos + up + right] == EMPTY
&& trymove(pos + up + right, other, "unconditional_life", pos))
locally_played_moves++;
if (board[pos - right] == other && board[pos + up + right] == other
&& same_string(pos - right, pos + up + right)) {
/* This is a critical seki. Extend the string with one stone
* in an arbitrary direction to break the seki.
*/
while (locally_played_moves > 0) {
popgo();
locally_played_moves--;
}
trymove(pos - up, color, "unconditional_life", pos);
moves_played++;
break;
}
else {
while (locally_played_moves > 0) {
popgo();
locally_played_moves--;
}
}
}
if (countstones(pos) > 2)
break;
}
}
/* Capture the strings involved in potential sekis. */
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
if (!potential_sekis[pos] || board[pos] == EMPTY)
continue;
/* Play as many liberties as we can. */
liberties = findlib(pos, MAXLIBS, libs);
for (k = 0; k < liberties; k++) {
if (trymove(libs[k], other, "unconditional_life", pos))
moves_played++;
}
}
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
int apos;
int bpos;
int aopen, bopen;
int alib, blib;
if (board[pos] != other || countlib(pos) != 2)
continue;
findlib(pos, 2, libs);
apos = libs[0];
bpos = libs[1];
if (abs(I(apos) - I(bpos)) + abs(J(apos) - J(bpos)) != 1)
continue;
/* Only two liberties and these are adjacent. Play one. We want
* to maximize the number of open liberties. In this particular
* situation we can count this with approxlib for the opposite
* color. If the number of open liberties is the same, we
* maximize the total number of obtained liberties.
* Two relevant positions:
*
* |XXX.
* |OOXX |XXXXXXX
* |O.OX |OOXOOOX
* |..OX |..OO.OX
* +---- +-------
*/
aopen = approxlib(apos, color, 4, NULL);
bopen = approxlib(bpos, color, 4, NULL);
alib = approxlib(apos, other, 4, NULL);
blib = approxlib(bpos, other, 4, NULL);
if (aopen > bopen || (aopen == bopen && alib >= blib)) {
trymove(apos, other, "unconditional_life", pos);
moves_played++;
}
else {
trymove(bpos, other, "unconditional_life", pos);
moves_played++;
}
}
/* Identify unconditionally alive stones and unconditional territory. */
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
if (board[pos] == color && !potential_sekis[pos]) {
unconditional_territory[pos] = 1;
if (find_origin(pos) == pos) {
liberties = findlib(pos, MAXLIBS, libs);
for (k = 0; k < liberties; k++)
unconditional_territory[libs[k]] = 2;
}
}
else if (board[pos] == other && countlib(pos) == 1) {
unconditional_territory[pos] = 2;
findlib(pos, 1, libs);
unconditional_territory[libs[0]] = 2;
}
}
/* Take back all moves. */
while (moves_played > 0) {
popgo();
moves_played--;
}
}
/* By unconditional status analysis we can statically find some moves
* which there is never any need to play. Those belong to three
* different categories:
*
* 1. A move on a vertex which is already unconditional territory for
* either color.
* 2. A move which after having been made ends up as unconditional
* territory for the opponent.
* 3. If a move at vertex A makes vertex B become unconditional
* territory, there is no need to consider a move at B, since A has
* all the positive effects that B would have.
*
* Moves in categories 1 and 2 are never any better than passing and
* often worse (with territory scoring always worse). Moves in
* category three can be either better or worse than passing, but it's
* always true that a move at A is at least as good as a move at B.
* Occasionally they are identically good (A makes B unconditional
* territory and B makes A unconditional territory) but there is never
* any need to analyze both.
*
* In meaningless_black_moves[] and meaningless_white_moves[] a value
* of -1 means it is not meaningless, 0 (NO_MOVE) means it belongs to
* category 1 or 2, and a value greater than zero points to the
* preferred move in category 3.
*
* The parameter unconditional_territory should contain the result of
* calling unconditional_life() in the original position. Meaningless
* moves are computed for the given color.
*/
void
find_unconditionally_meaningless_moves(int unconditional_territory[BOARDMAX],
int color)
{
int *meaningless_moves;
int other = OTHER_COLOR(color);
int friendly_unconditional[BOARDMAX];
int opponent_unconditional[BOARDMAX];
int pos;
int pos2;
gg_assert(color == BLACK || color == WHITE);
if (color == BLACK)
meaningless_moves = meaningless_black_moves;
else
meaningless_moves = meaningless_white_moves;
/* Initialize meaningless_moves and detect moves of category 1, but
* only for own unconditional territory.
*
* FIXME: We would save some time by detecting all category 1 moves
* here but then we would need to have the initial unconditional
* territory for the opponent as well. This can of course be done,
* the question is how we get it in the nicest way.
*/
for (pos = BOARDMIN; pos < BOARDMAX; pos++)
if (board[pos] == EMPTY) {
if (unconditional_territory[pos])
meaningless_moves[pos] = NO_MOVE;
else
meaningless_moves[pos] = -1;
}
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
if (board[pos] != EMPTY || meaningless_moves[pos] != -1)
continue;
if (!tryko(pos, color, "find_unconditionally_meaningless_moves"))
continue;
unconditional_life(opponent_unconditional, other);
if (opponent_unconditional[pos]) {
/* Move of category 1 or 2. */
meaningless_moves[pos] = NO_MOVE;
}
else {
unconditional_life(friendly_unconditional, color);
if (friendly_unconditional[pos])
for (pos2 = BOARDMIN; pos2 < BOARDMAX; pos2++)
if (board[pos2] == EMPTY
&& meaningless_moves[pos2] == -1
&& friendly_unconditional[pos2]) {
/* Move of category 3. */
meaningless_moves[pos2] = pos;
}
}
popgo();
}
/* Meaningless moves of category 3 may have been found in multiple
* steps. Normalize to the final replacement move.
*/
for (pos = BOARDMIN; pos < BOARDMAX; pos++)
if (board[pos] == EMPTY && meaningless_moves[pos] > 0)
while (meaningless_moves[meaningless_moves[pos]] > 0)
meaningless_moves[pos] = meaningless_moves[meaningless_moves[pos]];
}
/* Returns 1 if the move at pos by color is meaningless and 0
* otherwise. When it is meaningless, *replacement_move will contain a
* replacing move, which is NO_MOVE if passing is guaranteed to be no
* worse than making the move.
*/
int
unconditionally_meaningless_move(int pos, int color, int *replacement_move)
{
if (color == WHITE && meaningless_white_moves[pos] != -1) {
*replacement_move = meaningless_white_moves[pos];
return 1;
}
if (color == BLACK && meaningless_black_moves[pos] != -1) {
*replacement_move = meaningless_black_moves[pos];
return 1;
}
return 0;
}
void
clear_unconditionally_meaningless_moves()
{
int pos;
for (pos = BOARDMIN; pos < BOARDMAX; pos++)
if (ON_BOARD(pos)) {
meaningless_black_moves[pos] = -1;
meaningless_white_moves[pos] = -1;
}
}
/* Pick up antisuji and replacement move reasons found by analysis
* of unconditional status.
*/
void
unconditional_move_reasons(int color)
{
int replacement_move;
int pos;
for (pos = BOARDMIN; pos < BOARDMAX; pos++)
if (board[pos] == EMPTY
&& unconditionally_meaningless_move(pos, color, &replacement_move)) {
if (replacement_move == NO_MOVE) {
TRACE("%1m unconditional antisuji.\n", pos);
add_antisuji_move(pos);
}
else {
TRACE("%1m unconditionally replaced to %1m.\n", pos, replacement_move);
add_replacement_move(pos, replacement_move, color);
}
}
}
/*
* Local Variables:
* tab-width: 8
* c-basic-offset: 2
* End:
*/