Initial commit of GNU Go v3.8.
[sgk-go] / patterns / connections.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 <stdio.h>
#include "liberty.h"
#include "patterns.h"
/* Test whether apos and bpos can be cut. If yes, return 1 and
* store it in the cut list of dragons.c.
*/
int
disconnect_helper(int apos, int bpos)
{
int color = board[apos];
int move;
ASSERT1(color == board[bpos] && IS_STONE(color), apos);
if (disconnect(apos, bpos, &move)) {
add_cut(apos, bpos, move);
return 1;
}
return 0;
}
/* Try to match all (permutations of) connection patterns at (m,n).
* For each match, if it is a B pattern, set cutting point in
* cutting_points array. If it is a C pattern, amalgamate the dragons
* in the pattern.
*/
static void
cut_connect_callback(int anchor, int color, struct pattern *pattern,
int ll, void *data)
{
int move;
int k;
int first_dragon = NO_MOVE;
int second_dragon = NO_MOVE;
int other = OTHER_COLOR(color);
UNUSED(data);
move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);
if ((pattern->class & CLASS_B) && !safe_move(move, other))
return;
if (pattern->class & CLASS_C) {
/* If C pattern, test if there are more than one dragon in this
* pattern so that there is something to connect, before doing any
* expensive reading.
*/
for (k = 0; k < pattern->patlen; ++k) { /* match each point */
/* transform pattern real coordinate */
int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
/* Look for distinct dragons. */
if (pattern->patn[k].att == ATT_O) {
if (first_dragon == NO_MOVE)
first_dragon = dragon[pos].origin;
else if (second_dragon == NO_MOVE
&& dragon[pos].origin != first_dragon) {
second_dragon = dragon[pos].origin;
/* A second dragon found, no need to continue looping. */
break;
}
}
}
if (second_dragon == NO_MOVE)
return; /* Nothing to amalgamate. */
}
/* If the pattern has a constraint, call the autohelper to see
* if the pattern must be rejected.
*/
if (pattern->autohelper_flag & HAVE_CONSTRAINT) {
if (!pattern->autohelper(ll, move, color, 0))
return;
}
/* If the pattern has a helper, call it to see if the pattern must
* be rejected.
*/
if (pattern->helper) {
if (!pattern->helper(pattern, ll, move, color))
return;
}
if ((pattern->class & CLASS_B)
&& !(pattern->class & CLASS_s)) {
/* Require that the X stones in the pattern are tactically safe. */
for (k = 0; k < pattern->patlen; ++k) { /* match each point */
if (pattern->patn[k].att == ATT_X) {
/* transform pattern real coordinate */
int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
if (attack(pos, NULL) == WIN
&& (move == NO_MOVE
|| !does_defend(move, pos)))
return; /* Match failed */
}
}
}
/* Get here => Pattern matches. */
if (pattern->class & CLASS_B) {
DEBUG(DEBUG_DRAGONS, "Cutting pattern %s+%d found at %1m\n",
pattern->name, ll, anchor);
DEBUG(DEBUG_DRAGONS, "cutting point %1m\n", move);
}
else if (pattern->class & CLASS_C)
DEBUG(DEBUG_DRAGONS, "Connecting pattern %s+%d found at %1m\n",
pattern->name, ll, anchor);
/* does the pattern have an action? */
if (pattern->autohelper_flag & HAVE_ACTION) {
pattern->autohelper(ll, move, color, 1);
}
/* If it is a B pattern, set cutting point. */
if (pattern->class & CLASS_B) {
cutting_points[move] |= color;
}
else if (!(pattern->class & CLASS_C))
return; /* Nothing more to do, up to the helper or autohelper
to amalgamate dragons or modify eye space. */
/* If it is a C pattern, find the dragons to connect.
* If it is a B pattern, find eye space points to inhibit connection
* through.
*/
first_dragon = NO_MOVE;
second_dragon = NO_MOVE;
for (k = 0; k < pattern->patlen; ++k) { /* match each point */
/* transform pattern real coordinate */
int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
/* Look for dragons to amalgamate. Never amalgamate stones which
* can be attacked.
*/
if ((pattern->class & CLASS_C)
&& board[pos] == color
&& pattern->patn[k].att == ATT_O
&& ((pattern->class & CLASS_s) || attack(pos, NULL) == 0)) {
if (first_dragon == NO_MOVE)
first_dragon = dragon[pos].origin;
else if (second_dragon == NO_MOVE
&& dragon[pos].origin != first_dragon) {
second_dragon = dragon[pos].origin;
/* A second dragon found, we amalgamate them at once. */
/* Want this output if verbose or DEBUG_DRAGONS is on. */
if (verbose || (debug & DEBUG_DRAGONS))
gprintf("Pattern %s joins %C dragons %1m, %1m\n",
pattern->name, color, first_dragon, second_dragon);
join_dragons(second_dragon, first_dragon);
/* Now look for another second dragon. */
second_dragon = NO_MOVE;
first_dragon = dragon[pos].origin;
}
}
/* Inhibit connections */
if (pattern->class & CLASS_B) {
if (pattern->patn[k].att != ATT_not)
break; /* The inhibition points are guaranteed to come first. */
cutting_points[pos] |= color;
DEBUG(DEBUG_DRAGONS, "inhibiting connection at %1m\n", pos);
}
} /* loop over elements */
}
/* Only consider B patterns. */
static void
cut_callback(int anchor, int color, struct pattern *pattern, int ll,
void *data)
{
if (pattern->class & CLASS_B)
cut_connect_callback(anchor, color, pattern, ll, data);
}
/* Consider C patterns and those without classification. */
static void
conn_callback(int anchor, int color, struct pattern *pattern, int ll,
void *data)
{
if (!(pattern->class & CLASS_B))
cut_connect_callback(anchor, color, pattern, ll, data);
}
/* Find cutting points which should inhibit amalgamations and sever
* the adjacent eye space.
*/
void
find_cuts(void)
{
matchpat(cut_callback, ANCHOR_COLOR, &conn_db, NULL, NULL);
}
/* Find explicit connection patterns and amalgamate the involved dragons. */
void
find_connections(void)
{
matchpat(conn_callback, ANCHOR_COLOR, &conn_db, NULL, NULL);
}
/*
* Local Variables:
* tab-width: 8
* c-basic-offset: 2
* End:
*/