Updated README: Equal sign not required with `--mode` flag.
[sgk-go] / engine / genmove.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#include <string.h>
29
30#include "liberty.h"
31#include "sgftree.h"
32#include "gg_utils.h"
33
34/* Return one if x doesn't equal position_number and 0 otherwise.
35 * After using this macro x will always have the value
36 * position_number.
37 */
38#define NEEDS_UPDATE(x) (x != position_number ? (x = position_number, 1) : 0)
39
40/* Mark a limited search area. If limit_search != 1, genmove
41 * will only return moves within the area marked by the array
42 * search_mask.
43 */
44static int limit_search = 0;
45static int search_mask[BOARDMAX];
46
47static int do_genmove(int color, float pure_threat_value,
48 int allowed_moves[BOARDMAX], float *value, int *resign);
49
50/* Position numbers for which various examinations were last made. */
51static int worms_examined = -1;
52static int initial_influence_examined = -1;
53static int dragons_examined_without_owl = -1;
54static int dragons_examined = -1;
55static int initial_influence2_examined = -1;
56static int dragons_refinedly_examined = -1;
57
58static int revise_semeai(int color);
59static int revise_thrashing_dragon(int color, float our_score,
60 float advantage);
61
62static void break_mirror_go(int color);
63static int find_mirror_move(int *move, int color);
64static int should_resign(int color, float optimistic_score, int move);
65static void compute_scores(int use_chinese_rules);
66
67
68/* Reset some things in the engine.
69 *
70 * This prepares the hash table for the reading code for use. It
71 * should be called when we start examine a new position.
72 */
73
74void
75reset_engine()
76{
77 /* To improve the reproducability of games, we restart the random
78 * number generator with the same seed for each move. Thus we don't
79 * have to know how many previous moves have been played, nor
80 * actually play through them, in order to get the right random
81 * numbers.
82 */
83 reuse_random_seed();
84
85 /* Initialize things for hashing of positions. */
86 reading_cache_clear();
87
88 hashdata_recalc(&board_hash, board, board_ko_pos);
89
90 worms_examined = -1;
91 initial_influence_examined = -1;
92 dragons_examined_without_owl = -1;
93 dragons_examined = -1;
94 initial_influence2_examined = -1;
95 dragons_refinedly_examined = -1;
96
97 /* Prepare our table of move reasons. */
98 clear_move_reasons();
99 clear_break_in_list();
100
101 /* Set up depth values (see comments there for details). */
102 set_depth_values(get_level(), 0);
103
104 /* Initialize arrays of moves which are meaningless due to
105 * static analysis of unconditional status.
106 */
107 clear_unconditionally_meaningless_moves();
108}
109
110/*
111 * Examine the position and try to gather as much information as possible.
112 * This is used mainly for move generation, but could also be called
113 * for debugging purposes (decidestring, etc).
114 *
115 * The parameter how_much tells us how much of the work we have to do.
116 * For move generation we have to do it all. For debugging we can
117 * sometimes stop a little earlier.
118 *
119 * aftermath_play indicates we are in aftermath playout phase. It's only
120 * effect is to always use chinese rules for the score estimates.
121 */
122
123void
124examine_position(int how_much, int aftermath_play)
125{
126 int save_verbose = verbose;
127
128 purge_persistent_caches();
129
130 /* Don't print reading traces during make_worms and make_dragons unless
131 * the user really wants it (verbose == 3).
132 */
133 if (verbose == 1 || verbose == 2)
134 --verbose;
135
136 if (NEEDS_UPDATE(worms_examined)) {
137 start_timer(0);
138 make_worms();
139 time_report(0, " make worms", NO_MOVE, 1.0);
140 }
141
142 if (how_much == EXAMINE_WORMS) {
143 verbose = save_verbose;
144 gg_assert(test_gray_border() < 0);
145 return;
146 }
147
148 if (stones_on_board(BLACK | WHITE) != 0) {
149 if (NEEDS_UPDATE(initial_influence_examined))
150 compute_worm_influence();
151 if (how_much == EXAMINE_INITIAL_INFLUENCE) {
152 verbose = save_verbose;
153 gg_assert(test_gray_border() < 0);
154 return;
155 }
156
157 if (how_much == EXAMINE_DRAGONS_WITHOUT_OWL) {
158 if (NEEDS_UPDATE(dragons_examined_without_owl))
159 make_dragons(1);
160 verbose = save_verbose;
161 gg_assert(test_gray_border() < 0);
162 return;
163 }
164
165 if (NEEDS_UPDATE(dragons_examined)) {
166 make_dragons(0);
167 compute_scores(chinese_rules || aftermath_play);
168 /* We have automatically done a partial dragon analysis as well. */
169 dragons_examined_without_owl = position_number;
170 }
171 if (how_much == EXAMINE_DRAGONS) {
172 verbose = save_verbose;
173 gg_assert(test_gray_border() < 0);
174 return;
175 }
176 }
177 else if (how_much == EXAMINE_INITIAL_INFLUENCE
178 || how_much == EXAMINE_DRAGONS
179 || how_much == EXAMINE_ALL) {
180 initialize_dragon_data();
181 compute_scores(chinese_rules || aftermath_play);
182 verbose = save_verbose;
183 gg_assert(test_gray_border() < 0);
184 return;
185 }
186
187 verbose = save_verbose;
188
189 if (NEEDS_UPDATE(initial_influence2_examined)) {
190 compute_dragon_influence();
191 }
192 if (how_much == EXAMINE_INITIAL_INFLUENCE2) {
193 gg_assert(test_gray_border() < 0);
194 return;
195 }
196
197 if (NEEDS_UPDATE(dragons_refinedly_examined)) {
198 compute_refined_dragon_weaknesses();
199 compute_strategic_sizes();
200 }
201 if (how_much == FULL_EXAMINE_DRAGONS) {
202 gg_assert(test_gray_border() < 0);
203 return;
204 }
205
206 if (printworms)
207 show_dragons();
208}
209
210
211/* The same as examine_position(), except that all traces, debug
212 * output, and sgf traces are turned off.
213 */
214void
215silent_examine_position(int how_much)
216{
217 int save_verbose = verbose;
218 SGFTree *save_sgf_dumptree = sgf_dumptree;
219 int save_count_variations = count_variations;
220 int save_debug = debug;
221 int save_printmoyo = printmoyo;
222
223 verbose = 0;
224 sgf_dumptree = NULL;
225 count_variations = 0;
226 debug = 0;
227 printmoyo = 0;
228
229 examine_position(how_much, 0);
230
231 verbose = save_verbose;
232 sgf_dumptree = save_sgf_dumptree;
233 count_variations = save_count_variations;
234 debug = save_debug;
235 printmoyo = save_printmoyo;
236}
237
238
239/*
240 * Generate computer move for color.
241 *
242 * Return the generated move.
243 */
244
245int
246genmove(int color, float *value, int *resign)
247{
248 int move = PASS_MOVE;
249 if (resign)
250 *resign = 0;
251
252#if ORACLE
253 if (metamachine) {
254 move = metamachine_genmove(color, value, limit_search);
255 gg_assert(stackp == 0);
256 if (move != PASS_MOVE)
257 return move;
258 }
259#endif
260
261 if (limit_search)
262 move = do_genmove(color, 0.4, search_mask, value, resign);
263 else
264 move = do_genmove(color, 0.4, NULL, value, resign);
265 gg_assert(move == PASS_MOVE || ON_BOARD(move));
266
267 return move;
268}
269
270
271/*
272 * Same as above but doesn't generate pure threat moves. Useful when
273 * trying to score a game.
274 */
275
276int
277genmove_conservative(int color, float *value)
278{
279 return do_genmove(color, 0.0, NULL, value, NULL);
280}
281
282
283int
284genmove_restricted(int color, int allowed_moves[BOARDMAX])
285{
286 return do_genmove(color, 0.0, allowed_moves, NULL, NULL);
287}
288
289/* This function collects move reasons can be generated immediately from
290 * the data gathered in the examine_position() phase.
291 */
292void
293collect_move_reasons(int color)
294{
295 worm_reasons(color);
296 semeai_move_reasons(color);
297 owl_reasons(color);
298 cut_reasons(color);
299 break_in_move_reasons(color);
300 unconditional_move_reasons(color);
301}
302
303/* Call Monte Carlo module to generate a move. */
304static int
305monte_carlo_genmove(int color, int allowed_moves[BOARDMAX],
306 float *value, int *resign)
307{
308 int pos;
309 int best_move = PASS_MOVE;
310 int best_uct_move = PASS_MOVE;
311 int unconditional_territory_black[BOARDMAX];
312 int unconditional_territory_white[BOARDMAX];
313 int forbidden_move[BOARDMAX];
314 float move_values[BOARDMAX];
315 int move_frequencies[BOARDMAX];
316 float best_value;
317 int frequency_cutoff;
318 int frequency_cutoff2;
319 int number_of_simulations;
320
321 memset(move_values, 0, sizeof(move_values));
322 memset(move_frequencies, 0, sizeof(move_frequencies));
323
324 if (0) {
325 simple_showboard(stderr);
326 gprintf("\n");
327 }
328
329 if (resign)
330 *resign = 0;
331
332 unconditional_life(unconditional_territory_black, BLACK);
333 unconditional_life(unconditional_territory_white, WHITE);
334
335 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
336 if (!ON_BOARD(pos))
337 continue;
338 else if (unconditional_territory_black[pos])
339 forbidden_move[pos] = BLACK;
340 else if (unconditional_territory_white[pos])
341 forbidden_move[pos] = WHITE;
342 else
343 forbidden_move[pos] = 0;
344
345 number_of_simulations = mc_games_per_level * gg_max(get_level(), 1);
346
347 uct_genmove(color, &best_uct_move, forbidden_move, allowed_moves,
348 number_of_simulations, move_values, move_frequencies);
349
350 best_move = best_uct_move;
351 best_value = 0.0;
352 frequency_cutoff = move_frequencies[best_uct_move] / 2;
353 frequency_cutoff2 = move_frequencies[best_uct_move] / 10;
354 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
355 if (ON_BOARD(pos)
356 && (move_frequencies[pos] > frequency_cutoff
357 || (move_values[pos] > 0.9
358 && move_frequencies[pos] > frequency_cutoff2)
359 || move_values[best_uct_move] < 0.1)
360 && (!allowed_moves || allowed_moves[pos])
361 && potential_moves[pos] > best_value) {
362 best_move = pos;
363 best_value = potential_moves[pos];
364 }
365 }
366
367 unconditionally_meaningless_move(best_move, color, &best_move);
368
369 *value = 1.0;
370
371 return best_move;
372}
373
374
375/*
376 * Perform the actual move generation.
377 *
378 * The array allowed_moves restricts which moves may be considered. If
379 * NULL any move is allowed. Pass is always allowed and will be chosen
380 * if the move generation doesn't like any of the allowed moves (or
381 * overlooks them).
382 */
383
384static int
385do_genmove(int color, float pure_threat_value,
386 int allowed_moves[BOARDMAX], float *value, int *resign)
387{
388 float average_score, pessimistic_score, optimistic_score;
389 int save_verbose;
390 int save_depth;
391 int move;
392 float dummy_value;
393 int use_thrashing_dragon_heuristics = 0;
394
395 if (!value)
396 value = &dummy_value;
397
398 start_timer(0);
399 clearstats();
400
401 /* Usually we would not recommend resignation. */
402 if (resign)
403 *resign = 0;
404
405 /* Prepare our table of moves considered. */
406 memset(potential_moves, 0, sizeof(potential_moves));
407
408 /* no move is found yet. */
409 move = PASS_MOVE;
410 *value = 0.0;
411
412 /* Prepare pattern matcher and reading code. */
413 reset_engine();
414
415 /* Store the depth value so we can check that it hasn't changed when
416 * we leave this function.
417 */
418 save_depth = depth;
419
420 /* If in mirror mode, try to find a mirror move. */
421 if (play_mirror_go
422 && (mirror_stones_limit < 0
423 || stones_on_board(WHITE | BLACK) <= mirror_stones_limit)
424 && find_mirror_move(&move, color)) {
425 TRACE("genmove() recommends mirror move at %1m\n", move);
426 *value = 1.0;
427 return move;
428 }
429
430 /* Find out information about the worms and dragons. */
431 start_timer(1);
432 examine_position(EXAMINE_ALL, 0);
433 time_report(1, "examine position", NO_MOVE, 1.0);
434
435
436 /* The score will be used to determine when we are safely
437 * ahead. So we want the most conservative score.
438 *
439 * We always want to have the score from our point of view. So
440 * negate it if we are black.
441 */
442 if (color == WHITE) {
443 pessimistic_score = black_score;
444 optimistic_score = white_score;
445 }
446 else {
447 pessimistic_score = -white_score;
448 optimistic_score = -black_score;
449 }
450
451 if (color == WHITE)
452 average_score = (white_score + black_score)/2.0;
453 else
454 average_score = -(white_score + black_score)/2.0;
455 choose_strategy(color, average_score, game_status(color));
456
457 if (printboard) {
458 if (printboard == 1)
459 fprintf(stderr, "\n dragon_status display:\n\n");
460 if (printboard == 2)
461 fprintf(stderr, "\n eye display:\n\n");
462 showboard(printboard);
463 if (printboard == 1) {
464 fprintf(stderr, "\n owl_status display:\n\n");
465 showboard(3);
466 fprintf(stderr, "\n matcher_status display:\n\n");
467 showboard(4);
468 }
469 }
470
471 gg_assert(stackp == 0);
472
473 /*
474 * Ok, information gathering is complete. Now start to find some moves!
475 */
476
477
478 /* Pick up moves that we know of already. */
479 save_verbose = verbose;
480 if (verbose > 0)
481 verbose--;
482 collect_move_reasons(color);
483 verbose = save_verbose;
484 time_report(1, "generate move reasons", NO_MOVE, 1.0);
485
486 /* Try to find empty corner moves. */
487 fuseki(color);
488 gg_assert(stackp == 0);
489
490 /* Look for moves to break mirror play by the opponent. */
491 break_mirror_go(color);
492
493 /* If we are ahead by 5 points or more, consider a thrashing
494 * dragon dangerous and change its status from DEAD to
495 * UNKNOWN. Otherwise, pretend there is no thrashing dragon.
496 */
497 if (!doing_scoring)
498 use_thrashing_dragon_heuristics
499 = revise_thrashing_dragon(color, pessimistic_score, 5.0);
500
501 /* The general pattern database. */
502 shapes(color);
503 time_report(1, "shapes", NO_MOVE, 1.0);
504 gg_assert(stackp == 0);
505
506 /* Look for combination attacks and defenses against them. */
507 combinations(color);
508 time_report(1, "combinations", NO_MOVE, 1.0);
509 gg_assert(stackp == 0);
510
511 /* Review the move reasons and estimate move values. */
512 if (review_move_reasons(&move, value, color,
513 pure_threat_value, pessimistic_score, allowed_moves,
514 use_thrashing_dragon_heuristics))
515 TRACE("Move generation likes %1m with value %f\n", move, *value);
516 gg_assert(stackp == 0);
517 time_report(1, "review move reasons", NO_MOVE, 1.0);
518
519
520 /* If the move value is 6 or lower, we look for endgame patterns too. */
521 if (*value <= 6.0 && !disable_endgame_patterns) {
522 endgame_shapes(color);
523 endgame(color);
524 gg_assert(stackp == 0);
525 if (review_move_reasons(&move, value, color, pure_threat_value,
526 pessimistic_score, allowed_moves,
527 use_thrashing_dragon_heuristics))
528 TRACE("Move generation likes %1m with value %f\n", move, *value);
529 gg_assert(stackp == 0);
530 time_report(1, "endgame", NO_MOVE, 1.0);
531 }
532
533 /* If no move found yet, revisit any semeai and change the
534 * status of the opponent group from DEAD to UNKNOWN, then
535 * run shapes and endgame_shapes again. This may turn up a move.
536 */
537 if (move == PASS_MOVE) {
538 if (revise_semeai(color)) {
539 shapes(color);
540 endgame_shapes(color);
541 if (review_move_reasons(&move, value, color, pure_threat_value,
542 pessimistic_score, allowed_moves,
543 use_thrashing_dragon_heuristics)) {
544 TRACE("Upon reconsideration move generation likes %1m with value %f\n",
545 move, *value);
546 }
547 }
548 time_report(1, "move reasons with revised semeai status",
549 NO_MOVE, 1.0);
550 }
551
552 /* If Monte Carlo move generation is enabled, call it now. Do not
553 * override a fuseki move.
554 *
555 * FIXME: Identifying fuseki moves by checking the move value is
556 * very ugly and fragile.
557 */
558 if (use_monte_carlo_genmove && move != PASS_MOVE
559 && (*value < 75.0 || *value > 75.01) && !doing_scoring) {
560 int allowed_moves2[BOARDMAX];
561 int num_allowed_moves2 = 0;
562 int pos;
563 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
564 if (ON_BOARD(pos)
565 && (!allowed_moves || allowed_moves[pos])
566 && is_allowed_move(pos, color)) {
567 allowed_moves2[pos] = 1;
568 num_allowed_moves2++;
569 }
570 else
571 allowed_moves2[pos] = 0;
572
573 if (num_allowed_moves2 > 1)
574 move = monte_carlo_genmove(color, allowed_moves2, value, resign);
575 }
576
577 /* If still no move, fill a remaining liberty. This should pick up
578 * all missing dame points.
579 */
580 if (move == PASS_MOVE
581 && fill_liberty(&move, color)) {
582 if (!allowed_moves || allowed_moves[move]) {
583 *value = 1.0;
584 TRACE("Filling a liberty at %1m\n", move);
585 record_top_move(move, *value);
586 move_considered(move, *value);
587 time_report(1, "fill liberty", NO_MOVE, 1.0);
588 }
589 else
590 move = PASS_MOVE;
591 }
592
593 /* If we're instructed to play out the aftermath or capture all dead
594 * opponent stones, or if the opponent is trying to live inside
595 * our territory and we are clearly ahead, generate an aftermath move.
596 */
597 if (move == PASS_MOVE) {
598 if (play_out_aftermath
599 || capture_all_dead
600 || (!doing_scoring && thrashing_dragon && pessimistic_score > 15.0))
601 move = aftermath_genmove(color, capture_all_dead, allowed_moves);
602
603 if (move != PASS_MOVE) {
604 ASSERT1(is_legal(move, color), move);
605 *value = 1.0;
606 TRACE("Aftermath move at %1m\n", move);
607 record_top_move(move, *value);
608 move_considered(move, *value);
609 time_report(1, "aftermath_genmove", NO_MOVE, 1.0);
610 }
611 }
612
613 /* If we somehow have managed to generate an illegal move, pass instead. */
614 if (!is_allowed_move(move, color)) {
615 TRACE("ILLEGAL MOVE GENERATED. Passing instead.\n");
616 move = PASS_MOVE;
617 *value = -1.0;
618 }
619
620 /* If no move is found then pass. */
621 if (move == PASS_MOVE) {
622 TRACE("I pass.\n");
623 }
624 else {
625 TRACE("genmove() recommends %1m with value %f\n", move, *value);
626 }
627
628 /* Maybe time to resign...
629 */
630 if (resign && resign_allowed
631 && *value < 10.0 && should_resign(color, optimistic_score, move)) {
632 TRACE("... though, genmove() thinks the position is hopeless\n");
633 *resign = 1;
634 }
635
636 /* If statistics is turned on, this is the place to show it. */
637 if (showstatistics)
638 showstats();
639
640 if (showtime) {
641 double spent = time_report(0, "TIME to generate move at ", move, 1.0);
642 total_time += spent;
643 if (spent > slowest_time) {
644 slowest_time = spent;
645 slowest_move = move;
646 slowest_movenum = movenum + 1;
647 }
648 }
649
650 /* Some consistency checks to verify that things are properly
651 * restored and/or have not been corrupted.
652 */
653 gg_assert(stackp == 0);
654 gg_assert(test_gray_border() < 0);
655 gg_assert(depth == save_depth);
656
657 return move;
658}
659
660
661
662/* This is called for each move which has been considered. For
663 * debugging purposes, we keep a table of all the moves we
664 * have considered.
665 */
666
667void
668move_considered(int move, float value)
669{
670 if (value > potential_moves[move])
671 potential_moves[move] = value;
672}
673
674
675/* revise_semeai(color) changes the status of any DEAD dragon of
676 * OPPOSITE_COLOR(color) which occurs in a semeai to UNKNOWN.
677 * It returns true if such a dragon is found.
678 */
679
680static int
681revise_semeai(int color)
682{
683 int pos;
684 int found_one = 0;
685 int other = OTHER_COLOR(color);
686
687 if (stones_on_board(BLACK | WHITE) == 0)
688 return 0;
689
690 if (doing_scoring)
691 return 0;
692
693 gg_assert(dragon2 != NULL);
694
695 for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
696 if (ON_BOARD(pos)
697 && dragon[pos].color == other
698 && DRAGON2(pos).semeais
699 && dragon[pos].status == DEAD) {
700 found_one = 1;
701 dragon[pos].status = UNKNOWN;
702 if (dragon[pos].origin == pos)
703 TRACE("revise_semeai: changed status of dragon %1m from DEAD to UNKNOWN\n",
704 pos);
705 }
706 }
707
708 return found_one;
709}
710
711
712/* If the opponent's last move added a stone to a dead dragon,
713 * revise it's status to UNKNOWN. This will cause genmove to
714 * generate moves restraining the dragon. We only do this if
715 * we are ahead by 'advantage', and no owl threat has been found.
716 */
717
718static int
719revise_thrashing_dragon(int color, float our_score, float advantage)
720{
721 int pos;
722 signed char safe_stones[BOARDMAX];
723 float strength[BOARDMAX];
724
725 /* Trust the owl code's opinion if we are behind. */
726 if (our_score < advantage)
727 return 0;
728
729 if (disable_threat_computation
730 || !thrashing_dragon
731 || dragon[thrashing_dragon].status != DEAD)
732 return 0;
733
734 for (pos = BOARDMIN; pos < BOARDMAX; pos++)
735 if (ON_BOARD(pos) && thrashing_stone[pos]
736 && worm[pos].unconditional_status != DEAD) {
737 dragon[pos].status = UNKNOWN;
738 DRAGON2(pos).safety = ALIVE;
739 }
740
741 set_strength_data(OTHER_COLOR(color), safe_stones, strength);
742 compute_influence(OTHER_COLOR(color), safe_stones, strength,
743 OPPOSITE_INFLUENCE(color),
744 NO_MOVE, "revised thrashing dragon");
745 compute_refined_dragon_weaknesses();
746
747 return 1;
748}
749
750
751/* Look for a mirror move. First try the mirror of the last move. If
752 * none is available, test all moves to see if one makes the board
753 * symmetric.
754 *
755 * To be able to deal with handicap stones we use a somewhat weak
756 * definition of symmetry.
757 */
758
759static int
760find_mirror_move(int *move, int color)
761{
762 int last_move = get_last_move();
763 int mirror_move;
764 if (last_move != NO_MOVE) {
765 mirror_move = MIRROR_MOVE(last_move);
766 if (test_symmetry_after_move(mirror_move, color, 0)) {
767 *move = mirror_move;
768 return 1;
769 }
770 }
771 else {
772 for (mirror_move = BOARDMIN; mirror_move < BOARDMAX; mirror_move++) {
773 if (ON_BOARD(mirror_move)
774 && test_symmetry_after_move(mirror_move, color, 0)) {
775 *move = mirror_move;
776 return 1;
777 }
778 }
779 }
780
781 return 0;
782}
783
784/* Computer two territory estimates: for *upper, the status of all
785 * cricital stones gets resolved in White's favor; vice verso for
786 * black.
787 */
788static void
789compute_scores(int use_chinese_rules)
790{
791 signed char safe_stones[BOARDMAX];
792 float strength[BOARDMAX];
793
794 set_strength_data(WHITE, safe_stones, strength);
795 compute_influence(EMPTY, safe_stones, strength, &move_influence,
796 NO_MOVE, "White territory estimate");
797 white_score = influence_score(&move_influence, use_chinese_rules);
798 set_strength_data(BLACK, safe_stones, strength);
799 compute_influence(EMPTY, safe_stones, strength, &move_influence,
800 NO_MOVE, "White territory estimate");
801 black_score = influence_score(&move_influence, use_chinese_rules);
802
803 if (verbose || showscore) {
804 if (white_score == black_score)
805 gprintf("Score estimate: %s %f\n",
806 black_score > 0 ? "W " : "B ", gg_abs(black_score));
807 else
808 gprintf("Score estimate: %s %f to %s %f\n",
809 black_score > 0 ? "W " : "B ", gg_abs(black_score),
810 white_score > 0 ? "W " : "B ", gg_abs(white_score));
811 fflush(stderr);
812 }
813}
814
815
816/* Detect if a white opponent has played mirror go for at least 10
817 * moves and if so play on tengen.
818 *
819 * Mirror breaking moves in other situations are handled by patterns
820 * in patterns.db.
821 */
822static void
823break_mirror_go(int color)
824{
825 int tengen = POS((board_size - 1) / 2, (board_size - 1) / 2);
826 if (board[tengen] == EMPTY
827 && color == BLACK
828 && stones_on_board(BLACK | WHITE) > 10
829 && test_symmetry_after_move(tengen, color, 1)) {
830 set_minimum_move_value(tengen, 30.0);
831 TRACE("Play %1m to break mirror go, value 30.\n", tengen);
832 }
833}
834
835
836/* Helper to decide whether GG should resign a game
837 */
838static int
839should_resign(int color, float optimistic_score, int move)
840{
841 float status;
842 int d;
843 /* We resign 19x19 games only, smaller board games are fast enough.
844 * We resign only if the margin is bigger than 45 pts and if we are
845 * behind (of course).
846 *
847 * As an exception to this rule, we resign on any board size if
848 * it looks like all our dragons are dead and the generated move
849 * is a pass.
850 */
851 if (board_size > 2 && move == PASS_MOVE && !lively_dragon_exists(color))
852 return 1;
853
854 if (move == PASS_MOVE
855 || board_size < 19
856 || optimistic_score > -45.0)
857 return 0;
858 /* Check dragon statuses. If a friendly dragon is critical, we are
859 * possibly not that much behind after we save it. If some hostile
860 * dragon is at least weak, we possibly have a chance to come back
861 * if we can kill it.
862 */
863 for (d = 0; d < number_of_dragons; d++) {
864 /* any friendly critical dragon ? */
865 if (board[dragon2[d].origin] == color
866 && DRAGON(d).status == CRITICAL)
867 return 0;
868 /* any weak opponent dragon ? */
869 if (board[dragon2[d].origin] == OTHER_COLOR(color)
870 && DRAGON(d).status != DEAD
871 && DRAGON(d).effective_size >= 10
872 && dragon_weak(dragon2[d].origin))
873 return 0;
874 }
875 /* Is it already too late to try something ? */
876 status = game_status(color);
877 if (status < 0.8)
878 /* Still "too early".
879 * Note: the 0.8 constant is very conservative, we actually could give
880 * up a bit earlier.
881 */
882 return 0;
883
884 /* well, it is probably reasonable and polite to give up this game */
885 return 1;
886}
887
888
889/*********************************************************************\
890 * Mark a limited search area *
891\*********************************************************************/
892
893/* Activate or deactivate search limit. */
894void
895set_limit_search(int value)
896{
897 limit_search = value;
898}
899
900/* The following function marks a diamond of radius 6 with center pos. */
901
902void
903set_search_diamond(int pos)
904{
905 int i = I(pos);
906 int j = J(pos);
907 int m, n;
908
909 for (m = 0; m < board_size; m++)
910 for (n = 0; n < board_size; n++) {
911 if (gg_abs(m - i) + gg_abs(n - j) <= 6)
912 search_mask[POS(m, n)] = 1;
913 else
914 search_mask[POS(m, n)] = 0;
915 }
916 limit_search = pos;
917 if (0)
918 draw_search_area();
919}
920
921/* unmarks the entire board */
922
923void
924reset_search_mask()
925{
926 memset(search_mask, 0, sizeof(search_mask));
927}
928
929/* marks a single vertex */
930
931void
932set_search_mask(int pos, int value)
933{
934 search_mask[pos] = value;
935}
936
937/* displays the search area */
938
939void
940draw_search_area(void)
941{
942 int m, n;
943
944 start_draw_board();
945 for (m = 0; m < board_size; m++)
946 for (n = 0; n < board_size; n++) {
947 int col, c;
948
949 if (search_mask[POS(m, n)])
950 col = GG_COLOR_RED;
951 else
952 col = GG_COLOR_BLACK;
953
954 if (board[POS(m, n)] == BLACK)
955 c = 'X';
956 else if (board[POS(m, n)] == WHITE)
957 c = 'O';
958 else if (search_mask[POS(m, n)])
959 c = '*';
960 else
961 c = '.';
962 draw_color_char(m, n, c, col);
963 }
964 end_draw_board();
965}
966
967/* returns true if the position is within the search area */
968int
969within_search_area(int pos)
970{
971 if (!limit_search)
972 return 1;
973 return search_mask[pos];
974}
975
976/*
977 * Local Variables:
978 * tab-width: 8
979 * c-basic-offset: 2
980 * End:
981 */