238 lines
7.5 KiB
C
238 lines
7.5 KiB
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:
|
|
*/
|