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 #include <math.h>
30 
31 #include "liberty.h"
32 #include "gg_utils.h"
33 #include "random.h"
34 #include "move_reasons.h"
35 
36 
37 /* All these data structures are declared in move_reasons.h */
38 
39 struct move_data move[BOARDMAX];
40 struct move_reason move_reasons[MAX_MOVE_REASONS];
41 int next_reason;
42 
43 /* Connections */
44 int conn_worm1[MAX_CONNECTIONS];
45 int conn_worm2[MAX_CONNECTIONS];
46 int next_connection;
47 
48 /* Potential semeai moves. */
49 int semeai_target1[MAX_POTENTIAL_SEMEAI];
50 int semeai_target2[MAX_POTENTIAL_SEMEAI];
51 static int next_semeai;
52 
53 /* Unordered sets (currently pairs) of move reasons / targets */
54 Reason_set either_data[MAX_EITHER];
55 int next_either;
56 Reason_set all_data[MAX_ALL];
57 int next_all;
58 
59 /* Eye shapes */
60 int eyes[MAX_EYES];
61 int eyecolor[MAX_EYES];
62 int next_eye;
63 
64 /* Lunches */
65 int lunch_dragon[MAX_LUNCHES]; /* eater */
66 int lunch_worm[MAX_LUNCHES];   /* food */
67 int next_lunch;
68 
69 /* Point redistribution */
70 int replacement_map[BOARDMAX];
71 
72 /* The color for which we are evaluating moves. */
73 int current_color;
74 
75 /* Attack threats that are known to be sente locally. */
76 static int known_good_attack_threats[BOARDMAX][MAX_ATTACK_THREATS];
77 
78 /* Moves that are known to be safe (in the sense that played stones can
79  * be captured, but opponent loses much more when attempting to do so)
80  */
81 static int known_safe_moves[BOARDMAX];
82 
83 /* Helper functions to check conditions in discard rules. */
84 typedef int (*discard_condition_fn_ptr)(int pos, int what);
85 
86 struct discard_rule {
87   int reason_type[MAX_REASONS];
88   discard_condition_fn_ptr condition;
89   int flags;
90   char trace_message[MAX_TRACE_LENGTH];
91 };
92 
93 
94 /* Initialize move reason data structures. */
95 void
clear_move_reasons(void)96 clear_move_reasons(void)
97 {
98   int pos;
99   int k;
100   next_reason = 0;
101   next_connection = 0;
102   next_semeai = 0;
103   next_either = 0;
104   next_all = 0;
105   next_eye = 0;
106   next_lunch = 0;
107 
108   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
109     if (ON_BOARD(pos)) {
110       move[pos].value                    = 0.0;
111       move[pos].final_value              = 0.0;
112       move[pos].additional_ko_value      = 0.0;
113       move[pos].territorial_value        = 0.0;
114       move[pos].strategical_value        = 0.0;
115       move[pos].maxpos_shape             = 0.0;
116       move[pos].numpos_shape             = 0;
117       move[pos].maxneg_shape             = 0.0;
118       move[pos].numneg_shape             = 0;
119       move[pos].followup_value           = 0.0;
120       move[pos].influence_followup_value = 0.0;
121       move[pos].reverse_followup_value   = 0.0;
122       move[pos].secondary_value          = 0.0;
123       move[pos].min_value                = 0.0;
124       move[pos].max_value                = HUGE_MOVE_VALUE;
125       move[pos].min_territory            = 0.0;
126       move[pos].max_territory            = HUGE_MOVE_VALUE;
127       for (k = 0; k < MAX_REASONS; k++)
128 	move[pos].reason[k]              = -1;
129       move[pos].move_safety              = 0;
130       move[pos].worthwhile_threat        = 0;
131       move[pos].randomness_scaling       = 1.0;
132       /* The reason we assign a random number to each move immediately
133        * is to avoid dependence on which moves are evaluated when it
134        * comes to choosing between multiple moves of the same value.
135        * In this way we can get consistent results for use in the
136        * regression tests.
137        */
138       move[pos].random_number            = gg_drand();
139 
140       /* Do not send away the points (yet). */
141       replacement_map[pos] = NO_MOVE;
142     }
143   }
144 
145   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
146     known_safe_moves[pos] = 0;
147     for (k = 0; k < MAX_ATTACK_THREATS; k++)
148       known_good_attack_threats[pos][k] = NO_MOVE;
149   }
150 }
151 
152 
153 /*
154  * Find the index of a connection in the list of connections.
155  * If necessary, add a new entry.
156  */
157 int
find_connection(int worm1,int worm2)158 find_connection(int worm1, int worm2)
159 {
160   int k;
161 
162   if (worm1 > worm2) {
163     /* Swap to canonical order. */
164     int tmp = worm1;
165     worm1 = worm2;
166     worm2 = tmp;
167   }
168 
169   for (k = 0; k < next_connection; k++)
170     if (conn_worm1[k] == worm1 && conn_worm2[k] == worm2)
171       return k;
172 
173   /* Add a new entry. */
174   gg_assert(next_connection < MAX_CONNECTIONS);
175   conn_worm1[next_connection] = worm1;
176   conn_worm2[next_connection] = worm2;
177   next_connection++;
178   return next_connection - 1;
179 }
180 
181 
182 static int
find_either_data(int reason1,int what1,int reason2,int what2)183 find_either_data(int reason1, int what1, int reason2, int what2)
184 {
185   int k;
186 
187   /* Make sure the worms are ordered canonically. */
188   if (what1 > what2) {
189     int tmp = what1;
190     what1 = what2;
191     what2 = tmp;
192   }
193 
194   for (k = 0; k < next_either; k++)
195     if (either_data[k].reason1    == reason1
196 	&& either_data[k].what1   == what1
197 	&& either_data[k].reason2 == reason2
198 	&& either_data[k].what2   == what2)
199       return k;
200 
201   /* Add a new entry. */
202   gg_assert(next_either < MAX_EITHER);
203   either_data[next_either].reason1 = reason1;
204   either_data[next_either].what1   = what1;
205   either_data[next_either].reason2 = reason2;
206   either_data[next_either].what2   = what2;
207   next_either++;
208   return next_either - 1;
209 }
210 
211 static int
find_all_data(int reason1,int what1,int reason2,int what2)212 find_all_data(int reason1, int what1, int reason2, int what2)
213 {
214   int k;
215 
216   /* Make sure the worms are ordered canonically. */
217   if (what1 > what2) {
218     int tmp = what1;
219     what1 = what2;
220     what2 = tmp;
221   }
222 
223   for (k = 0; k < next_all; k++)
224     if (all_data[k].reason1    == reason1
225 	&& all_data[k].what1   == what1
226 	&& all_data[k].reason2 == reason2
227 	&& all_data[k].what2   == what2)
228       return k;
229 
230   /* Add a new entry. */
231   gg_assert(next_all < MAX_ALL);
232   all_data[next_all].reason1 = reason1;
233   all_data[next_all].what1   = what1;
234   all_data[next_all].reason2 = reason2;
235   all_data[next_all].what2   = what2;
236   next_all++;
237   return next_all - 1;
238 }
239 
240 static int
find_pair_data(int what1,int what2)241 find_pair_data(int what1, int what2)
242 {
243   int k;
244 
245   for (k = 0; k < next_either; k++)
246     if (either_data[k].what1 == what1
247 	&& either_data[k].what2 == what2)
248       return k;
249 
250   /* Add a new entry. */
251   gg_assert(next_either < MAX_EITHER);
252   either_data[next_either].what1   = what1;
253   either_data[next_either].what2   = what2;
254   next_either++;
255   return next_either - 1;
256 }
257 
258 
259 /* Interprets the object of a reason and returns its position.
260  * If the object is a pair (of worms or dragons), the position of the first
261  * object is returned. (This is only used for trace outputs.) Returns
262  * NO_MOVE if move does not point to a location.
263  * FIXME: This new function produces some code duplication with other
264  * trace output function. Do some code cleanup here.
265  */
266 static int
get_pos(int reason,int what)267 get_pos(int reason, int what)
268 {
269   switch (reason) {
270   case ATTACK_MOVE:
271   case DEFEND_MOVE:
272   case ATTACK_THREAT:
273   case DEFEND_THREAT:
274   case ATTACK_MOVE_GOOD_KO:
275   case ATTACK_MOVE_BAD_KO:
276   case DEFEND_MOVE_GOOD_KO:
277   case DEFEND_MOVE_BAD_KO:
278     return what;
279 
280   case SEMEAI_MOVE:
281   case SEMEAI_THREAT:
282   case STRATEGIC_ATTACK_MOVE:
283   case STRATEGIC_DEFEND_MOVE:
284   case OWL_ATTACK_MOVE:
285   case OWL_DEFEND_MOVE:
286   case OWL_ATTACK_THREAT:
287   case OWL_DEFEND_THREAT:
288   case OWL_PREVENT_THREAT:
289   case UNCERTAIN_OWL_ATTACK:
290   case UNCERTAIN_OWL_DEFENSE:
291   case OWL_ATTACK_MOVE_GOOD_KO:
292   case OWL_ATTACK_MOVE_BAD_KO:
293   case OWL_DEFEND_MOVE_GOOD_KO:
294   case OWL_DEFEND_MOVE_BAD_KO:
295     return what;
296 
297   case EITHER_MOVE:
298     /* FIXME: What should we return here? */
299     return either_data[what].what1;
300 
301   case ALL_MOVE:
302     /* FIXME: What should we return here? */
303     return all_data[what].what1;
304 
305   case CONNECT_MOVE:
306   case CUT_MOVE:
307     return conn_worm1[what];
308 
309   case ANTISUJI_MOVE:
310   case EXPAND_TERRITORY_MOVE:
311   case EXPAND_MOYO_MOVE:
312   case INVASION_MOVE:
313   case MY_ATARI_ATARI_MOVE:
314   case YOUR_ATARI_ATARI_MOVE:
315     return NO_MOVE;
316 
317   case OWL_ATTACK_MOVE_GAIN:
318   case OWL_DEFEND_MOVE_LOSS:
319     /* FIXME: What should we return here? */
320     return either_data[what].what1;
321 
322   default:
323     /* We should never get here: */
324     gg_assert(0);
325     return 0; /* To keep gcc happy. */
326   }
327 }
328 
329 /*
330  * See if a lunch is already in the list of lunches, otherwise add a new
331  * entry. A lunch is in this context a pair of eater (a dragon) and food
332  * (a worm).
333  */
334 void
add_lunch(int eater,int food)335 add_lunch(int eater, int food)
336 {
337   int k;
338   int dragon1 = dragon[eater].origin;
339   int worm1   = worm[food].origin;
340   ASSERT_ON_BOARD1(eater);
341   ASSERT_ON_BOARD1(food);
342 
343   for (k = 0; k < next_lunch; k++)
344     if ((lunch_dragon[k] == dragon1) && (lunch_worm[k] == worm1))
345       return;
346 
347   /* Add a new entry. */
348   gg_assert(next_lunch < MAX_LUNCHES);
349   lunch_dragon[next_lunch] = dragon1;
350   lunch_worm[next_lunch] = worm1;
351   next_lunch++;
352   return;
353 }
354 
355 /* ---------------------------------------------------------------- */
356 
357 
358 /*
359  * Add a move reason for (pos) if it's not already there or the
360  * table is full.
361  */
362 static void
add_move_reason(int pos,int type,int what)363 add_move_reason(int pos, int type, int what)
364 {
365   int k;
366 
367   ASSERT_ON_BOARD1(pos);
368   if (stackp == 0) {
369     ASSERT1(board[pos] == EMPTY, pos);
370   }
371 
372   for (k = 0; k < MAX_REASONS; k++) {
373     int r = move[pos].reason[k];
374     if (r < 0)
375       break;
376     if (move_reasons[r].type == type
377 	&& move_reasons[r].what == what)
378       return;  /* Reason already listed. */
379   }
380 
381   /* Reason not found, add it if there is place left in both lists.
382    * Otherwise drop it.
383    */
384   if (k >= MAX_REASONS) {
385     DEBUG(DEBUG_MOVE_REASONS,
386 	  "Move reason at %1m (type=%d, what=%d) dropped because list full.\n",
387 	  pos, type, what);
388     return;
389   }
390 
391   if (next_reason >= MAX_MOVE_REASONS) {
392     DEBUG(DEBUG_MOVE_REASONS,
393 	  "Move reason at %1m (type=%d, what=%d) dropped because global list full.\n",
394 	  pos, type, what);
395     return;
396   }
397 
398   /* Add a new entry. */
399   move[pos].reason[k] = next_reason;
400   move_reasons[next_reason].type = type;
401   move_reasons[next_reason].what = what;
402   move_reasons[next_reason].status = ACTIVE;
403   next_reason++;
404 }
405 
406 /*
407  * Remove a move reason for (pos). Ignore silently if the reason
408  * wasn't there.
409  */
410 static void
remove_move_reason(int pos,int type,int what)411 remove_move_reason(int pos, int type, int what)
412 {
413   int k;
414   int n = -1; /* Position of the move reason to be deleted. */
415 
416   ASSERT_ON_BOARD1(pos);
417   for (k = 0; k < MAX_REASONS; k++) {
418     int r = move[pos].reason[k];
419     if (r < 0)
420       break;
421     if (move_reasons[r].type == type
422 	&& move_reasons[r].what == what)
423       n = k;
424   }
425 
426   if (n == -1)
427     return; /* Move reason wasn't there. */
428 
429   /* Now move the last move reason to position n, thereby removing the
430    * one we were looking for.
431    */
432   k--;
433   move[pos].reason[n] = move[pos].reason[k];
434   move[pos].reason[k] = -1;
435 }
436 
437 
438 /*
439  * Check whether a move reason already is recorded for a move.
440  * A negative value for 'what' means only match 'type'.
441  */
442 int
move_reason_known(int pos,int type,int what)443 move_reason_known(int pos, int type, int what)
444 {
445   int k;
446   int r;
447 
448   ASSERT_ON_BOARD1(pos);
449   for (k = 0; k < MAX_REASONS; k++) {
450     r = move[pos].reason[k];
451     if (r < 0)
452       break;
453     if (move_reasons[r].type == type
454 	&& (what < 0
455 	    || move_reasons[r].what == what))
456       return 1;
457   }
458   return 0;
459 }
460 
461 /* ---------------------------------------------------------------- */
462 
463 /* Functions used in discard_rules follow below. */
464 
465 /*
466  * Check whether an attack move reason already is recorded for a move.
467  * A negative value for 'what' means only match 'type'.
468  */
469 int
attack_move_reason_known(int pos,int what)470 attack_move_reason_known(int pos, int what)
471 {
472   ASSERT1(what < 0 || IS_STONE(board[what]), what);
473   what = worm[what].origin;
474   if (move_reason_known(pos, ATTACK_MOVE, what))
475     return WIN;
476   if (move_reason_known(pos, ATTACK_MOVE_GOOD_KO, what))
477     return KO_A;
478   if (move_reason_known(pos, ATTACK_MOVE_BAD_KO, what))
479     return KO_B;
480   return 0;
481 }
482 
483 /*
484  * Check whether a defense move reason already is recorded for a move.
485  * A negative value for 'what' means only match 'type'.
486  */
487 int
defense_move_reason_known(int pos,int what)488 defense_move_reason_known(int pos, int what)
489 {
490   ASSERT1(what < 0 || IS_STONE(board[what]), what);
491   what = worm[what].origin;
492   if (move_reason_known(pos, DEFEND_MOVE, what))
493     return WIN;
494   if (move_reason_known(pos, DEFEND_MOVE_GOOD_KO, what))
495     return KO_A;
496   if (move_reason_known(pos, DEFEND_MOVE_BAD_KO, what))
497     return KO_B;
498   return 0;
499 }
500 
501 /* Check whether a dragon consists of only one worm. If so, check
502  * whether we know of a tactical attack or defense move.
503  */
504 static int
tactical_move_vs_whole_dragon_known(int pos,int what)505 tactical_move_vs_whole_dragon_known(int pos, int what)
506 {
507   return ((worm[what].size == dragon[what].size)
508 	  && (attack_move_reason_known(pos, what)
509 	      || defense_move_reason_known(pos, what)));
510 }
511 
512 /*
513  * Check whether an owl attack move reason already is recorded for a move.
514  * A negative value for 'what' means only match 'type'.
515  */
516 int
owl_attack_move_reason_known(int pos,int what)517 owl_attack_move_reason_known(int pos, int what)
518 {
519   if (move_reason_known(pos, OWL_ATTACK_MOVE, what))
520     return WIN;
521   if (move_reason_known(pos, OWL_ATTACK_MOVE_GOOD_KO, what))
522     return KO_A;
523   if (move_reason_known(pos, OWL_ATTACK_MOVE_BAD_KO, what))
524     return KO_B;
525   return 0;
526 }
527 
528 /*
529  * Check whether an owl defense move reason already is recorded for a move.
530  * A negative value for 'what' means only match 'type'.
531  */
532 int
owl_defense_move_reason_known(int pos,int what)533 owl_defense_move_reason_known(int pos, int what)
534 {
535   if (move_reason_known(pos, OWL_DEFEND_MOVE, what))
536     return WIN;
537   if (move_reason_known(pos, OWL_DEFEND_MOVE_GOOD_KO, what))
538     return KO_A;
539   if (move_reason_known(pos, OWL_DEFEND_MOVE_BAD_KO, what))
540     return KO_B;
541   return 0;
542 }
543 
544 /*
545  * Check whether an owl attack/defense move reason is recorded for a move.
546  * A negative value for 'what' means only match 'type'.
547  */
548 int
owl_move_reason_known(int pos,int what)549 owl_move_reason_known(int pos, int what)
550 {
551   return (owl_attack_move_reason_known(pos, what)
552           || owl_defense_move_reason_known(pos, what));
553 }
554 
555 /*
556  * Check whether we have an owl attack/defense reason for a move that
557  * involves a specific worm.
558  */
559 static int
owl_move_vs_worm_known(int pos,int what)560 owl_move_vs_worm_known(int pos, int what)
561 {
562   return owl_move_reason_known(pos, dragon[what].origin);
563 }
564 
565 int
semeai_move_reason_known(int pos,int what)566 semeai_move_reason_known(int pos, int what)
567 {
568   return move_reason_known(pos, SEMEAI_MOVE, what);
569 }
570 
571 /* Check whether a worm is inessential */
572 static int
concerns_inessential_worm(int pos,int what)573 concerns_inessential_worm(int pos, int what)
574 {
575   UNUSED(pos);
576   return DRAGON2(what).safety == INESSENTIAL
577         || worm[what].inessential;
578 }
579 
580 /* Check whether a dragon is inessential */
581 static int
concerns_inessential_dragon(int pos,int what)582 concerns_inessential_dragon(int pos, int what)
583 {
584   UNUSED(pos);
585   return DRAGON2(what).safety == INESSENTIAL;
586 }
587 
588 static int
move_is_marked_unsafe(int pos,int what)589 move_is_marked_unsafe(int pos, int what)
590 {
591   UNUSED(what);
592   return (!move[pos].move_safety
593 	  && !adjacent_to_nondead_stone(pos, current_color));
594 }
595 
596 /* Check whether a dragon is non-critical. */
597 static int
concerns_noncritical_dragon(int pos,int what)598 concerns_noncritical_dragon(int pos, int what)
599 {
600   UNUSED(pos);
601   return (dragon[what].status != CRITICAL
602 	  && worm[what].attack_codes[0] == 0);
603 }
604 
605 
606 /* (what) points to two worms listed in either_data. Returns true if
607  * this is a "attack either" move reason, and one of the worms attackable.
608  * FIXME: Ko?
609  */
610 static int
either_worm_attackable(int pos,int what)611 either_worm_attackable(int pos, int what)
612 {
613   UNUSED(pos);
614   return (either_data[what].reason1 == ATTACK_STRING
615       	  && either_data[what].reason2 == ATTACK_STRING
616           && (worm[either_data[what].what1].attack_codes[0] != 0
617               || worm[either_data[what].what2].attack_codes[0] != 0));
618 }
619 
620 /* (what) points to two worms via all_data. Returns true if this is
621  * a "defend both" move reason, and one of the worms is attackable.
622  * FIXME: Ko?
623  */
624 static int
one_of_both_attackable(int pos,int what)625 one_of_both_attackable(int pos, int what)
626 {
627   UNUSED(pos);
628   return (all_data[what].reason1 == DEFEND_STRING
629       	  && all_data[what].reason2 == DEFEND_STRING
630    	  && (worm[all_data[what].what1].attack_codes[0] != 0
631               || worm[all_data[what].what2].attack_codes[0] != 0));
632 }
633 
634 
635 /* ---------------------------------------------------------------- */
636 
637 
638 /*
639  * Add to the reasons for the move at (pos) that it attacks the worm
640  * at (ww).
641  */
642 void
add_attack_move(int pos,int ww,int code)643 add_attack_move(int pos, int ww, int code)
644 {
645   ASSERT_ON_BOARD1(ww);
646   ww = worm[ww].origin;
647 
648   if (code == WIN)
649     add_move_reason(pos, ATTACK_MOVE, ww);
650   else if (code == KO_A)
651     add_move_reason(pos, ATTACK_MOVE_GOOD_KO, ww);
652   else if (code == KO_B)
653     add_move_reason(pos, ATTACK_MOVE_BAD_KO, ww);
654 }
655 
656 /*
657  * Add to the reasons for the move at (pos) that it defends the worm
658  * at (ww).
659  */
660 void
add_defense_move(int pos,int ww,int code)661 add_defense_move(int pos, int ww, int code)
662 {
663   ASSERT_ON_BOARD1(ww);
664   ww = worm[ww].origin;
665 
666   if (code == WIN)
667     add_move_reason(pos, DEFEND_MOVE, ww);
668   else if (code == KO_A)
669     add_move_reason(pos, DEFEND_MOVE_GOOD_KO, ww);
670   else if (code == KO_B)
671     add_move_reason(pos, DEFEND_MOVE_BAD_KO, ww);
672 }
673 
674 /*
675  * Add to the reasons for the move at (pos) that it threatens to
676  * attack the worm at (ww).
677  */
678 void
add_attack_threat_move(int pos,int ww,int code)679 add_attack_threat_move(int pos, int ww, int code)
680 {
681   UNUSED(code);
682 
683   ASSERT_ON_BOARD1(ww);
684   add_move_reason(pos, ATTACK_THREAT, worm[ww].origin);
685 }
686 
687 /* Remove an attack threat move reason. */
688 
689 void
remove_attack_threat_move(int pos,int ww)690 remove_attack_threat_move(int pos, int ww)
691 {
692   ASSERT_ON_BOARD1(ww);
693   remove_move_reason(pos, ATTACK_THREAT, worm[ww].origin);
694 }
695 
696 /*
697  * Add to the reasons for the move at (pos) that it defends the worm
698  * at (ww).
699  */
700 void
add_defense_threat_move(int pos,int ww,int code)701 add_defense_threat_move(int pos, int ww, int code)
702 {
703   UNUSED(code);
704 
705   ASSERT_ON_BOARD1(ww);
706   add_move_reason(pos, DEFEND_THREAT, worm[ww].origin);
707 }
708 
709 
710 /* Report all, or up to max_strings, strings that are threatened
711  * at (pos).
712  */
713 int
get_attack_threats(int pos,int max_strings,int strings[])714 get_attack_threats(int pos, int max_strings, int strings[])
715 {
716   int k;
717   int num_strings;
718 
719   num_strings = 0;
720   for (k = 0; k < MAX_REASONS; k++) {
721     int r = move[pos].reason[k];
722     if (r < 0)
723       break;
724 
725     if (move_reasons[r].type == ATTACK_THREAT)
726       strings[num_strings++] = move_reasons[r].what;
727 
728     if (num_strings == max_strings)
729       break;
730   }
731 
732   return num_strings;
733 }
734 
735 /* Report all, or up to max_strings, strings that might be defended
736  * at (pos).
737  */
738 int
get_defense_threats(int pos,int max_strings,int strings[])739 get_defense_threats(int pos, int max_strings, int strings[])
740 {
741   int k;
742   int num_strings;
743 
744   num_strings = 0;
745   for (k = 0; k < MAX_REASONS; k++) {
746     int r = move[pos].reason[k];
747     if (r < 0)
748       break;
749 
750     if (move_reasons[r].type == DEFEND_THREAT)
751       strings[num_strings++] = move_reasons[r].what;
752 
753     if (num_strings == max_strings)
754       break;
755   }
756 
757   return num_strings;
758 }
759 
760 /* Report the biggest dragon that is owl-affected (possibily with ko)
761  * by a move at (pos).
762  */
763 int
get_biggest_owl_target(int pos)764 get_biggest_owl_target(int pos)
765 {
766   int k;
767   int biggest_target = -1;
768   float target_size = 0.0;
769   for (k = 0; k < MAX_REASONS; k++) {
770     int r = move[pos].reason[k];
771     if (r < 0)
772       break;
773 
774     switch (move_reasons[r].type) {
775     case OWL_ATTACK_MOVE:
776     case OWL_ATTACK_MOVE_GOOD_KO:
777     case OWL_ATTACK_MOVE_BAD_KO:
778     case OWL_ATTACK_THREAT:
779     case OWL_DEFEND_MOVE:
780     case OWL_DEFEND_MOVE_GOOD_KO:
781     case OWL_DEFEND_MOVE_BAD_KO:
782     case OWL_DEFEND_THREAT:
783     case OWL_PREVENT_THREAT:
784       if (dragon[move_reasons[r].what].effective_size > target_size) {
785         biggest_target = move_reasons[r].what;
786         target_size = dragon[move_reasons[r].what].effective_size;
787       }
788       break;
789     }
790   }
791   return biggest_target;
792 }
793 
794 /*
795  * Add to the reasons for the move at (pos) that it connects the
796  * dragons at (dr1) and (dr2). Require that the dragons are
797  * distinct.
798  */
799 void
add_connection_move(int pos,int w1,int w2)800 add_connection_move(int pos, int w1, int w2)
801 {
802   int connection;
803 
804   ASSERT_ON_BOARD1(w1);
805   ASSERT_ON_BOARD1(w2);
806   ASSERT1(worm[w1].color == worm[w2].color, w1);
807   if (worm[w1].origin == worm[w2].origin)
808     return;
809 
810   connection = find_connection(worm[w1].origin, worm[w2].origin);
811   add_move_reason(pos, CONNECT_MOVE, connection);
812 }
813 
814 /*
815  * Add to the reasons for the move at (pos) that it cuts the
816  * dragons at (dr1) and (dr2). Require that the dragons are
817  * distinct.
818  */
819 void
add_cut_move(int pos,int w1,int w2)820 add_cut_move(int pos, int w1, int w2)
821 {
822   int connection;
823 
824   ASSERT_ON_BOARD1(w1);
825   ASSERT_ON_BOARD1(w2);
826   ASSERT1(worm[w1].color == worm[w2].color, w1);
827   if (worm[w1].origin == worm[w2].origin)
828     return;
829   connection = find_connection(worm[w1].origin, worm[w2].origin);
830 
831   /*
832    * Ignore the cut or connection if either (w1) or (w2)
833    * points to a tactically captured worm.
834    */
835   if ((worm[w1].attack_codes[0] != 0 && worm[w1].defense_codes[0] == 0)
836       || (worm[w2].attack_codes[0] != 0 && worm[w2].defense_codes[0] == 0))
837     return;
838 
839   add_move_reason(pos, CUT_MOVE, connection);
840 
841 }
842 
843 /*
844  * Add to the reasons for the move at (pos) that it is an anti-suji.
845  * This means that it's a locally inferior move or for some other reason
846  * must *not* be played.
847  */
848 void
add_antisuji_move(int pos)849 add_antisuji_move(int pos)
850 {
851   add_move_reason(pos, ANTISUJI_MOVE, 0);
852 }
853 
854 /*
855  * Add to the reasons for the move at (pos) that it wins the
856  * dragon (friendly or not) at (dr) in semeai. Since it is
857  * possible that in some semeai one player can kill but the
858  * other can only make seki, it is possible that one dragon
859  * is already alive in seki. Therefore separate move reasons
860  * must be added for the two dragons.
861  */
862 void
add_semeai_move(int pos,int dr)863 add_semeai_move(int pos, int dr)
864 {
865   ASSERT_ON_BOARD1(dr);
866   add_move_reason(pos, SEMEAI_MOVE, dragon[dr].origin);
867 }
868 
869 /*
870  * Add to the reasons for the move at (pos) that it might
871  * kill/save the dragon at (dr1) in the semeai against (dr2).
872  */
873 static void
add_potential_semeai_move(int pos,int type,int dr1,int dr2)874 add_potential_semeai_move(int pos, int type, int dr1, int dr2)
875 {
876   ASSERT1(ON_BOARD(dr1), pos);
877   ASSERT1(ON_BOARD(dr2), pos);
878   if (next_semeai >= MAX_POTENTIAL_SEMEAI)
879     DEBUG(DEBUG_MOVE_REASONS,
880 	  "Potential semeai move at %1m dropped as list was full\n", pos);
881   else {
882     semeai_target1[next_semeai] = dr1;
883     semeai_target2[next_semeai] = dr2;
884     add_move_reason(pos, type, next_semeai);
885     next_semeai++;
886   }
887 }
888 
889 /*
890  * Add to the reasons for the move at (pos) that it might
891  * kill the dragon at (dr1) in the semeai against (dr2).
892  */
893 void
add_potential_semeai_attack(int pos,int dr1,int dr2)894 add_potential_semeai_attack(int pos, int dr1, int dr2)
895 {
896   add_potential_semeai_move(pos, POTENTIAL_SEMEAI_ATTACK, dr1, dr2);
897 }
898 
899 /*
900  * Add to the reasons for the move at (pos) that it might
901  * save the dragon at (dr1) in the semeai against (dr2).
902  */
903 void
add_potential_semeai_defense(int pos,int dr1,int dr2)904 add_potential_semeai_defense(int pos, int dr1, int dr2)
905 {
906   add_potential_semeai_move(pos, POTENTIAL_SEMEAI_DEFENSE, dr1, dr2);
907 }
908 
909 /*
910  * Add to the reasons for the move at (pos) that given two
911  * moves in a row a move here can win the dragon (friendly or
912  * not) at (dr) in semeai. Such a move can be used as a
913  * ko threat, and it is also given some value due to uncertainty
914  * in the counting of liberties.
915  */
916 void
add_semeai_threat(int pos,int dr)917 add_semeai_threat(int pos, int dr)
918 {
919   ASSERT_ON_BOARD1(dr);
920   add_move_reason(pos, SEMEAI_THREAT, dragon[dr].origin);
921 }
922 
923 /*
924  * Add to the reasons for the move at (pos) that it will accomplish
925  * one of two things: either (reason1) on (target1) or (reason2) on
926  * (target2).
927  *
928  * At this time, (reason) can only be ATTACK_STRING.
929  * However, more reasons will be implemented in the future.
930  *
931  * FIXME: Implement at least ATTACK_MOVE_GOOD_KO, ATTACK_MOVE_BAD_KO,
932  *         DEFEND_MOVE and associates, CONNECT_MOVE, OWL_ATTACK_MOVE,
933  *         OWL_DEFEND_MOVE, and possibly more.
934  *
935  * FIXME: Generalize to more than 2 parameters.
936  *        When that is done, this will be a good way to add
937  *        atari_atari moves.
938  */
939 void
add_either_move(int pos,int reason1,int target1,int reason2,int target2)940 add_either_move(int pos, int reason1, int target1, int reason2, int target2)
941 {
942   int what1 = 0;
943   int what2 = 0;
944   int index;
945 
946   ASSERT_ON_BOARD1(target1);
947   ASSERT_ON_BOARD1(target2);
948   if (reason1 == reason2 && target1 == target2)
949     return;
950 
951   /* For now. */
952   gg_assert(reason1 == ATTACK_STRING);
953   gg_assert(reason2 == ATTACK_STRING);
954 
955   switch (reason1) {
956   case ATTACK_STRING:
957     {
958       what1 = worm[target1].origin;
959 
960       /* If this string is already attacked, and with no defense, then
961        * there is no additional value of this move reason. */
962       if (worm[target1].attack_codes[0] != 0
963 	  && worm[target1].defense_codes[0] == 0)
964 	return;
965     }
966     break;
967 
968   default:
969     break;
970   }
971 
972   switch (reason2) {
973   case ATTACK_STRING:
974     {
975       what2 = worm[target2].origin;
976 
977       /* If this string is already attacked, and with no defense, then
978        * there is no additional value of this move reason. */
979       if (worm[target2].attack_codes[0] != 0
980 	  && worm[target2].defense_codes[0] == 0)
981 	return;
982     }
983     break;
984 
985   default:
986     break;
987   }
988 
989   index = find_either_data(reason1, what1, reason2, what2);
990   add_move_reason(pos, EITHER_MOVE, index);
991 }
992 
993 
994 /*
995  * Add to the reasons for the move at (pos) that it will accomplish
996  * both of two things: (reason1) on (target1) and (reason2) on
997  * (target2).
998  *
999  * At this time, (reason) can only be DEFEND_STRING.
1000  * However, more reasons will be implemented in the future.
1001  *
1002  * FIXME: Implement at least ATTACK_MOVE_GOOD_KO, ATTACK_MOVE_BAD_KO,
1003  *         DEFEND_MOVE and associates, CONNECT_MOVE, OWL_ATTACK_MOVE,
1004  *         OWL_DEFEND_MOVE, and possibly more.
1005  *
1006  * FIXME: Generalize to more than 2 parameters.
1007  *        When that is done, this will be a good way to add
1008  *        atari_atari moves.
1009  */
1010 void
add_all_move(int pos,int reason1,int target1,int reason2,int target2)1011 add_all_move(int pos, int reason1, int target1, int reason2, int target2)
1012 {
1013   int what1 = 0;
1014   int what2 = 0;
1015   int index;
1016 
1017   ASSERT_ON_BOARD1(target1);
1018   ASSERT_ON_BOARD1(target2);
1019   if (reason1 == reason2 && target1 == target2)
1020     return;
1021 
1022   /* For now. */
1023   gg_assert(reason1 == DEFEND_STRING);
1024   gg_assert(reason2 == DEFEND_STRING);
1025 
1026   switch (reason1) {
1027   case DEFEND_STRING:
1028     what1 = worm[target1].origin;
1029     break;
1030 
1031   default:
1032     break;
1033   }
1034 
1035   switch (reason2) {
1036   case DEFEND_STRING:
1037     what2 = worm[target2].origin;
1038     break;
1039 
1040   default:
1041     break;
1042   }
1043 
1044   index = find_all_data(reason1, what1, reason2, what2);
1045   add_move_reason(pos, ALL_MOVE, index);
1046 }
1047 
1048 
1049 void
add_loss_move(int pos,int target1,int target2)1050 add_loss_move(int pos, int target1, int target2)
1051 {
1052   int what1 = dragon[target1].origin;
1053   int what2 = worm[target2].origin;
1054   int index = find_pair_data(what1, what2);
1055   ASSERT1(target2 != NO_MOVE, pos);
1056   add_move_reason(pos, OWL_DEFEND_MOVE_LOSS, index);
1057 }
1058 
1059 /*
1060  * Add to the reasons for the move at (pos) that it expands
1061  * territory.
1062  */
1063 void
add_expand_territory_move(int pos)1064 add_expand_territory_move(int pos)
1065 {
1066   add_move_reason(pos, EXPAND_TERRITORY_MOVE, 0);
1067 }
1068 
1069 /*
1070  * Add to the reasons for the move at (pos) that it expands
1071  * moyo.
1072  */
1073 void
add_expand_moyo_move(int pos)1074 add_expand_moyo_move(int pos)
1075 {
1076   add_move_reason(pos, EXPAND_MOYO_MOVE, 0);
1077 }
1078 
1079 /*
1080  * Add to the reasons for the move at (pos) that it is an invasion.
1081  */
1082 void
add_invasion_move(int pos)1083 add_invasion_move(int pos)
1084 {
1085   add_move_reason(pos, INVASION_MOVE, 0);
1086 }
1087 
1088 /*
1089  * This function is called when a shape value for the move at (pos)
1090  * is found.
1091  *
1092  * We keep track of the largest positive shape value found, and the
1093  * total number of positive contributions, as well as the largest
1094  * negative shape value found, and the total number of negative
1095  * shape contributions.
1096  */
1097 void
add_shape_value(int pos,float value)1098 add_shape_value(int pos, float value)
1099 {
1100   ASSERT_ON_BOARD1(pos);
1101   if (value > 0.0) {
1102     if (value > move[pos].maxpos_shape)
1103       move[pos].maxpos_shape = value;
1104     move[pos].numpos_shape += 1;
1105   }
1106   else if (value < 0.0) {
1107     value = -value;
1108     if (value > move[pos].maxneg_shape)
1109       move[pos].maxneg_shape = value;
1110     move[pos].numneg_shape += 1;
1111   }
1112 }
1113 
1114 /*
1115  * Flag that this move is worthwhile to play as a pure threat move.
1116  */
1117 void
add_worthwhile_threat_move(int pos)1118 add_worthwhile_threat_move(int pos)
1119 {
1120   move[pos].worthwhile_threat = 1;
1121 }
1122 
1123 /*
1124  * Add to the reasons for the move at (pos) that it attacks
1125  * the dragon (dr) on a strategical level.
1126  */
1127 void
add_strategical_attack_move(int pos,int dr)1128 add_strategical_attack_move(int pos, int dr)
1129 {
1130   dr = dragon[dr].origin;
1131   ASSERT_ON_BOARD1(dr);
1132   add_move_reason(pos, STRATEGIC_ATTACK_MOVE, dr);
1133 }
1134 
1135 /*
1136  * Add to the reasons for the move at (pos) that it defends
1137  * the dragon (dr) on a strategical level.
1138  */
1139 void
add_strategical_defense_move(int pos,int dr)1140 add_strategical_defense_move(int pos, int dr)
1141 {
1142   dr = dragon[dr].origin;
1143   ASSERT_ON_BOARD1(dr);
1144   add_move_reason(pos, STRATEGIC_DEFEND_MOVE, dr);
1145 }
1146 
1147 /*
1148  * Add to the reasons for the move at (pos) that the owl
1149  * code reports an attack on the dragon (dr).
1150  */
1151 void
add_owl_attack_move(int pos,int dr,int kworm,int code)1152 add_owl_attack_move(int pos, int dr, int kworm, int code)
1153 {
1154   dr = dragon[dr].origin;
1155 
1156   ASSERT_ON_BOARD1(dr);
1157   if (code == WIN)
1158     add_move_reason(pos, OWL_ATTACK_MOVE, dr);
1159   else if (code == KO_A)
1160     add_move_reason(pos, OWL_ATTACK_MOVE_GOOD_KO, dr);
1161   else if (code == KO_B)
1162     add_move_reason(pos, OWL_ATTACK_MOVE_BAD_KO, dr);
1163   else if (code == GAIN) {
1164     ASSERT_ON_BOARD1(kworm);
1165     add_move_reason(pos, OWL_ATTACK_MOVE_GAIN, find_pair_data(dr, kworm));
1166   }
1167 }
1168 
1169 /*
1170  * Add to the reasons for the move at (pos) that the owl
1171  * code reports a defense of the dragon (dr).
1172  */
1173 void
add_owl_defense_move(int pos,int dr,int code)1174 add_owl_defense_move(int pos, int dr, int code)
1175 {
1176   dr = dragon[dr].origin;
1177 
1178   ASSERT_ON_BOARD1(dr);
1179   if (code == WIN)
1180     add_move_reason(pos, OWL_DEFEND_MOVE, dr);
1181   else if (code == KO_A)
1182     add_move_reason(pos, OWL_DEFEND_MOVE_GOOD_KO, dr);
1183   else if (code == KO_B)
1184     add_move_reason(pos, OWL_DEFEND_MOVE_BAD_KO, dr);
1185 }
1186 
1187 /*
1188  * Add to the reasons for the move at (pos) that the owl
1189  * code reports a move threatening to attack the dragon enemy (dr).
1190  * That is, if the attacker is given two moves in a row, (pos)
1191  * can be the first move.
1192  */
1193 void
add_owl_attack_threat_move(int pos,int dr,int code)1194 add_owl_attack_threat_move(int pos, int dr, int code)
1195 {
1196   UNUSED(code);
1197   dr = dragon[dr].origin;
1198 
1199   ASSERT_ON_BOARD1(dr);
1200   add_move_reason(pos, OWL_ATTACK_THREAT, dragon[dr].origin);
1201   add_worthwhile_threat_move(pos);
1202 }
1203 
1204 /* The owl code found the friendly dragon alive, or the unfriendly dragon
1205  * dead, and an extra point of attack or defense was found, so this might be a
1206  * good place to play.
1207  */
1208 void
add_owl_uncertain_defense_move(int pos,int dr)1209 add_owl_uncertain_defense_move(int pos, int dr)
1210 {
1211   dr = dragon[dr].origin;
1212   ASSERT_ON_BOARD1(dr);
1213   add_move_reason(pos, UNCERTAIN_OWL_DEFENSE, dragon[dr].origin);
1214 }
1215 
1216 /* The owl code found the opponent dragon alive, or the friendly
1217  * dragon dead, but was uncertain, and this move reason propose
1218  * an attack or defense which is expected to fail but might succeed.
1219  */
1220 void
add_owl_uncertain_attack_move(int pos,int dr)1221 add_owl_uncertain_attack_move(int pos, int dr)
1222 {
1223   dr = dragon[dr].origin;
1224   ASSERT_ON_BOARD1(dr);
1225   add_move_reason(pos, UNCERTAIN_OWL_ATTACK, dragon[dr].origin);
1226 }
1227 
1228 /*
1229  * Add to the reasons for the move at (pos) that the owl
1230  * code reports a move threatening to rescue the dragon (dr).
1231  * That is, if the defender is given two moves in a row, (pos)
1232  * can be the first move.
1233  */
1234 void
add_owl_defense_threat_move(int pos,int dr,int code)1235 add_owl_defense_threat_move(int pos, int dr, int code)
1236 {
1237   UNUSED(code);
1238   dr = dragon[dr].origin;
1239 
1240   ASSERT_ON_BOARD1(dr);
1241   add_move_reason(pos, OWL_DEFEND_THREAT, dragon[dr].origin);
1242   add_worthwhile_threat_move(pos);
1243 }
1244 
1245 /* Add to the reasons for the move at (pos) that it captures
1246  * at least one of a set of worms which individually are tactically
1247  * safe (such as a double atari). Only one such move reason is
1248  * permitted per move.
1249  */
1250 void
add_my_atari_atari_move(int pos,int size)1251 add_my_atari_atari_move(int pos, int size)
1252 {
1253   add_move_reason(pos, MY_ATARI_ATARI_MOVE, size);
1254 }
1255 
1256 /* Add to the reasons for the move at (pos) that it stops a
1257  * combination attack for the opponent.
1258  */
1259 void
add_your_atari_atari_move(int pos,int size)1260 add_your_atari_atari_move(int pos, int size)
1261 {
1262   add_move_reason(pos, YOUR_ATARI_ATARI_MOVE, size);
1263 }
1264 
1265 
1266 /*
1267  * Add to the reasons for the move at (pos) that the owl
1268  * code reports a move threatening to defend the dragon enemy (dr),
1269  * and that (pos) is a move which attacks the dragon.
1270  * That is, if the defender is given two moves in a row, (pos)
1271  * can be the first move. Hopefully playing at (pos) makes it harder
1272  * for the dragon to live.
1273  */
1274 void
add_owl_prevent_threat_move(int pos,int dr)1275 add_owl_prevent_threat_move(int pos, int dr)
1276 {
1277   ASSERT_ON_BOARD1(dr);
1278   add_move_reason(pos, OWL_PREVENT_THREAT, dragon[dr].origin);
1279 }
1280 
1281 /*
1282  * Add value of followup moves.
1283  */
1284 void
add_followup_value(int pos,float value)1285 add_followup_value(int pos, float value)
1286 {
1287   ASSERT_ON_BOARD1(pos);
1288   if (value > move[pos].followup_value)
1289     move[pos].followup_value = value;
1290 }
1291 
1292 /*
1293  * Add value of reverse followup moves.
1294  */
1295 void
add_reverse_followup_value(int pos,float value)1296 add_reverse_followup_value(int pos, float value)
1297 {
1298   ASSERT_ON_BOARD1(pos);
1299   if (value > move[pos].reverse_followup_value)
1300     move[pos].reverse_followup_value = value;
1301 }
1302 
1303 /*
1304  * Set a minimum allowed value for the move.
1305  */
1306 int
set_minimum_move_value(int pos,float value)1307 set_minimum_move_value(int pos, float value)
1308 {
1309   ASSERT_ON_BOARD1(pos);
1310   if (value > move[pos].min_value) {
1311     move[pos].min_value = value;
1312     return 1;
1313   }
1314   return 0;
1315 }
1316 
1317 /*
1318  * Set a maximum allowed value for the move.
1319  */
1320 void
set_maximum_move_value(int pos,float value)1321 set_maximum_move_value(int pos, float value)
1322 {
1323   ASSERT_ON_BOARD1(pos);
1324   if (value < move[pos].max_value)
1325     move[pos].max_value = value;
1326 }
1327 
1328 /*
1329  * Set a minimum allowed territorial value for the move.
1330  */
1331 void
set_minimum_territorial_value(int pos,float value)1332 set_minimum_territorial_value(int pos, float value)
1333 {
1334   ASSERT_ON_BOARD1(pos);
1335   if (value > move[pos].min_territory)
1336     move[pos].min_territory = value;
1337 }
1338 
1339 /*
1340  * Set a maximum allowed territorial value for the move.
1341  */
1342 void
set_maximum_territorial_value(int pos,float value)1343 set_maximum_territorial_value(int pos, float value)
1344 {
1345   ASSERT_ON_BOARD1(pos);
1346   if (value < move[pos].max_territory)
1347     move[pos].max_territory = value;
1348 }
1349 
1350 /*
1351  * Add a point redistribution rule, sending the points from (from)
1352  * to (to).
1353  */
1354 void
add_replacement_move(int from,int to,int color)1355 add_replacement_move(int from, int to, int color)
1356 {
1357   int cc;
1358   int pos;
1359   int dummy;
1360 
1361   ASSERT_ON_BOARD1(from);
1362   ASSERT_ON_BOARD1(to);
1363 
1364   if (board[from] != EMPTY)
1365     return;
1366   ASSERT1(board[to] == EMPTY, to);
1367 
1368   cc = replacement_map[to];
1369   if (unconditionally_meaningless_move(to, color, &dummy)) {
1370     /* Silently ignore replacement patterns which conflict with the
1371      * unconditional analysis since the latter is always correct and
1372      * it's difficult to anticipate such situations for the patterns.
1373      */
1374     return;
1375   }
1376 
1377   /* First check for an incompatible redistribution rule. */
1378   if (replacement_map[from] != NO_MOVE) {
1379     int dd = replacement_map[from];
1380     /* Abort if the old rule isn't compatible with the new one.
1381      * (But not in the stable release.)
1382      */
1383     if (0) {
1384       ASSERT1(dd == to || to == replacement_map[dd], from);
1385     }
1386     /* There already is a redistribution in effect so we
1387      * have nothing more to do.
1388      */
1389     return;
1390   }
1391 
1392   TRACE("Move at %1m is replaced by %1m.\n", from, to);
1393 
1394   /* Verify that we don't introduce a cyclic redistribution. */
1395   if (cc == from) {
1396     gprintf("Cyclic point redistribution detected.\n");
1397     ASSERT1(0, from);
1398   }
1399 
1400   /* Update the replacement map. Make sure that all replacements
1401    * always are directed immediately to the final destination.
1402    */
1403   if (cc != NO_MOVE)
1404     replacement_map[from] = cc;
1405   else
1406     replacement_map[from] = to;
1407 
1408   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1409     if (ON_BOARD(pos) && replacement_map[pos] == from)
1410       replacement_map[pos] = replacement_map[from];
1411   }
1412 }
1413 
1414 
1415 /* Find worms rescued by a move at (pos). */
1416 void
get_saved_worms(int pos,signed char saved[BOARDMAX])1417 get_saved_worms(int pos, signed char saved[BOARDMAX])
1418 {
1419   int k;
1420   memset(saved, 0, sizeof(saved[0]) * BOARDMAX);
1421 
1422   for (k = 0; k < MAX_REASONS; k++) {
1423     int r = move[pos].reason[k];
1424     int what;
1425 
1426     if (r < 0)
1427       break;
1428 
1429     what = move_reasons[r].what;
1430     /* We exclude the ko contingent defenses, to avoid that the
1431      * confirm_safety routines spot an attack with ko and thinks the
1432      * move is unsafe.
1433      */
1434     if (move_reasons[r].type == DEFEND_MOVE)
1435       mark_string(worm[what].origin, saved, 1);
1436     else if (move_reasons[r].type == OWL_DEFEND_MOVE_LOSS) {
1437       int origin = dragon[what].origin;
1438       int kworm = worm[what].origin;
1439       int ii;
1440       for (ii = BOARDMIN; ii < BOARDMAX; ii++)
1441 	if (IS_STONE(board[ii]) && dragon[ii].origin == origin
1442 	    && worm[ii].origin != kworm)
1443 	  mark_string(worm[ii].origin, saved, 1);
1444     }
1445   }
1446 }
1447 
1448 /* This function marks all stones whose status is changed by an owl move
1449  * reason according to the following rules:
1450  * 1. For an owl attack, all stones belonging to the attacked dragon are
1451  *    marked as INFLUENCE_CAPTURED_STONE
1452  * 2. For an owl defense, all stones belonging to the defended dragon are
1453  *    markes as INFLUENCE_SAVED_STONE if they are also sufficiently
1454  *    tactically stable.
1455  *
1456  * In effective_size, the sum of the effective size of the changed worms
1457  * is returned (unless it is a NULL pointer).
1458  */
1459 void
mark_changed_dragon(int pos,int color,int affected,int affected2,int move_reason_type,signed char safe_stones[BOARDMAX],float strength[BOARDMAX],float * effective_size)1460 mark_changed_dragon(int pos, int color, int affected, int affected2,
1461     		    int move_reason_type, signed char safe_stones[BOARDMAX],
1462 		    float strength[BOARDMAX], float *effective_size)
1463 {
1464   int ii;
1465   signed char new_status = INFLUENCE_SAVED_STONE;
1466   int result_to_beat = 0;
1467 
1468   ASSERT1(board[pos] == EMPTY, pos);
1469   ASSERT1(IS_STONE(board[affected]), pos);
1470 
1471   if (effective_size)
1472     *effective_size = 0.0;
1473 
1474   /* For attack moves, we immediately can set the effective size.
1475    * For defense moves, it will be calculated in the course of
1476    * updating the worms' status.
1477    */
1478   switch (move_reason_type) {
1479     case OWL_ATTACK_MOVE:
1480     case OWL_ATTACK_MOVE_GOOD_KO:
1481     case OWL_ATTACK_MOVE_BAD_KO:
1482       ASSERT1(board[affected] == OTHER_COLOR(color), pos);
1483       new_status = 0;
1484       if (effective_size)
1485 	*effective_size = dragon[affected].effective_size;
1486       break;
1487     case OWL_DEFEND_MOVE:
1488       ASSERT1(board[affected] == color, pos);
1489       result_to_beat = WIN;
1490       break;
1491     case OWL_DEFEND_MOVE_GOOD_KO:
1492       ASSERT1(board[affected] == color, pos);
1493       result_to_beat = KO_A;
1494       break;
1495     case OWL_DEFEND_MOVE_BAD_KO:
1496       ASSERT1(board[affected] == color, pos);
1497       result_to_beat = KO_B;
1498       break;
1499     case OWL_ATTACK_MOVE_GAIN:
1500       ASSERT1(board[affected] == OTHER_COLOR(color), pos);
1501       new_status = 0;
1502       if (effective_size)
1503 	*effective_size = worm[affected2].effective_size;
1504       break;
1505     case OWL_DEFEND_MOVE_LOSS:
1506       ASSERT1(board[affected] == color, pos);
1507       if (effective_size)
1508 	*effective_size = dragon[affected].effective_size
1509 			  - worm[affected2].effective_size;
1510       result_to_beat = WIN;
1511       break;
1512     case SEMEAI_MOVE:
1513       ASSERT1(IS_STONE(board[affected]), pos);
1514       if (board[affected] == color)
1515 	result_to_beat = WIN;
1516       else {
1517 	new_status = 0;
1518 	if (effective_size)
1519 	  *effective_size = dragon[affected].effective_size;
1520       }
1521       break;
1522 
1523     default:
1524       /* mark_changed_dragon() called with invalid move reason. */
1525       ASSERT1(0, pos);
1526   }
1527 
1528   if (move_reason_type == OWL_ATTACK_MOVE_GAIN)
1529     mark_changed_string(affected2, safe_stones, strength, new_status);
1530   else {
1531     for (ii = first_worm_in_dragon(affected); ii != NO_MOVE;
1532 	 ii = next_worm_in_dragon(ii))
1533       if (new_status == 0)
1534 	mark_changed_string(ii, safe_stones, strength, new_status);
1535       else {
1536 	int worm_is_safe = 0;
1537 	if (worm[ii].attack_codes[0] == NO_MOVE
1538 	    || defense_move_reason_known(pos, ii))
1539 	  worm_is_safe = 1;
1540 	else if (trymove(pos, color, "mark-changed-dragon", ii)) {
1541 	    if (REVERSE_RESULT(attack(ii, NULL)) >= result_to_beat)
1542 	      worm_is_safe = 1;
1543 	    popgo();
1544 	}
1545 	if (worm_is_safe || move_reason_type == SEMEAI_MOVE) {
1546 	  /* This string can now be considered safe. Hence we mark the
1547 	   * whole string as such:
1548 	   */
1549 	  mark_changed_string(ii, safe_stones, strength, new_status);
1550 	  if (effective_size)
1551 	    *effective_size += worm[ii].effective_size;
1552 	}
1553       }
1554     if (move_reason_type == OWL_DEFEND_MOVE_LOSS) {
1555       new_status = 0;
1556       mark_changed_string(affected2, safe_stones, strength, new_status);
1557     }
1558   }
1559 }
1560 
1561 /* Marks the string at (affected) with the new status and accordingly
1562  * with the new strength.
1563  */
1564 void
mark_changed_string(int affected,signed char safe_stones[BOARDMAX],float strength[BOARDMAX],signed char new_status)1565 mark_changed_string(int affected, signed char safe_stones[BOARDMAX],
1566     		    float strength[BOARDMAX], signed char new_status)
1567 {
1568   float new_strength;
1569   int ii;
1570 
1571   ASSERT1(IS_STONE(board[affected]), affected);
1572 
1573   if (new_status == 0)
1574     new_strength = 0.0;
1575   else {
1576     gg_assert(new_status == INFLUENCE_SAVED_STONE);
1577     new_strength = DEFAULT_STRENGTH;
1578   }
1579   for (ii = BOARDMIN; ii < BOARDMAX; ii++)
1580     if (board[ii] == board[affected]
1581 	&& same_string(ii, affected)) {
1582       strength[ii] = new_strength;
1583       safe_stones[ii] = new_status;
1584     }
1585 }
1586 
1587 
1588 /* Find dragons rescued by a move at (pos). */
1589 void
get_saved_dragons(int pos,signed char saved[BOARDMAX])1590 get_saved_dragons(int pos, signed char saved[BOARDMAX])
1591 {
1592   int k;
1593   memset(saved, 0, sizeof(saved[0]) * BOARDMAX);
1594 
1595   for (k = 0; k < MAX_REASONS; k++) {
1596     int r = move[pos].reason[k];
1597     int what;
1598 
1599     if (r < 0)
1600       break;
1601 
1602     what = move_reasons[r].what;
1603     /* We exclude the ko contingent defenses, to avoid that the
1604      * confirm_safety routines spot an attack with ko and thinks the
1605      * move is unsafe.
1606      */
1607     if (move_reasons[r].type == OWL_DEFEND_MOVE)
1608       mark_dragon(what, saved, 1);
1609   }
1610 }
1611 
1612 
1613 /* If a move has saved the dragons in saved_dragons[] and worms in
1614  * saved_worms[], this functions writes the stones now supposedly safe
1615  * in the array safe_stones[].
1616  *
1617  * The safety of the played move itself is set according to
1618  * move[pos].move_safety.
1619  */
1620 void
mark_safe_stones(int color,int move_pos,const signed char saved_dragons[BOARDMAX],const signed char saved_worms[BOARDMAX],signed char safe_stones[BOARDMAX])1621 mark_safe_stones(int color, int move_pos,
1622 		 const signed char saved_dragons[BOARDMAX],
1623     		 const signed char saved_worms[BOARDMAX],
1624 		 signed char safe_stones[BOARDMAX])
1625 {
1626   int pos;
1627 
1628   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
1629     if (board[pos] == OTHER_COLOR(color)) {
1630       if (dragon[pos].status == DEAD
1631 	  || (worm[pos].attack_codes[0] != 0
1632 	      && worm[pos].defense_codes[0] == 0))
1633 	safe_stones[pos] = 0;
1634       else
1635 	safe_stones[pos] = SAFE_STONE;
1636     }
1637     else if (board[pos] == color) {
1638       if ((worm[pos].attack_codes[0] != 0
1639 	   && (worm[pos].defense_codes[0] == 0 || !saved_worms[pos]))
1640 	  || dragon[pos].status == DEAD)
1641 	safe_stones[pos] = 0;
1642       else if (saved_dragons[pos])
1643 	safe_stones[pos] = OWL_SAVED_STONE;
1644       else if (dragon[pos].status == CRITICAL)
1645 	safe_stones[pos] = 0;
1646       else
1647 	safe_stones[pos] = SAFE_STONE;
1648     }
1649     else
1650       safe_stones[pos] = 0;
1651   }
1652   safe_stones[move_pos]
1653     = move[move_pos].move_safety && safe_move(move_pos, color) == WIN;
1654 }
1655 
1656 
1657 /* List the move reasons for (color)'s move at (pos). Return the
1658  * number of move reasons.
1659  */
1660 int
list_move_reasons(FILE * out,int move_pos)1661 list_move_reasons(FILE *out, int move_pos)
1662 {
1663   int m;
1664   int n;
1665   int pos;
1666   int k;
1667   int reason1;
1668   int reason2;
1669   int aa = NO_MOVE;
1670   int bb = NO_MOVE;
1671   int worm1 = -1;
1672   int worm2 = -1;
1673   int num_move_reasons = 0;
1674 
1675   gprintf("\nMove reasons:\n");
1676 
1677   for (n = 0; n < board_size; n++)
1678     for (m = board_size-1; m >= 0; m--) {
1679       pos = POS(m, n);
1680 
1681       if (move_pos != NO_MOVE && move_pos != pos)
1682 	continue;
1683 
1684       for (k = 0; k < MAX_REASONS; k++) {
1685 	int r = move[pos].reason[k];
1686 
1687 	if (r < 0)
1688 	  break;
1689 
1690 	num_move_reasons++;
1691 
1692 	switch (move_reasons[r].type) {
1693 	case ATTACK_MOVE:
1694 	  aa = move_reasons[r].what;
1695 	  gfprintf(out, "Move at %1m attacks %1m%s\n", pos, aa,
1696 		   (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : "");
1697 	  break;
1698 	case ATTACK_MOVE_GOOD_KO:
1699 	  aa = move_reasons[r].what;
1700 	  gfprintf(out, "Move at %1m attacks %1m%s with good ko\n", pos, aa,
1701 		   (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : "");
1702 	  break;
1703 	case ATTACK_MOVE_BAD_KO:
1704 	  aa = move_reasons[r].what;
1705 	  gfprintf(out, "Move at %1m attacks %1m%s with bad ko\n", pos, aa,
1706 		   (worm[aa].defense_codes[0] == 0) ? " (defenseless)" : "");
1707 	  break;
1708 
1709 	case DEFEND_MOVE:
1710 	  aa = move_reasons[r].what;
1711 	  gfprintf(out, "Move at %1m defends %1m\n", pos, aa);
1712 	  break;
1713 	case DEFEND_MOVE_GOOD_KO:
1714 	  aa = move_reasons[r].what;
1715 	  gfprintf(out, "Move at %1m defends %1m with good ko\n", pos, aa);
1716 	  break;
1717 	case DEFEND_MOVE_BAD_KO:
1718 	  aa = move_reasons[r].what;
1719 	  gfprintf(out, "Move at %1m defends %1m with bad ko\n", pos, aa);
1720 	  break;
1721 
1722 	case ATTACK_THREAT:
1723 	case DEFEND_THREAT:
1724 	  aa = move_reasons[r].what;
1725 
1726 	  if (move_reasons[r].type == ATTACK_THREAT)
1727 	    gfprintf(out, "Move at %1m threatens to attack %1m\n", pos, aa);
1728 	  else if (move_reasons[r].type == DEFEND_THREAT)
1729 	    gfprintf(out, "Move at %1m threatens to defend %1m\n", pos, aa);
1730 	  break;
1731 
1732 	case UNCERTAIN_OWL_DEFENSE:
1733 	  aa = move_reasons[r].what;
1734 	  if (board[aa] == current_color)
1735 	    gfprintf(out, "%1m found alive but not certainly, %1m defends it again\n",
1736 		     aa, pos);
1737 	  else
1738 	    gfprintf(out, "%1m found dead but not certainly, %1m attacks it again\n",
1739 		     aa, pos);
1740 	  break;
1741 
1742 	case CONNECT_MOVE:
1743 	case CUT_MOVE:
1744 	  worm1 = conn_worm1[move_reasons[r].what];
1745 	  worm2 = conn_worm2[move_reasons[r].what];
1746 	  if (move_reasons[r].type == CONNECT_MOVE)
1747 	    gfprintf(out, "Move at %1m connects %1m and %1m\n",
1748 		     pos, worm1, worm2);
1749 	  else
1750 	    gfprintf(out, "Move at %1m cuts %1m and %1m\n", pos, worm1, worm2);
1751 	  break;
1752 
1753 	case ANTISUJI_MOVE:
1754 	  gfprintf(out, "Move at %1m is an antisuji\n", pos);
1755 	  break;
1756 
1757 	case SEMEAI_MOVE:
1758 	  aa = move_reasons[r].what;
1759 	  gfprintf(out, "Move at %1m wins semeai for %1m\n", pos, aa);
1760 	  break;
1761 
1762 	case SEMEAI_THREAT:
1763 	  aa = move_reasons[r].what;
1764 	  gfprintf(out, "Move at %1m threatens to win semeai for %1m\n",
1765 		   pos, aa);
1766 	  break;
1767 
1768 	case EITHER_MOVE:
1769 	  reason1 = either_data[move_reasons[r].what].reason1;
1770 	  reason2 = either_data[move_reasons[r].what].reason2;
1771 	  worm1 = either_data[move_reasons[r].what].what1;
1772 	  worm2 = either_data[move_reasons[r].what].what2;
1773 	  gfprintf(out, "Move at %1m either %s %1m or %s %1m\n", pos,
1774 		   reason1 == ATTACK_STRING ? "attacks" : "defends", worm1,
1775 		   reason2 == ATTACK_STRING ? "attacks" : "defends", worm2);
1776 	  break;
1777 
1778 	case ALL_MOVE:
1779 	  reason1 = all_data[move_reasons[r].what].reason1;
1780 	  reason2 = all_data[move_reasons[r].what].reason2;
1781 	  worm1 = all_data[move_reasons[r].what].what1;
1782 	  worm2 = all_data[move_reasons[r].what].what2;
1783 	  gfprintf(out, "Move at %1m both %s %1m and %s %1m\n", pos,
1784 		   reason1 == ATTACK_STRING ? "attacks" : "defends", worm1,
1785 		   reason2 == ATTACK_STRING ? "attacks" : "defends", worm2);
1786 	  break;
1787 
1788 	case OWL_ATTACK_MOVE:
1789 	  aa = move_reasons[r].what;
1790 	  gfprintf(out, "Move at %1m owl-attacks %1m\n", pos, aa);
1791 	  break;
1792 	case OWL_ATTACK_MOVE_GOOD_KO:
1793 	  aa = move_reasons[r].what;
1794 	  gfprintf(out, "Move at %1m owl-attacks %1m with good ko\n", pos, aa);
1795 	  break;
1796 	case OWL_ATTACK_MOVE_BAD_KO:
1797 	  aa = move_reasons[r].what;
1798 	  gfprintf(out, "Move at %1m owl-attacks %1m with bad ko\n", pos, aa);
1799 	  break;
1800 	case OWL_ATTACK_MOVE_GAIN:
1801 	  aa = either_data[move_reasons[r].what].what1;
1802 	  bb = either_data[move_reasons[r].what].what2;
1803 	  gfprintf(out, "Move at %1m owl-attacks %1m (captures %1m)\n",
1804 		   pos, aa, bb);
1805 	  break;
1806 
1807 	case OWL_DEFEND_MOVE:
1808 	  aa = move_reasons[r].what;
1809 	  gfprintf(out, "Move at %1m owl-defends %1m\n", pos, aa);
1810 	  break;
1811 	case OWL_DEFEND_MOVE_GOOD_KO:
1812 	  aa = move_reasons[r].what;
1813 	  gfprintf(out, "Move at %1m owl-defends %1m with good ko\n", pos, aa);
1814 	  break;
1815 	case OWL_DEFEND_MOVE_BAD_KO:
1816 	  aa = move_reasons[r].what;
1817 	  gfprintf(out, "Move at %1m owl-defends %1m with bad ko\n", pos, aa);
1818 	  break;
1819 	case OWL_DEFEND_MOVE_LOSS:
1820 	  aa = either_data[move_reasons[r].what].what1;
1821 	  bb = either_data[move_reasons[r].what].what2;
1822 	  gfprintf(out, "Move at %1m owl-defends %1m (loses %1m)\n",
1823 		   pos, aa, bb);
1824 	  break;
1825 
1826 	case OWL_ATTACK_THREAT:
1827 	  aa = move_reasons[r].what;
1828 	  gfprintf(out, "Move at %1m owl-threatens to attack %1m\n", pos, aa);
1829 	  break;
1830 
1831 	case OWL_DEFEND_THREAT:
1832 	  aa = move_reasons[r].what;
1833 	  gfprintf(out, "Move at %1m owl-threatens to defend %1m\n", pos, aa);
1834 	  break;
1835 
1836 	case OWL_PREVENT_THREAT:
1837 	  aa = move_reasons[r].what;
1838 	  gfprintf(out, "Move at %1m owl-prevents a threat to attack or defend %1m\n",
1839 		   pos, aa);
1840 	  break;
1841 
1842 	case EXPAND_TERRITORY_MOVE:
1843 	  gfprintf(out, "Move at %1m expands territory\n", pos);
1844 	  break;
1845 
1846 	case EXPAND_MOYO_MOVE:
1847 	  gfprintf(out, "Move at %1m expands moyo\n", pos);
1848 	  break;
1849 
1850 	case INVASION_MOVE:
1851 	  gfprintf(out, "Move at %1m is an invasion\n", pos);
1852 	  break;
1853 
1854 	case STRATEGIC_ATTACK_MOVE:
1855 	case STRATEGIC_DEFEND_MOVE:
1856 	  aa = move_reasons[r].what;
1857 
1858 	  if (move_reasons[r].type == STRATEGIC_ATTACK_MOVE)
1859 	    gfprintf(out, "Move at %1m strategically attacks %1m\n", pos, aa);
1860 	  else
1861 	    gfprintf(out, "Move at %1m strategically defends %1m\n", pos, aa);
1862 	  break;
1863 
1864 	case MY_ATARI_ATARI_MOVE:
1865 	  gfprintf(out, "Move at %1m captures something\n", pos);
1866 
1867 	case YOUR_ATARI_ATARI_MOVE:
1868 	  gfprintf(out, "Move at %1m defends against combination attack\n",
1869 		   pos);
1870 	}
1871       }
1872       if (k > 0 && move[pos].move_safety == 0)
1873 	gfprintf(out, "Move at %1m strategically or tactically unsafe\n", pos);
1874     }
1875 
1876   return num_move_reasons;
1877 }
1878 
1879 
1880 
1881 
1882 /* This array lists rules according to which we set the status
1883  * flags of a move reasons.
1884  * The format is:
1885  * { List of reasons to which the rule applies, condition of the rule,
1886  * flags to be set, trace message }
1887  * The condition must be of type discard_condition_fn_ptr, that is a pointer
1888  * to a function with parameters (pos, what).
1889  *
1890  * FIXME: Add handling of ALL and EITHER moves for inessential worms.
1891  */
1892 
1893 static struct discard_rule discard_rules[] =
1894 {
1895   { { ATTACK_MOVE, ATTACK_MOVE_GOOD_KO,
1896       ATTACK_MOVE_BAD_KO, ATTACK_THREAT,
1897       DEFEND_MOVE, DEFEND_MOVE_GOOD_KO,
1898       DEFEND_MOVE_BAD_KO, DEFEND_THREAT, -1 },
1899     owl_move_vs_worm_known, TERRITORY_REDUNDANT,
1900     "  %1m: 0.0 - (threat of) attack/defense of %1m (owl attack/defense as well)\n" },
1901   { { SEMEAI_MOVE, SEMEAI_THREAT, -1 },
1902     owl_move_reason_known, REDUNDANT,
1903     "  %1m: 0.0 - (threat to) win semeai involving %1m (owl move as well)\n"},
1904   { { SEMEAI_MOVE, SEMEAI_THREAT, -1 },
1905     tactical_move_vs_whole_dragon_known, REDUNDANT,
1906     "  %1m: 0.0 - (threat to) win semeai involving %1m (tactical move as well)\n"},
1907   { { EITHER_MOVE, -1 },
1908     either_worm_attackable, REDUNDANT,
1909     "  %1m: 0.0 - 'attack either' is redundant at %1m (direct att./def. as well)\n"},
1910   { { ALL_MOVE, -1 },
1911     one_of_both_attackable, REDUNDANT,
1912     "  %1m: 0.0 - 'defend both' is redundant at %1m (direct att./def. as well)\n"},
1913   { { ATTACK_THREAT, DEFEND_THREAT, -1 },
1914     concerns_inessential_worm, TERRITORY_REDUNDANT,
1915     "  %1m: 0.0 - attack/defense threat of %1m (inessential)\n"},
1916   { { OWL_ATTACK_THREAT, UNCERTAIN_OWL_DEFENSE, -1 },
1917     concerns_inessential_dragon, REDUNDANT,
1918     "  %1m: 0.0 - (uncertain) owl attack/defense of %1m (inessential)\n"},
1919   { { ATTACK_MOVE, ATTACK_MOVE_GOOD_KO, ATTACK_MOVE_BAD_KO,
1920       DEFEND_MOVE, DEFEND_MOVE_GOOD_KO, DEFEND_MOVE_BAD_KO, -1},
1921     move_is_marked_unsafe, REDUNDANT,
1922     "  %1m: 0.0 - tactical move vs %1m (unsafe move)\n"},
1923   { { OWL_ATTACK_MOVE, OWL_ATTACK_MOVE_GOOD_KO, OWL_ATTACK_MOVE_BAD_KO,
1924       OWL_DEFEND_MOVE, OWL_DEFEND_MOVE_GOOD_KO, OWL_DEFEND_MOVE_BAD_KO, -1},
1925     concerns_noncritical_dragon, REDUNDANT,
1926     "  %1m: 0.0 - owl move vs %1m (non-critical)\n"},
1927   { { -1 }, NULL, 0, ""}  /* Keep this entry at end of the list. */
1928 };
1929 
1930 /* This function checks the list of move reasons for redundant move
1931  * reasons and marks them accordingly in their status field.
1932  */
1933 void
discard_redundant_move_reasons(int pos)1934 discard_redundant_move_reasons(int pos)
1935 {
1936   int k1, k2;
1937   int l;
1938   for (k1 = 0; !(discard_rules[k1].reason_type[0] == -1); k1++) {
1939     for (k2 = 0; !(discard_rules[k1].reason_type[k2] == -1); k2++) {
1940       for (l = 0; l < MAX_REASONS; l++) {
1941 
1942         int r = move[pos].reason[l];
1943         if (r < 0)
1944           break;
1945         if ((move_reasons[r].type == discard_rules[k1].reason_type[k2])
1946             && (discard_rules[k1].condition(pos, move_reasons[r].what))) {
1947           DEBUG(DEBUG_MOVE_REASONS, discard_rules[k1].trace_message,
1948                 pos, get_pos(move_reasons[r].type, move_reasons[r].what));
1949           move_reasons[r].status |= discard_rules[k1].flags;
1950         }
1951       }
1952     }
1953   }
1954 }
1955 
1956 
1957 /* Look through the move reasons to see whether (pos) is an antisuji move. */
1958 int
is_antisuji_move(int pos)1959 is_antisuji_move(int pos)
1960 {
1961   int k;
1962   for (k = 0; k < MAX_REASONS; k++) {
1963     int r = move[pos].reason[k];
1964     if (r < 0)
1965       break;
1966     if (move_reasons[r].type == ANTISUJI_MOVE)
1967       return 1; /* This move must not be played. End of story. */
1968   }
1969 
1970   return 0;
1971 }
1972 
1973 /* Increase the randomness scaling factor.
1974  * This causes the move value to be more random.
1975  */
1976 
1977 void
scale_randomness(int pos,float scaling)1978 scale_randomness(int pos, float scaling)
1979 {
1980   if (scaling > move[pos].randomness_scaling)
1981     move[pos].randomness_scaling = scaling;
1982 }
1983 
1984 
1985 /* Register the given `move' as a good attack threat against `target'. By
1986  * "good" we mean a threat which is effectively a sente for the player.
1987  * E.g. in this position the threat is good, because it results in four
1988  * sente moves locally (trevord:950):
1989  *
1990  *  ..OX..
1991  *  .O.*..
1992  *  .OXX..
1993  *  .OOX..
1994  *  ------
1995  *
1996  * We use this list of good threats for performance reasons so that
1997  * estimate_territorial_value() in valuemoves.c doesn't have to read
1998  * through all the moves. Such threats are found with patterns.
1999  */
2000 void
register_good_attack_threat(int move,int target)2001 register_good_attack_threat(int move, int target)
2002 {
2003   int k;
2004   ASSERT_ON_BOARD1(move);
2005   ASSERT_ON_BOARD1(target);
2006   ASSERT1(IS_STONE(worm[target].color), move);
2007 
2008   target = worm[target].origin;
2009   for (k = 0; k < MAX_ATTACK_THREATS; k++) {
2010     if (known_good_attack_threats[move][k] == target)
2011       break;
2012     if (known_good_attack_threats[move][k] == NO_MOVE) {
2013       known_good_attack_threats[move][k] = target;
2014       break;
2015     }
2016   }
2017 }
2018 
2019 
2020 /* Determine if an attack threat is registered as good (see above). */
2021 int
is_known_good_attack_threat(int move,int target)2022 is_known_good_attack_threat(int move, int target)
2023 {
2024   int k;
2025   ASSERT_ON_BOARD1(move);
2026   ASSERT_ON_BOARD1(target);
2027   ASSERT1(IS_STONE(worm[target].color), move);
2028 
2029   target = worm[target].origin;
2030   for (k = 0; k < MAX_ATTACK_THREATS; k++) {
2031     if (known_good_attack_threats[move][k] == target)
2032       return 1;
2033     if (known_good_attack_threats[move][k] == NO_MOVE)
2034       break;
2035   }
2036 
2037   return 0;
2038 }
2039 
2040 /* Like documented in endgame:980, there are also moves which aren't
2041  * safe by themselves, but attempting to capture these stones would
2042  * result in a loss for the opponent (typically, by damezumari).
2043  * Simple examples include snapbacks, but more complicated ones do
2044  * exist. Following functions are helpers for the valuation processing
2045  * which deal with such special cases.
2046  */
2047 void
register_known_safe_move(int move)2048 register_known_safe_move(int move)
2049 {
2050   ASSERT_ON_BOARD1(move);
2051 
2052   known_safe_moves[move] = 1;
2053 }
2054 
2055 
2056 int
is_known_safe_move(int move)2057 is_known_safe_move(int move)
2058 {
2059   ASSERT_ON_BOARD1(move);
2060 
2061   return known_safe_moves[move];
2062 }
2063 
2064 
2065 /*
2066  * Local Variables:
2067  * tab-width: 8
2068  * c-basic-offset: 2
2069  * End:
2070  */
2071