/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* 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. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Test whether apos and bpos can be cut. If yes, return 1 and
* store it in the cut list of dragons.c.
disconnect_helper(int apos
, int bpos
)
ASSERT1(color
== board
[bpos
] && IS_STONE(color
), apos
);
if (disconnect(apos
, bpos
, &move
)) {
add_cut(apos
, bpos
, move
);
/* 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
cut_connect_callback(int anchor
, int color
, struct pattern
*pattern
,
int first_dragon
= NO_MOVE
;
int second_dragon
= NO_MOVE
;
int other
= OTHER_COLOR(color
);
move
= AFFINE_TRANSFORM(pattern
->move_offset
, ll
, anchor
);
if ((pattern
->class & CLASS_B
) && !safe_move(move
, other
))
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
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. */
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))
/* If the pattern has a helper, call it to see if the pattern must
if (!pattern
->helper(pattern
, ll
, move
, color
))
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
|| !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
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
if ((pattern
->class & CLASS_C
)
&& 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. */
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. */
cut_callback(int anchor
, int color
, struct pattern
*pattern
, int ll
,
if (pattern
->class & CLASS_B
)
cut_connect_callback(anchor
, color
, pattern
, ll
, data
);
/* Consider C patterns and those without classification. */
conn_callback(int anchor
, int color
, struct pattern
*pattern
, int ll
,
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.
matchpat(cut_callback
, ANCHOR_COLOR
, &conn_db
, NULL
, NULL
);
/* Find explicit connection patterns and amalgamate the involved dragons. */
matchpat(conn_callback
, ANCHOR_COLOR
, &conn_db
, NULL
, NULL
);