/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * 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 #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: */