Updated README: Equal sign not required with `--mode` flag.
[sgk-go] / engine / shapes.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 "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. */
44static void
45handle_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 */
198static void
199shapes_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 */
523static void
524joseki_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 */
617void
618shapes(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 */
641void
642endgame_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 */