Updated README: Equal sign not required with `--mode` flag.
[sgk-go] / patterns / connections.c
CommitLineData
7eeb782e
AT
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
3 * http://www.gnu.org/software/gnugo/ for more information. *
4 * *
5 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
6 * 2008 and 2009 by the Free Software Foundation. *
7 * *
8 * This program is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License as *
10 * published by the Free Software Foundation - version 3 or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License in file COPYING for more details. *
17 * *
18 * You should have received a copy of the GNU General Public *
19 * License along with this program; if not, write to the Free *
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
21 * Boston, MA 02111, USA. *
22\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23
24#include <stdio.h>
25#include "liberty.h"
26#include "patterns.h"
27
28
29/* Test whether apos and bpos can be cut. If yes, return 1 and
30 * store it in the cut list of dragons.c.
31 */
32int
33disconnect_helper(int apos, int bpos)
34{
35 int color = board[apos];
36 int move;
37 ASSERT1(color == board[bpos] && IS_STONE(color), apos);
38
39 if (disconnect(apos, bpos, &move)) {
40 add_cut(apos, bpos, move);
41 return 1;
42 }
43 return 0;
44}
45
46/* Try to match all (permutations of) connection patterns at (m,n).
47 * For each match, if it is a B pattern, set cutting point in
48 * cutting_points array. If it is a C pattern, amalgamate the dragons
49 * in the pattern.
50 */
51
52static void
53cut_connect_callback(int anchor, int color, struct pattern *pattern,
54 int ll, void *data)
55{
56 int move;
57 int k;
58 int first_dragon = NO_MOVE;
59 int second_dragon = NO_MOVE;
60
61 int other = OTHER_COLOR(color);
62 UNUSED(data);
63
64 move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);
65
66 if ((pattern->class & CLASS_B) && !safe_move(move, other))
67 return;
68
69 if (pattern->class & CLASS_C) {
70 /* If C pattern, test if there are more than one dragon in this
71 * pattern so that there is something to connect, before doing any
72 * expensive reading.
73 */
74
75 for (k = 0; k < pattern->patlen; ++k) { /* match each point */
76 /* transform pattern real coordinate */
77 int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
78
79 /* Look for distinct dragons. */
80 if (pattern->patn[k].att == ATT_O) {
81 if (first_dragon == NO_MOVE)
82 first_dragon = dragon[pos].origin;
83 else if (second_dragon == NO_MOVE
84 && dragon[pos].origin != first_dragon) {
85 second_dragon = dragon[pos].origin;
86 /* A second dragon found, no need to continue looping. */
87 break;
88 }
89 }
90 }
91 if (second_dragon == NO_MOVE)
92 return; /* Nothing to amalgamate. */
93 }
94
95 /* If the pattern has a constraint, call the autohelper to see
96 * if the pattern must be rejected.
97 */
98 if (pattern->autohelper_flag & HAVE_CONSTRAINT) {
99 if (!pattern->autohelper(ll, move, color, 0))
100 return;
101 }
102
103 /* If the pattern has a helper, call it to see if the pattern must
104 * be rejected.
105 */
106 if (pattern->helper) {
107 if (!pattern->helper(pattern, ll, move, color))
108 return;
109 }
110
111 if ((pattern->class & CLASS_B)
112 && !(pattern->class & CLASS_s)) {
113 /* Require that the X stones in the pattern are tactically safe. */
114 for (k = 0; k < pattern->patlen; ++k) { /* match each point */
115 if (pattern->patn[k].att == ATT_X) {
116 /* transform pattern real coordinate */
117 int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
118
119 if (attack(pos, NULL) == WIN
120 && (move == NO_MOVE
121 || !does_defend(move, pos)))
122 return; /* Match failed */
123 }
124 }
125 }
126
127 /* Get here => Pattern matches. */
128 if (pattern->class & CLASS_B) {
129 DEBUG(DEBUG_DRAGONS, "Cutting pattern %s+%d found at %1m\n",
130 pattern->name, ll, anchor);
131 DEBUG(DEBUG_DRAGONS, "cutting point %1m\n", move);
132 }
133 else if (pattern->class & CLASS_C)
134 DEBUG(DEBUG_DRAGONS, "Connecting pattern %s+%d found at %1m\n",
135 pattern->name, ll, anchor);
136
137 /* does the pattern have an action? */
138 if (pattern->autohelper_flag & HAVE_ACTION) {
139 pattern->autohelper(ll, move, color, 1);
140 }
141
142 /* If it is a B pattern, set cutting point. */
143
144 if (pattern->class & CLASS_B) {
145 cutting_points[move] |= color;
146 }
147 else if (!(pattern->class & CLASS_C))
148 return; /* Nothing more to do, up to the helper or autohelper
149 to amalgamate dragons or modify eye space. */
150
151 /* If it is a C pattern, find the dragons to connect.
152 * If it is a B pattern, find eye space points to inhibit connection
153 * through.
154 */
155 first_dragon = NO_MOVE;
156 second_dragon = NO_MOVE;
157 for (k = 0; k < pattern->patlen; ++k) { /* match each point */
158 /* transform pattern real coordinate */
159 int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
160
161 /* Look for dragons to amalgamate. Never amalgamate stones which
162 * can be attacked.
163 */
164 if ((pattern->class & CLASS_C)
165 && board[pos] == color
166 && pattern->patn[k].att == ATT_O
167 && ((pattern->class & CLASS_s) || attack(pos, NULL) == 0)) {
168 if (first_dragon == NO_MOVE)
169 first_dragon = dragon[pos].origin;
170 else if (second_dragon == NO_MOVE
171 && dragon[pos].origin != first_dragon) {
172 second_dragon = dragon[pos].origin;
173 /* A second dragon found, we amalgamate them at once. */
174 /* Want this output if verbose or DEBUG_DRAGONS is on. */
175 if (verbose || (debug & DEBUG_DRAGONS))
176 gprintf("Pattern %s joins %C dragons %1m, %1m\n",
177 pattern->name, color, first_dragon, second_dragon);
178 join_dragons(second_dragon, first_dragon);
179 /* Now look for another second dragon. */
180 second_dragon = NO_MOVE;
181 first_dragon = dragon[pos].origin;
182 }
183 }
184
185 /* Inhibit connections */
186 if (pattern->class & CLASS_B) {
187 if (pattern->patn[k].att != ATT_not)
188 break; /* The inhibition points are guaranteed to come first. */
189 cutting_points[pos] |= color;
190 DEBUG(DEBUG_DRAGONS, "inhibiting connection at %1m\n", pos);
191 }
192 } /* loop over elements */
193}
194
195
196/* Only consider B patterns. */
197static void
198cut_callback(int anchor, int color, struct pattern *pattern, int ll,
199 void *data)
200{
201 if (pattern->class & CLASS_B)
202 cut_connect_callback(anchor, color, pattern, ll, data);
203}
204
205
206/* Consider C patterns and those without classification. */
207static void
208conn_callback(int anchor, int color, struct pattern *pattern, int ll,
209 void *data)
210{
211 if (!(pattern->class & CLASS_B))
212 cut_connect_callback(anchor, color, pattern, ll, data);
213}
214
215/* Find cutting points which should inhibit amalgamations and sever
216 * the adjacent eye space.
217 */
218void
219find_cuts(void)
220{
221 matchpat(cut_callback, ANCHOR_COLOR, &conn_db, NULL, NULL);
222}
223
224/* Find explicit connection patterns and amalgamate the involved dragons. */
225void
226find_connections(void)
227{
228 matchpat(conn_callback, ANCHOR_COLOR, &conn_db, NULL, NULL);
229}
230
231
232/*
233 * Local Variables:
234 * tab-width: 8
235 * c-basic-offset: 2
236 * End:
237 */