Commit | Line | Data |
---|---|---|
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 "gnugo.h" | |
25 | ||
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | ||
29 | #include "liberty.h" | |
30 | #include "patterns.h" | |
31 | ||
32 | /* Maximum number of dragons considered by a, B, C, and d class patterns. */ | |
33 | #define MAX_DRAGONS_PER_PATTERN 5 | |
34 | #define MAX_STRINGS_PER_PATTERN 5 | |
35 | ||
36 | /* Values of joseki patterns. */ | |
37 | #define U_VALUE 40.0 | |
38 | #define J_VALUE 35.0 | |
39 | #define j_VALUE 24.0 | |
40 | #define t_VALUE 16.0 | |
41 | ||
42 | ||
43 | /* Take care of joseki patterns. */ | |
44 | static void | |
45 | handle_joseki_patterns(struct pattern_attribute *attributes, | |
46 | unsigned int class, int move, | |
47 | int my_dragons[MAX_DRAGONS_PER_PATTERN], | |
48 | int my_ndragons, | |
49 | int your_dragons[MAX_DRAGONS_PER_PATTERN], | |
50 | int your_ndragons) | |
51 | { | |
52 | struct pattern_attribute *attribute; | |
53 | ||
54 | /* Pattern class J, joseki standard move. Add expand territory and | |
55 | * moyo, and require the value at least J_value. | |
56 | */ | |
57 | if (class & CLASS_J) { | |
58 | TRACE("...joseki standard move\n"); | |
59 | add_expand_territory_move(move); | |
60 | TRACE("...expands territory\n"); | |
61 | add_expand_moyo_move(move); | |
62 | TRACE("...expands moyo\n"); | |
63 | set_minimum_move_value(move, J_VALUE); | |
64 | TRACE("... minimum move value %f\n", J_VALUE); | |
65 | } | |
66 | ||
67 | /* Class `j' and `t' patterns are treated similarly. */ | |
68 | if (class & (CLASS_j | CLASS_t)) { | |
69 | float min_value; | |
70 | float shape_value = 0.0; | |
71 | ||
72 | if (class & CLASS_j) { | |
73 | min_value = j_VALUE; | |
74 | TRACE("...less urgent joseki move\n"); | |
75 | add_expand_territory_move(move); | |
76 | TRACE("...expands territory\n"); | |
77 | add_expand_moyo_move(move); | |
78 | TRACE("...expands moyo\n"); | |
79 | } | |
80 | else { | |
81 | min_value = t_VALUE; | |
82 | TRACE("...minor joseki move\n"); | |
83 | } | |
84 | ||
85 | /* Board size modification. */ | |
86 | min_value *= board_size / 19.0; | |
87 | ||
88 | for (attribute = attributes; attribute->type != LAST_ATTRIBUTE; | |
89 | attribute++) { | |
90 | if (attribute->type == SHAPE) { | |
91 | shape_value = attribute->value; | |
92 | min_value *= (1 + 0.01 * shape_value); | |
93 | break; | |
94 | } | |
95 | } | |
96 | ||
97 | if ((board_size >= 17) && (class & CLASS_F)) { | |
98 | /* Otherwise, `j' and `t' patterns not of CLASS_F would get | |
99 | * preferred in value_move_reasons(). | |
100 | */ | |
101 | min_value *= 1.005; | |
102 | ||
103 | set_maximum_move_value(move, min_value); | |
104 | scale_randomness(move, 5.0); | |
105 | TRACE("...move value %f (shape %f)\n", min_value, shape_value); | |
106 | } | |
107 | else | |
108 | TRACE("...minimum move value %f (shape %f)\n", min_value, shape_value); | |
109 | ||
110 | set_minimum_move_value(move, min_value); | |
111 | } | |
112 | ||
113 | /* Pattern class U, very urgent joseki move. Add strategical defense | |
114 | * and attack, plus a shape bonus of 15 and a minimum value of 40. | |
115 | */ | |
116 | if (class & CLASS_U) { | |
117 | int k; | |
118 | ||
119 | TRACE("...joseki urgent move\n"); | |
120 | for (k = 0; k < my_ndragons; k++) { | |
121 | add_strategical_defense_move(move, my_dragons[k]); | |
122 | TRACE("...strategical defense of %1m\n", my_dragons[k]); | |
123 | } | |
124 | for (k = 0; k < your_ndragons; k++) { | |
125 | add_strategical_attack_move(move, your_dragons[k]); | |
126 | TRACE("...strategical attack on %1m\n", your_dragons[k]); | |
127 | } | |
128 | add_shape_value(move, 15); | |
129 | TRACE("...shape value 15\n"); | |
130 | set_minimum_move_value(move, U_VALUE); | |
131 | TRACE("...(min) move value %f\n", U_VALUE); | |
132 | } | |
133 | ||
134 | /* Pattern class T, joseki trick move. For the moment we never play | |
135 | * these. | |
136 | */ | |
137 | if (class & CLASS_T) { | |
138 | TRACE("...joseki trick move\n"); | |
139 | add_antisuji_move(move); | |
140 | TRACE("...antisuji\n"); | |
141 | } | |
142 | ||
143 | for (attribute = attributes; attribute->type != LAST_ATTRIBUTE; | |
144 | attribute++) { | |
145 | switch (attribute->type) { | |
146 | case MIN_VALUE: | |
147 | set_minimum_move_value(move, attribute->value); | |
148 | TRACE("...(min) move value %f\n", attribute->value); | |
149 | break; | |
150 | ||
151 | case MAX_VALUE: | |
152 | set_maximum_move_value(move, attribute->value); | |
153 | TRACE("...max move value %f\n", attribute->value); | |
154 | break; | |
155 | ||
156 | case MIN_TERRITORY: | |
157 | set_minimum_territorial_value(move, attribute->value); | |
158 | TRACE("...(min) territorial value %f\n", attribute->value); | |
159 | break; | |
160 | ||
161 | case MAX_TERRITORY: | |
162 | set_maximum_territorial_value(move, attribute->value); | |
163 | TRACE("...max territorial value %f\n", attribute->value); | |
164 | break; | |
165 | ||
166 | case SHAPE: | |
167 | /* For class `j' and `t' patterns shape value has been counted | |
168 | * already. | |
169 | */ | |
170 | if (!(class & (CLASS_j | CLASS_t))) { | |
171 | add_shape_value(move, attribute->value); | |
172 | TRACE("...shape value %f\n", attribute->value); | |
173 | } | |
174 | ||
175 | break; | |
176 | ||
177 | case FOLLOWUP: | |
178 | add_followup_value(move, attribute->value); | |
179 | TRACE("...followup value %f\n", attribute->value); | |
180 | break; | |
181 | ||
182 | case REVERSE_FOLLOWUP: | |
183 | add_reverse_followup_value(move, attribute->value); | |
184 | TRACE("...reverse followup value %f\n", attribute->value); | |
185 | break; | |
186 | ||
187 | default: | |
188 | /* Must not happen. */ | |
189 | gg_assert(0); | |
190 | } | |
191 | } | |
192 | } | |
193 | ||
194 | ||
195 | /* | |
196 | * This callback is invoked for each matched pattern. | |
197 | */ | |
198 | static void | |
199 | shapes_callback(int anchor, int color, struct pattern *pattern, int ll, | |
200 | void *data) | |
201 | { | |
202 | int other = OTHER_COLOR(color); | |
203 | ||
204 | int k, l; | |
205 | int move; | |
206 | /* For restricted search, the pattern must intersect the search area */ | |
207 | ||
208 | /* Dragons of our color. */ | |
209 | int my_dragons[MAX_DRAGONS_PER_PATTERN]; | |
210 | int my_ndragons = 0; | |
211 | ||
212 | /* Dragons of other color. */ | |
213 | int your_dragons[MAX_DRAGONS_PER_PATTERN]; | |
214 | int your_ndragons = 0; | |
215 | ||
216 | /* Strings of our color. */ | |
217 | int my_strings[MAX_STRINGS_PER_PATTERN]; | |
218 | int my_nstrings = 0; | |
219 | ||
220 | /* Strings of other color. */ | |
221 | int your_strings[MAX_STRINGS_PER_PATTERN]; | |
222 | int your_nstrings = 0; | |
223 | ||
224 | /* Make a local copy of the classification that we may modify. */ | |
225 | unsigned int class = pattern->class; | |
226 | ||
227 | /* Don't accept fuseki marked patterns while scoring. */ | |
228 | if (doing_scoring && (class & CLASS_F)) | |
229 | return; | |
230 | ||
231 | /* Don't need auxiliary data in this callback. */ | |
232 | UNUSED(data); | |
233 | ||
234 | /* Pick up the location of the move */ | |
235 | move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor); | |
236 | ||
237 | /* For some classes of patterns we need to find all dragons present | |
238 | * in the pattern. | |
239 | */ | |
240 | if ((class & (CLASS_B | CLASS_C | CLASS_c | CLASS_a | CLASS_d | CLASS_O | |
241 | | CLASS_J | CLASS_j | CLASS_U | CLASS_T | CLASS_t)) != 0) { | |
242 | /* Match each point. */ | |
243 | for (k = 0; k < pattern->patlen; ++k) { | |
244 | int pos; /* absolute (board) co-ord of (transformed) pattern element */ | |
245 | int origin; /* dragon origin */ | |
246 | ||
247 | /* all the following stuff (currently) applies only at occupied cells */ | |
248 | if (pattern->patn[k].att == ATT_dot) | |
249 | continue; | |
250 | ||
251 | /* transform pattern real coordinate */ | |
252 | pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor); | |
253 | ||
254 | /* Already, matchpat rejects O patterns containing a friendly stone with | |
255 | * DEAD or CRITICAL matcher_status. If the stone is tactically | |
256 | * CRITICAL it still could have matcher_status ALIVE since it might | |
257 | * be amalgamated into a live dragon. In this case we want to reject the | |
258 | * pattern if (move) does not rescue it. This is most easily tested | |
259 | * here within shapes_callback(), since the value of (move) is not | |
260 | * known by matchpat(). | |
261 | */ | |
262 | if ((class & CLASS_O) | |
263 | && board[pos] == color | |
264 | && worm[pos].attack_points[0] != 0 | |
265 | && !does_defend(move, pos)) | |
266 | return; | |
267 | ||
268 | origin = dragon[pos].origin; | |
269 | if (board[pos] == color && my_ndragons < MAX_DRAGONS_PER_PATTERN) { | |
270 | for (l = 0; l < my_ndragons; l++) { | |
271 | if (my_dragons[l] == origin) | |
272 | break; | |
273 | } | |
274 | if (l == my_ndragons) { | |
275 | /* We found another dragon of our color. Check that it (or | |
276 | * rather the underlying worm) cannot be tactically | |
277 | * captured before adding it to the list of my_dragons. | |
278 | */ | |
279 | if (worm[pos].attack_codes[0] == 0 | |
280 | || does_defend(move, pos)) { | |
281 | /* Ok, add the dragon to the list. */ | |
282 | my_dragons[l] = origin; | |
283 | my_ndragons++; | |
284 | } | |
285 | } | |
286 | } | |
287 | ||
288 | if (board[pos] == other && your_ndragons < MAX_DRAGONS_PER_PATTERN) { | |
289 | for (l = 0; l < your_ndragons; l++) { | |
290 | if (your_dragons[l] == origin) | |
291 | break; | |
292 | } | |
293 | if (l == your_ndragons) { | |
294 | /* We found another opponent dragon, add it to the list. */ | |
295 | your_dragons[l] = origin; | |
296 | your_ndragons++; | |
297 | } | |
298 | } | |
299 | ||
300 | if (pattern->patn[k].att == ATT_O || pattern->patn[k].att == ATT_X) { | |
301 | origin = find_origin(pos); | |
302 | if (board[pos] == color && my_nstrings < MAX_STRINGS_PER_PATTERN) { | |
303 | for (l = 0; l < my_nstrings; l++) { | |
304 | if (my_strings[l] == origin) | |
305 | break; | |
306 | } | |
307 | if (l == my_nstrings) { | |
308 | /* We found another string of our color. Check that it | |
309 | * cannot be tactically captured before adding it to the | |
310 | * list of my_strings. | |
311 | */ | |
312 | if (worm[pos].attack_codes[0] == 0 | |
313 | || does_defend(move, pos)) { | |
314 | /* Ok, add the string to the list. */ | |
315 | my_strings[l] = origin; | |
316 | my_nstrings++; | |
317 | } | |
318 | } | |
319 | } | |
320 | ||
321 | if (board[pos] == other && your_nstrings < MAX_STRINGS_PER_PATTERN) { | |
322 | for (l = 0; l < your_nstrings; l++) { | |
323 | if (your_strings[l] == origin) | |
324 | break; | |
325 | } | |
326 | if (l == your_nstrings) { | |
327 | /* We found another opponent string, add it to the list. */ | |
328 | your_strings[l] = origin; | |
329 | your_nstrings++; | |
330 | } | |
331 | } | |
332 | } | |
333 | } /* loop over elements */ | |
334 | } /* if we need to loop over the elements */ | |
335 | ||
336 | /* Nothing to connect. Remove C class bit. */ | |
337 | if (my_nstrings < 2) | |
338 | class &= ~CLASS_C; | |
339 | ||
340 | /* Nothing to cut. Remove B class bit. */ | |
341 | if (your_nstrings < 2) | |
342 | class &= ~CLASS_B; | |
343 | ||
344 | /* | |
345 | * If this pattern can't produce any effect (e.g. if it was a B or C | |
346 | * pattern with only one dragon of the appropriate color), don't | |
347 | * do any expensive checking but return immediately. | |
348 | * If it only has some move_values, these will be ignored. | |
349 | */ | |
350 | if (!pattern->helper | |
351 | && !allpats | |
352 | && !(pattern->autohelper_flag & HAVE_ACTION) | |
353 | && !(class & CLASS_MOVE_REASONS) | |
354 | && pattern->attributes->type == LAST_ATTRIBUTE) | |
355 | return; | |
356 | ||
357 | /* For sacrifice patterns, the survival of the stone to be played is | |
358 | * not checked (but it still needs to be legal). Otherwise we | |
359 | * discard moves which can be captured. | |
360 | */ | |
361 | if (!(class & CLASS_s)) { | |
362 | /* Don't allow ko unsafety. */ | |
363 | if (safe_move(move, color) != WIN) { | |
364 | if (0) | |
365 | TRACE(" move at %1m wasn't safe, discarded\n", move); | |
366 | return; | |
367 | } | |
368 | } | |
369 | else { | |
370 | /* Allow illegal ko captures at this stage. */ | |
371 | if (!is_ko(move, color, NULL) && !is_legal(move, color)) { | |
372 | if (0) | |
373 | TRACE(" move at %1m wasn't legal, discarded\n", move); | |
374 | return; | |
375 | } | |
376 | } | |
377 | ||
378 | /* For class n patterns, the pattern is contingent on an opponent | |
379 | * move at * not being captured. | |
380 | */ | |
381 | if (class & CLASS_n) { | |
382 | /* Allow ko unsafety. */ | |
383 | if (safe_move(move, other) == 0) { | |
384 | if (0) | |
385 | TRACE(" opponent can't play safely at %1m, move discarded\n", move); | |
386 | return; | |
387 | } | |
388 | } | |
389 | ||
390 | /* If the pattern has a constraint, call the autohelper to see | |
391 | * if the pattern must be rejected. | |
392 | */ | |
393 | if (pattern->autohelper_flag & HAVE_CONSTRAINT) { | |
394 | if (!pattern->autohelper(ll, move, color, 0)) | |
395 | return; | |
396 | } | |
397 | ||
398 | /* Ask helper for acceptance of pattern. */ | |
399 | if (pattern->helper) { | |
400 | /* ask helper function to consider the move */ | |
401 | int accepted; | |
402 | DEBUG(DEBUG_HELPER, " asking helper to consider '%s'+%d at %1m\n", | |
403 | pattern->name, ll, move); | |
404 | accepted = pattern->helper(pattern, ll, move, color); | |
405 | ||
406 | if (accepted) { | |
407 | DEBUG(DEBUG_HELPER, "helper likes pattern '%s' at %1m\n", | |
408 | pattern->name, move); | |
409 | } | |
410 | else { | |
411 | DEBUG(DEBUG_HELPER, " helper does not like pattern '%s' at %1m\n", | |
412 | pattern->name, move); | |
413 | return; /* pattern matcher does not like it */ | |
414 | } | |
415 | } | |
416 | ||
417 | /* If using -a, want to see all matches even if not -v */ | |
418 | if (allpats || verbose) { | |
419 | TRACE("pattern '%s'+%d matched at %1m\n", pattern->name, ll, move); | |
420 | } | |
421 | ||
422 | /* does the pattern have an action? */ | |
423 | if (pattern->autohelper_flag & HAVE_ACTION) | |
424 | pattern->autohelper(ll, move, color, 1); | |
425 | ||
426 | /* Pattern class B, try to cut all combinations of opponent strings. */ | |
427 | if (class & CLASS_B) { | |
428 | for (k = 0; k < your_nstrings; k++) | |
429 | for (l = k+1; l < your_nstrings; l++) { | |
430 | if (string_connect(your_strings[k], your_strings[l], NULL) | |
431 | && !play_connect_n(color, 1, 1, move, | |
432 | your_strings[k], your_strings[l])) { | |
433 | add_cut_move(move, your_strings[k], your_strings[l]); | |
434 | TRACE("...cuts strings %1m, %1m\n", | |
435 | your_strings[k], your_strings[l]); | |
436 | } | |
437 | } | |
438 | } | |
439 | ||
440 | /* Pattern class C, try to connect all combinations of our strings. */ | |
441 | if (class & CLASS_C) { | |
442 | for (k = 0; k < my_nstrings; k++) | |
443 | for (l = k+1; l < my_nstrings; l++) { | |
444 | if (disconnect(my_strings[k], my_strings[l], NULL) | |
445 | && !play_connect_n(color, 0, 1, move, | |
446 | my_strings[k], my_strings[l])) { | |
447 | add_connection_move(move, my_strings[k], my_strings[l]); | |
448 | TRACE("...connects strings %1m, %1m\n", | |
449 | my_strings[k], my_strings[l]); | |
450 | } | |
451 | } | |
452 | } | |
453 | ||
454 | /* Pattern class c, add strategical defense move reason for all our | |
455 | * dragons and a small shape bonus. | |
456 | * | |
457 | * This is a preliminary effect of "weak connection" and may need to | |
458 | * be revised. | |
459 | */ | |
460 | if (class & CLASS_c) { | |
461 | for (k = 0; k < my_ndragons; k++) { | |
462 | add_strategical_defense_move(move, my_dragons[k]); | |
463 | TRACE("...strategical defense (weak connection) of %1m\n", | |
464 | my_dragons[k]); | |
465 | } | |
466 | add_shape_value(move, 1); | |
467 | TRACE("...shape value 1\n"); | |
468 | } | |
469 | ||
470 | /* Pattern class b is obsolete in the pattern databases handled here. */ | |
471 | gg_assert(!(class & CLASS_b)); | |
472 | ||
473 | /* Pattern class e, expand to make territory. */ | |
474 | if (class & CLASS_e) { | |
475 | add_expand_territory_move(move); | |
476 | TRACE("...expands territory\n"); | |
477 | } | |
478 | ||
479 | /* Pattern class E, expand to make moyo. */ | |
480 | if (class & CLASS_E) { | |
481 | add_expand_moyo_move(move); | |
482 | TRACE("...expands moyo\n"); | |
483 | } | |
484 | ||
485 | /* Pattern class i, an invasion. */ | |
486 | if (class & CLASS_I) { | |
487 | add_invasion_move(move); | |
488 | TRACE("...is an invasion\n"); | |
489 | } | |
490 | ||
491 | /* Pattern class a, strategical level attack on all opponent dragons. */ | |
492 | if (class & CLASS_a) { | |
493 | for (k = 0; k < your_ndragons; k++) { | |
494 | add_strategical_attack_move(move, your_dragons[k]); | |
495 | TRACE("...strategical attack on %1m\n", your_dragons[k]); | |
496 | } | |
497 | } | |
498 | ||
499 | /* Pattern class d, strategical level defense of all own dragons. */ | |
500 | if (class & CLASS_d) { | |
501 | for (k = 0; k < my_ndragons; k++) { | |
502 | add_strategical_defense_move(move, my_dragons[k]); | |
503 | TRACE("...strategical defense of %1m\n", my_dragons[k]); | |
504 | } | |
505 | } | |
506 | ||
507 | /* Pattern class W, worthwhile threat move. */ | |
508 | if (class & CLASS_W) { | |
509 | TRACE("...worthwhile threat move\n"); | |
510 | add_worthwhile_threat_move(move); | |
511 | } | |
512 | ||
513 | handle_joseki_patterns(pattern->attributes, class, move, | |
514 | my_dragons, my_ndragons, your_dragons, your_ndragons); | |
515 | } | |
516 | ||
517 | ||
518 | /* This callback is invoked for each matched pattern from joseki | |
519 | * database. This function is just a copy of relevant parts of | |
520 | * shapes_callback(). However, most of the common code resides in | |
521 | * handle_joseki_patterns(). | |
522 | */ | |
523 | static void | |
524 | joseki_callback(int move, int color, struct corner_pattern *pattern, | |
525 | int trans, int *stones, int num_stones) | |
526 | { | |
527 | int k, l; | |
528 | int class = pattern->class; | |
529 | ||
530 | /* Dragons of our color. */ | |
531 | int my_dragons[MAX_DRAGONS_PER_PATTERN]; | |
532 | int my_ndragons = 0; | |
533 | ||
534 | /* Dragons of other color. */ | |
535 | int your_dragons[MAX_DRAGONS_PER_PATTERN]; | |
536 | int your_ndragons = 0; | |
537 | ||
538 | /* For urgent joseki patterns we need to find all dragons present in the | |
539 | * pattern since such patterns are assumed to have strategical effect on | |
540 | * them. | |
541 | */ | |
542 | if (class & CLASS_U) { | |
543 | /* Loop over all stones in the pattern. */ | |
544 | for (k = 0; k < num_stones; k++) { | |
545 | int pos = stones[k]; | |
546 | int origin = dragon[pos].origin; | |
547 | ||
548 | if (board[pos] == color && my_ndragons < MAX_DRAGONS_PER_PATTERN) { | |
549 | for (l = 0; l < my_ndragons; l++) { | |
550 | if (my_dragons[l] == origin) | |
551 | break; | |
552 | } | |
553 | ||
554 | if (l == my_ndragons) { | |
555 | /* We found another dragon of our color. Check that it (or | |
556 | * rather the underlying worm) cannot be tactically | |
557 | * captured before adding it to the list of my_dragons. | |
558 | */ | |
559 | if (worm[pos].attack_codes[0] == 0 || does_defend(move, pos)) { | |
560 | /* Ok, add the dragon to the list. */ | |
561 | my_dragons[l] = origin; | |
562 | my_ndragons++; | |
563 | } | |
564 | } | |
565 | } | |
566 | ||
567 | if (board[pos] != color && your_ndragons < MAX_DRAGONS_PER_PATTERN) { | |
568 | for (l = 0; l < your_ndragons; l++) { | |
569 | if (your_dragons[l] == origin) | |
570 | break; | |
571 | } | |
572 | if (l == your_ndragons) { | |
573 | /* We found another opponent dragon, add it to the list. */ | |
574 | your_dragons[l] = origin; | |
575 | your_ndragons++; | |
576 | } | |
577 | } | |
578 | } | |
579 | } | |
580 | ||
581 | /* For joseki patterns we don't check if the proposed move is safe or legal. | |
582 | */ | |
583 | ||
584 | /* If the pattern has a constraint, call the autohelper to see | |
585 | * if the pattern must be rejected. | |
586 | */ | |
587 | if (pattern->autohelper_flag & HAVE_CONSTRAINT) { | |
588 | if (!pattern->autohelper(trans, move, color, 0)) | |
589 | return; | |
590 | } | |
591 | ||
592 | /* If using -a, want to see all matches even if not -v. */ | |
593 | if (allpats || verbose) | |
594 | TRACE("pattern '%s'+%d matched at %1m\n", pattern->name, trans, move); | |
595 | ||
596 | /* Does the pattern have an action? */ | |
597 | if (pattern->autohelper_flag & HAVE_ACTION) | |
598 | pattern->autohelper(trans, move, color, 1); | |
599 | ||
600 | /* Pattern class N, antisuji move. */ | |
601 | if (class & CLASS_N) { | |
602 | TRACE("...antisuji move\n"); | |
603 | add_antisuji_move(move); | |
604 | } | |
605 | ||
606 | handle_joseki_patterns(pattern->attributes, class, move, | |
607 | my_dragons, my_ndragons, your_dragons, your_ndragons); | |
608 | } | |
609 | ||
610 | ||
611 | /* | |
612 | * Match all patterns in patterns.db and patterns2.db on all positions. | |
613 | * | |
614 | * This function is one of the basic generators of move reasons, called | |
615 | * by genmove(). | |
616 | */ | |
617 | void | |
618 | shapes(int color) | |
619 | { | |
620 | TRACE("\nPattern matcher is looking for move reasons for %s!\n", | |
621 | color_to_string(color)); | |
622 | ||
623 | matchpat(shapes_callback, color, &pat_db, NULL, NULL); | |
624 | ||
625 | /* Don't match joseki patterns while scoring. */ | |
626 | if (josekidb && !doing_scoring) | |
627 | #if 1 | |
628 | corner_matchpat(joseki_callback, color, &joseki_db); | |
629 | #else | |
630 | matchpat(shapes_callback, color, &joseki_db, NULL, NULL); | |
631 | #endif | |
632 | ||
633 | if (!disable_fuseki && !doing_scoring) | |
634 | matchpat(shapes_callback, color, &fusekipat_db, NULL, NULL); | |
635 | } | |
636 | ||
637 | ||
638 | /* | |
639 | * Match all patterns in endgame.db on all positions. | |
640 | */ | |
641 | void | |
642 | endgame_shapes(int color) | |
643 | { | |
644 | TRACE("\nEndgame pattern matcher is looking for move reasons for %s!\n", | |
645 | color_to_string(color)); | |
646 | ||
647 | matchpat(shapes_callback, color, &endpat_db, NULL, NULL); | |
648 | } | |
649 | ||
650 | ||
651 | /* | |
652 | * Local Variables: | |
653 | * tab-width: 8 | |
654 | * c-basic-offset: 2 | |
655 | * End: | |
656 | */ |