Initial commit of GNU Go v3.8.
[sgk-go] / engine / filllib.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 <stdlib.h>
#include <string.h>
#include "liberty.h"
static int find_backfilling_move(int move, int color, int *backfill_move,
int forbidden_moves[BOARDMAX]);
static int filllib_confirm_safety(int move, int color, int *defense_point);
/* Determine whether a point is adjacent to at least one own string which
* isn't dead.
*/
static int
living_neighbor(int pos, int color)
{
int k;
for (k = 0; k < 4; k++) {
if (board[pos + delta[k]] == color
&& dragon[pos + delta[k]].status != DEAD)
return 1;
}
return 0;
}
/* Determine whether (pos) effectively is a black or white point.
* The test for inessentiality is to avoid filling the liberties
* around a killing nakade string.
*/
static void
analyze_neighbor(int pos, int *found_black, int *found_white)
{
switch (board[pos]) {
case EMPTY:
if (!(*found_black)
&& living_neighbor(pos, BLACK)
&& safe_move(pos, WHITE) != WIN)
*found_black = 1;
if (!(*found_white)
&& living_neighbor(pos, WHITE)
&& safe_move(pos, BLACK) != WIN)
*found_white = 1;
break;
case BLACK:
if (!worm[pos].inessential && DRAGON2(pos).safety != INESSENTIAL) {
if (dragon[pos].status == ALIVE
|| dragon[pos].status == UNKNOWN)
*found_black = 1;
else
*found_white = 1;
}
break;
case WHITE:
if (!worm[pos].inessential && DRAGON2(pos).safety != INESSENTIAL) {
if (dragon[pos].status == ALIVE
|| dragon[pos].status == UNKNOWN)
*found_white = 1;
else
*found_black = 1;
}
break;
}
}
/* If no move of value can be found to play, this seeks to fill a
* common liberty, backfilling or back-capturing if necessary. When
* backfilling we take care to start from the right end, in the case
* that several backfilling moves are ultimately necessary.
*
* If a move for color is found, return 1, otherwise return 0.
* The move is returned in (*move).
*/
int
fill_liberty(int *move, int color)
{
int k;
int pos;
int other = OTHER_COLOR(color);
int defense_point;
int potential_color[BOARDMAX];
/* We first make a fast scan for intersections which are potential
* candidates for liberty filling. This is not very accurate, but it
* does filter out intersections which could never pass the real
* tests below but might still require a lot of tactical reading in
* the process.
*/
memset(potential_color, 0, sizeof(potential_color));
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
if (!IS_STONE(board[pos]))
continue;
if (worm[pos].inessential || DRAGON2(pos).safety == INESSENTIAL)
continue;
if (dragon[pos].status != ALIVE) {
for (k = 0; k < 4; k++) {
int pos2 = pos + delta[k];
if (board[pos2] == EMPTY)
potential_color[pos2] |= OTHER_COLOR(board[pos]);
}
}
if (dragon[pos].status != DEAD) {
for (k = 0; k < 12; k++) {
int d = delta[k%8];
if (k >= 8) {
if (board[pos + d] != EMPTY)
continue;
d *= 2;
}
if (board[pos + d] == EMPTY)
potential_color[pos + d] |= board[pos];
}
}
}
for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
/* It seems we can't trust an empty liberty to be gray-colored
* either as a cave or as a cavity. Instead we look for empty
* intersections with at least one neighbor of each color, where
* dead stones count as enemy stones. We also count empty
* neighbors to either color if the opponent can't play there.
*/
int found_white = 0;
int found_black = 0;
if (board[pos] != EMPTY)
continue;
/* Quick rejection based on preliminary test above. */
if (potential_color[pos] != GRAY)
continue;
/* Loop over the neighbors. */
for (k = 0; k < 4; k++) {
int d = delta[k];
if (ON_BOARD(pos + d))
analyze_neighbor(pos + d, &found_black, &found_white);
}
/* Do we have neighbors of both colors? */
if (!(found_white && found_black))
continue;
/* Ok, we wish to play here, but maybe we can't. The following
* cases may occur:
* 1. Move is legal and safe.
* 2. Move is legal but not safe because it's in the middle of a seki.
* 3. Move is legal but not safe, can be played after backfilling.
* 4. Move is an illegal ko recapture.
* 5. Move is illegal but can be played after back-captures.
* 6. Move would violate confirm_safety.
*/
DEBUG(DEBUG_FILLLIB, "Filllib: Considering move at %1m.\n", pos);
/* Legal and tactically safe, play it if it passes
* confirm_safety test, i.e. that it isn't a blunder which
* causes problems for other strings.
*/
if (safe_move(pos, color) == WIN) {
DEBUG(DEBUG_FILLLIB, "Filllib: Tactically safe.\n");
if (filllib_confirm_safety(pos, color, &defense_point)) {
/* Safety confirmed. */
DEBUG(DEBUG_FILLLIB, "Filllib: Safety confirmed.\n");
*move = pos;
return 1;
}
else if (defense_point != NO_MOVE && is_legal(defense_point, color)) {
/* Safety not confirmed because the move at (pos) would set
* up a double threat. (defense_point) is assumed to defend
* against this threat.
*
* FIXME: We should verify that (defense_point) really is effective.
*/
DEBUG(DEBUG_FILLLIB,
"Filllib: Safety not confirmed, but %1m defends.\n",
defense_point);
*move = defense_point;
return 1;
}
else {
/* The move causes problems somewhere else on the board, so
* we have to discard it. If everything works right this
* should not happen at this time.
*/
DEBUG(DEBUG_FILLLIB, "Filllib: Safety not confirmed, discarded.\n");
TRACE("Warning: Blunder detected in fill_liberty().\n");
continue;
}
}
/* Try to play the move. */
if (trymove(pos, color, "fill_liberty", NO_MOVE)) {
int forbidden_moves[BOARDMAX];
popgo();
/* Legal, but not safe. Look for backfilling move. */
DEBUG(DEBUG_FILLLIB,
"Filllib: Legal but not safe, looking for backfilling move.\n");
memset(forbidden_moves, 0, sizeof(forbidden_moves));
while (find_backfilling_move(pos, color, move, forbidden_moves)) {
/* Mark as forbidden in case we need another turn in the loop. */
forbidden_moves[*move] = 1;
DEBUG(DEBUG_FILLLIB, "Filllib: Backfilling move at %1m.\n", *move);
/* In certain positions it may happen that an illegal move
* is found. This probably only can happen if we try to play
* a move inside a lost semeai. Anyway we should discard the
* move.
*/
if (!is_legal(*move, color)) {
DEBUG(DEBUG_FILLLIB, "Filllib: Was illegal, discarded.\n");
*move = NO_MOVE;
continue;
}
/* If the move turns out to be strategically unsafe, or
* setting up a double threat elsewhere, also discard it.
*/
if (!filllib_confirm_safety(*move, color, &defense_point)) {
DEBUG(DEBUG_FILLLIB,
"Filllib: Safety not confirmed, discarded.\n");
*move = NO_MOVE;
continue;
}
/* Seems to be ok. */
return 1;
}
/* No acceptable backfilling move found.
* If we captured some stones, this move should be ok anyway.
*/
if (does_capture_something(pos, color)) {
DEBUG(DEBUG_FILLLIB,
"Filllib: Not tactically safe, but captures stones.\n");
if (!filllib_confirm_safety(pos, color, &defense_point)) {
DEBUG(DEBUG_FILLLIB,
"Filllib: Safety not confirmed, discarded.\n");
continue;
}
*move = pos;
return 1;
}
}
else {
/* Move is illegal. Look for an attack on one of the neighbor
* worms. If found, return that move for back-capture.
*/
DEBUG(DEBUG_FILLLIB, "Filllib: Illegal, looking for back-capture.\n");
for (k = 0; k < 4; k++) {
int d = delta[k];
if (board[pos + d] == other
&& worm[pos + d].attack_codes[0] == WIN) {
*move = worm[pos + d].attack_points[0];
DEBUG(DEBUG_FILLLIB, "Filllib: Found at %1m.\n", *move);
return 1;
}
}
DEBUG(DEBUG_FILLLIB,
"Filllib: Nothing found, looking for ko back-capture.\n");
for (k = 0; k < 4; k++) {
int d = delta[k];
if (board[pos + d] == other
&& worm[pos + d].attack_codes[0] != 0
&& is_legal(worm[pos + d].attack_points[0], color)) {
*move = worm[pos + d].attack_points[0];
DEBUG(DEBUG_FILLLIB, "Filllib: Found at %1m.\n", *move);
return 1;
}
}
DEBUG(DEBUG_FILLLIB,
"Filllib: Nothing found, looking for threat to back-capture.\n");
for (k = 0; k < 4; k++) {
int d = delta[k];
if (board[pos + d] == other
&& worm[pos + d].attack_codes[0] != 0) {
/* Just pick some other liberty. */
/* FIXME: Something is odd about this code. */
int libs[2];
if (findlib(pos + d, 2, libs) > 1) {
if (is_legal(libs[0], color))
*move = libs[0];
else if (is_legal(libs[1], color))
*move = libs[1];
else
continue;
DEBUG(DEBUG_FILLLIB, "Filllib: Found at %1m.\n", *move);
return 1;
}
}
}
}
}
/* Nothing found. */
DEBUG(DEBUG_FILLLIB, "Filllib: No move found.\n");
return 0;
}
/* The strategy for finding a backfilling move is to first identify
* moves that
*
* 1. defends the position obtained after playing (move).
* 2. captures a stone adjacent to our neighbors to (move), before
* (move) is played.
*
* Then we check which of these are legal before (move) is played. If
* there is at least one, we take one of these arbitrarily as a
* backfilling move.
*
* Now it may happen that (move) still isn't a safe move. In that case
* we recurse to find a new backfilling move. To do things really
* correctly we should also give the opponent the opportunity to keep
* up the balance of the position by letting him do a backfilling move
* of his own. Maybe this could also be arranged by recursing this
* function. Currently we only do a half-hearted attempt to find
* opponent moves.
*
* The purpose of the forbidden_moves[] array is to get a new
* backfilling move if the first one later was found to be unsafe,
* like backfilling for J5 at F9 in filllib:45. With F9 marked as
* forbidden the correct move at G9 is found.
*/
static int adjs[MAXCHAIN];
static int libs[MAXLIBS];
static int
find_backfilling_move(int move, int color, int *backfill_move,
int forbidden_moves[BOARDMAX])
{
int k;
int liberties;
int neighbors;
int found_one = 0;
int apos = NO_MOVE;
int bpos = NO_MOVE;
int extra_pop = 0;
int success = 0;
int acode;
int saved_move = NO_MOVE;
int opponent_libs;
DEBUG(DEBUG_FILLLIB, "find_backfilling_move for %C %1m\n", color, move);
if (debug & DEBUG_FILLLIB)
dump_stack();
/* Play (move) and identify all liberties and adjacent strings. */
if (!trymove(move, color, "find_backfilling_move", move))
return 0; /* This shouldn't happen, I believe. */
/* The move wasn't safe, so there must be an attack for the
* opponent. Save it for later use.
*/
acode = attack(move, &apos);
gg_assert(acode != 0 && apos != NO_MOVE);
/* Find liberties. */
liberties = findlib(move, MAXLIBS, libs);
/* Find neighbors. */
neighbors = chainlinks(move, adjs);
/* Remove (move) again. */
popgo();
/* It's most fun to capture stones. Start by trying to take some
* neighbor off the board. If the attacking move does not directly
* reduce the number of liberties of the attacked string we don't
* trust it but keep it around if we don't find anything else. (See
* filllib:17 for a position where this matters.)
*
* It is also necessary to take care to first attack the string with
* the fewest liberties, which can probably be removed the fastest.
* See filllib:37 for an example (J5 tactically attacks K7 but the
* correct move is H5).
*
* FIXME: It seems we have to return immediately when we find an
* attacking move, because recursing for further backfilling might
* lead to moves which complete the capture but cannot be played
* before the attacking move itself. This is not ideal but probably
* good enough.
*
* In order to avoid losing unnecessary points while capturing dead
* stones, we try first to capture stones in atari, second defending
* at a liberty, and third capture stones with two or more
* liberties. See filllib:43 for a position where capturing dead
* stones (B10 or C8) loses a point compared to defending at a
* liberty (C6).
*/
for (opponent_libs = 1; opponent_libs <= 1; opponent_libs++) {
for (k = 0; k < neighbors; k++) {
if (opponent_libs < 5 && countlib(adjs[k]) != opponent_libs)
continue;
if (attack(adjs[k], &bpos) == WIN) {
if (forbidden_moves[bpos])
continue;
if (liberty_of_string(bpos, adjs[k])) {
*backfill_move = bpos;
return 1;
}
else
saved_move = bpos;
}
}
}
/* Otherwise look for a safe move at a liberty. */
if (!found_one) {
for (k = 0; k < liberties; k++) {
if (!forbidden_moves[libs[k]] && safe_move(libs[k], color) == WIN) {
*backfill_move = libs[k];
found_one = 1;
break;
}
}
}
if (!found_one) {
for (opponent_libs = 2; opponent_libs <= 5; opponent_libs++) {
for (k = 0; k < neighbors; k++) {
if (opponent_libs < 5 && countlib(adjs[k]) != opponent_libs)
continue;
if (attack(adjs[k], &bpos) == WIN) {
if (forbidden_moves[bpos])
continue;
if (liberty_of_string(bpos, adjs[k])) {
*backfill_move = bpos;
return 1;
}
else
saved_move = bpos;
}
}
}
}
/* If no luck so far, try with superstring liberties. */
if (!found_one) {
trymove(move, color, "find_backfilling_move", move);
find_proper_superstring_liberties(move, &liberties, libs, 0);
popgo();
for (k = 0; k < liberties; k++) {
if (!forbidden_moves[libs[k]] && safe_move(libs[k], color) == WIN) {
*backfill_move = libs[k];
found_one = 1;
break;
}
}
}
/* If no luck so far, try attacking superstring neighbors. */
if (!found_one) {
trymove(move, color, "find_backfilling_move", move);
superstring_chainlinks(move, &neighbors, adjs, 4);
popgo();
for (k = 0; k < neighbors; k++) {
if (attack(adjs[k], &bpos) == WIN) {
if (!forbidden_moves[bpos] && liberty_of_string(bpos, adjs[k])) {
*backfill_move = bpos;
return 1;
}
}
}
}
if (found_one) {
ASSERT1(!forbidden_moves[*backfill_move], *backfill_move);
if (!trymove(*backfill_move, color, "find_backfilling_move", move))
return 0; /* This really shouldn't happen. */
/* Allow opponent to get a move in here. */
if (trymove(apos, OTHER_COLOR(color), "find_backfilling_move", move))
extra_pop = 1;
/* If still not safe, recurse to find a new backfilling move. */
if (safe_move(move, color) == WIN)
success = 1;
else
success = find_backfilling_move(move, color, backfill_move,
forbidden_moves);
/* Pop move(s) and return. */
if (extra_pop)
popgo();
popgo();
}
if (!success && saved_move != NO_MOVE) {
ASSERT1(!forbidden_moves[saved_move], saved_move);
*backfill_move = saved_move;
success = 1;
}
if (!success)
*backfill_move = NO_MOVE;
return success;
}
/* Confirm that (move) is a safe move for color. In addition to
* calling the global confirm_safety(), this function also calls the
* owl code to verify the strategical viability of the move.
*/
static int
filllib_confirm_safety(int move, int color, int *defense_point)
{
int k;
int apos = NO_MOVE;
int save_verbose;
gg_assert(stackp == 0);
gg_assert(defense_point != NULL);
*defense_point = NO_MOVE;
/* Before we can call the owl code, we need to find a neighbor of
* our color.
*/
for (k = 0; k < 4; k++)
if (board[move + delta[k]] == color) {
apos = move + delta[k];
break;
}
/* If none found, look for a neighbor of an attacked adjacent string. */
if (apos == NO_MOVE)
for (k = 0; k < 4; k++) {
int pos2 = move + delta[k];
if (board[pos2] == OTHER_COLOR(color)
&& !play_attack_defend_n(color, 0, 1, move, pos2)) {
int adj;
adj = chainlinks(pos2, adjs);
/* It seems unlikely that we would ever get no adjacent strings
* here, but if it should happen we simply give up and say the
* move is unsafe.
*/
if (adj == 0)
return 0;
apos = adjs[0];
break;
}
}
/* Next attempt are diagonal neighbors. */
if (apos == NO_MOVE) {
for (k = 4; k < 8; k++)
if (board[move + delta[k]] == color) {
apos = move + delta[k];
break;
}
}
/* And two steps away. */
if (apos == NO_MOVE) {
for (k = 0; k < 4; k++)
if (board[move + 2 * delta[k]] == color) {
apos = move + 2 * delta[k];
break;
}
}
/* We should have found something by now. If not something's
* probably broken elsewhere. Declare the move unsafe if it happens.
*/
if (apos == NO_MOVE)
return 0;
/* Ask the owl code whether this move is strategically viable. */
save_verbose = verbose;
if (verbose > 0)
verbose--;
if (!owl_does_defend(move, apos, NULL))
return 0;
verbose = save_verbose;
return confirm_safety(move, color, defense_point, NULL);
}
/*
* Local Variables:
* tab-width: 8
* c-basic-offset: 2
* End:
*/