gnugo-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnugo-devel] Preparatory patch


From: Inge Wallin
Subject: [gnugo-devel] Preparatory patch
Date: Tue, 18 Dec 2001 19:54:16 +0100 (MET)

Here is a patch that is preparatory for a more advanced handling of
combinations of threats.

I started this change a few days ago, but I hope that it applies
cleanly to the current version in CVS.  In particular I hope that it
doesn't clash to heavily with Arends scheme to filter out redundant
move reasons.

Summary:
 - remove all _THREAT move reasons
 - new member in move_reason: is_threat
 - All move reasons except strategic attacks and defends can now be
   threats
 - handling of threats in move_reasons.c rewritten
 - calls to add and remove move reasons changed to new calling
   standards everywhere
 - some minor cleanup

I have run the regressions and not found any discrepancies.  However,
not all trace output is exactly the same yet so I think there is some
subtle differences still.  I will continue the work until everything
is exactly the same as before, when seen from the outside.

After that I will tackle find_double_threats() in combinations.c,
making it handle many more threats than just attacks.  For those of
you working with readconnect, now might, by the way, be a good time to
implement threats to connect our groups and threats to disconnect the
opponent groups.

After *that* it might be time to make a more general atari_atari.  At
that time the name atari_atari might not be descriptive anymore.  The
alternative name threat_chain comes to mind.

        -Inge



diff -ur gnugo-sync/engine/combination.c gnugo-iw/engine/combination.c
--- gnugo-sync/engine/combination.c     Fri Dec 14 21:40:47 2001
+++ gnugo-iw/engine/combination.c       Sun Dec 16 13:43:51 2001
@@ -78,7 +78,7 @@
     if (save_verbose)
       gprintf("Combination attack for %C with size %d found at %1m\n",
              color, aa_val, attack_point);
-    add_my_atari_atari_move(attack_point, aa_val);
+    add_my_atari_atari_move(attack_point, aa_val, FALSE);
   }
   
   aa_val = atari_atari(other, &attack_point, &defense_point, save_verbose);
@@ -86,7 +86,7 @@
     if (save_verbose)
       gprintf("Combination attack for %C with size %d found at %1m, defense at 
%1m\n",
              other, aa_val, attack_point, defense_point);
-    add_your_atari_atari_move(defense_point, aa_val);
+    add_your_atari_atari_move(defense_point, aa_val, FALSE);
   }
   
   verbose = save_verbose;
@@ -143,17 +143,17 @@
                  || board[a_threatened_groups[l]] == EMPTY) {
                if (!attack(ii, NULL)) {
                  add_attack_either_move(ii, a_threatened_groups[k], 
-                                        a_threatened_groups[l]);
-                 remove_attack_threat_move(ii, a_threatened_groups[k]);
-                 remove_attack_threat_move(ii, a_threatened_groups[l]);
+                                        a_threatened_groups[l], FALSE);
+                 remove_attack_move(ii, a_threatened_groups[k], TRUE);
+                 remove_attack_move(ii, a_threatened_groups[l], TRUE);
                }
              }
              else if (!defend_both(a_threatened_groups[k],
                                    a_threatened_groups[l])) {
                add_attack_either_move(ii, a_threatened_groups[k], 
-                                      a_threatened_groups[l]);
-               remove_attack_threat_move(ii, a_threatened_groups[k]);
-               remove_attack_threat_move(ii, a_threatened_groups[l]);
+                                      a_threatened_groups[l], FALSE);
+               remove_attack_move(ii, a_threatened_groups[k], TRUE);
+               remove_attack_move(ii, a_threatened_groups[l], TRUE);
              }
            }
          popgo();
@@ -177,7 +177,7 @@
 /* ================================================================ */
 
 
-/* atari_atari(color, *move) looks for a series of ataris on
+/* atari_atari(color, *move) looks for a series of threats on
  * strings of the other color culminating in the capture of
  * a string which is thought to be invulnerable by the reading
  * code. Such a move can be missed since it may be that each
diff -ur gnugo-sync/engine/dragon.c gnugo-iw/engine/dragon.c
--- gnugo-sync/engine/dragon.c  Thu Dec 13 20:23:17 2001
+++ gnugo-iw/engine/dragon.c    Sat Dec 15 01:33:13 2001
@@ -33,10 +33,10 @@
 static void find_neighbor_dragons(void);
 static void add_adjacent_dragons(int a, int b);
 static void add_adjacent_dragon(int a, int b);
-static int dragon_invincible(int pos);
-static int compute_dragon_status(int pos);
+static int  dragon_invincible(int pos);
+static int  compute_dragon_status(int pos);
 static void dragon_eye(int pos, struct eye_data[BOARDMAX]);
-static int compute_escape(int pos, int dragon_status_known);
+static int  compute_escape(int pos, int dragon_status_known);
 static void compute_surrounding_moyo_sizes(int opposite);
 
 static int dragon2_initialized;
@@ -374,8 +374,10 @@
   /* Compute the surrounding moyo sizes. */
   for (d = 0; d < number_of_dragons; d++) 
     dragon2[d].moyo = 2 * BOARDMAX;
+
   /* Set moyo sizes according to initial_influence. */
   compute_surrounding_moyo_sizes(0);
+
   /* Set moyo sizes according to initial_opposite_influence if
    * this yields smaller results.
    */
@@ -1115,7 +1117,7 @@
 
 
 /*
- * dragon_eye(pos, eye_data) is invoked with (pos) the origin of an
+ * dragon_eye(origin, eye_data) is invoked with (origin) the origin of an
  * eyespace. It unites all the worms adjacent to non-marginal points
  * of the eyespace into a single dragon.. In addition to marginal eye
  * space points, amalgamation is inhibited for points with the
@@ -1125,7 +1127,7 @@
  */
 
 static void
-dragon_eye(int pos, struct eye_data eye[BOARDMAX])
+dragon_eye(int origin, struct eye_data eye[BOARDMAX])
 {
   int i, j;
   int ii;
@@ -1134,14 +1136,14 @@
   int k;
 
   /* don't amalgamate across ikken tobi */
-  if (eye[pos].esize == 3 && eye[pos].msize > 1)
+  if (eye[origin].esize == 3 && eye[origin].msize > 1)
     return;
 
-  DEBUG(DEBUG_DRAGONS, "amalgamate dragons around %1m\n", pos);
-  if (eye[pos].color == BLACK_BORDER)
+  DEBUG(DEBUG_DRAGONS, "amalgamate dragons around %1m\n", origin);
+  if (eye[origin].color == BLACK_BORDER)
     color = BLACK;
   else {
-    gg_assert(eye[pos].color == WHITE_BORDER);
+    gg_assert(eye[origin].color == WHITE_BORDER);
     color = WHITE;
   }
 
@@ -1149,7 +1151,7 @@
     for (j = 0; j < board_size; j++) {
       ii = POS(i, j);
 
-      if (eye[ii].origin == pos
+      if (eye[ii].origin == origin
          && !eye[ii].marginal
          && !(eye[ii].type & INHIBIT_CONNECTION)) {
        for (k = 0; k < 4; k++) {
@@ -1173,7 +1175,7 @@
 
       if ((eye[ii].color == BLACK_BORDER 
           || eye[ii].color == WHITE_BORDER) 
-         && eye[ii].origin == pos)
+         && eye[ii].origin == origin)
       {
        eye[ii].dragon = dr;
       }
diff -ur gnugo-sync/engine/gnugo.h gnugo-iw/engine/gnugo.h
--- gnugo-sync/engine/gnugo.h   Thu Dec 13 20:23:17 2001
+++ gnugo-iw/engine/gnugo.h     Sun Dec 16 13:32:52 2001
@@ -50,6 +50,11 @@
 /* ================================================================ */
 
 
+/* truth values */
+#define FALSE        0
+#define TRUE         1
+
+
 /* Colors */
 #define EMPTY        0
 #define WHITE        1
diff -ur gnugo-sync/engine/liberty.h gnugo-iw/engine/liberty.h
--- gnugo-sync/engine/liberty.h Fri Dec 14 21:40:47 2001
+++ gnugo-iw/engine/liberty.h   Sun Dec 16 13:55:28 2001
@@ -308,30 +308,25 @@
 void clear_move_reasons(void);
 void add_lunch(int eater, int food);
 void remove_lunch(int eater, int food);
-void add_attack_move(int pos, int ww, int code);
-void add_defense_move(int pos, int ww, int code);
-void add_attack_threat_move(int pos, int ww, int code);
-void remove_attack_threat_move(int pos, int ww);
-void add_defense_threat_move(int pos, int ww, int code);
+void add_attack_move(int pos, int ww, int code, int is_threat);
+void remove_attack_move(int pos, int ww, int is_threat);
+void add_defense_move(int pos, int ww, int code, int is_threat);
 void add_connection_move(int pos, int dr1, int dr2);
 void add_cut_move(int pos, int dr1, int dr2);
 void add_antisuji_move(int pos);
-void add_semeai_move(int pos, int dr);
-void add_semeai_threat(int pos, int dr);
+void add_semeai_move(int pos, int dr, int is_threat);
 
-void add_owl_attack_move(int pos, int dr, int code);
-void add_owl_defense_move(int pos, int dr, int code);
-void add_owl_attack_threat_move(int pos, int dr, int code);
-void add_owl_defense_threat_move(int pos, int dr, int code);
+void add_owl_attack_move(int pos, int dr, int code, int is_threat);
+void add_owl_defense_move(int pos, int dr, int code, int is_threat);
 void add_owl_prevent_threat_move(int pos, int dr);
 void add_owl_uncertain_defense_move(int pos, int dr);
 void add_owl_uncertain_attack_move(int pos, int dr);
 
-void add_my_atari_atari_move(int pos, int size);
-void add_your_atari_atari_move(int pos, int size);
-void add_vital_eye_move(int pos, int eyespace, int color);
-void add_attack_either_move(int pos, int str1, int str2);
-void add_defend_both_move(int pos, int str1, int str2);
+void add_my_atari_atari_move(int pos, int size, int is_threat);
+void add_your_atari_atari_move(int pos, int size, int is_threat);
+void add_vital_eye_move(int pos, int eyespace, int color, int is_threat);
+void add_attack_either_move(int pos, int str1, int str2, int is_threat);
+void add_defend_both_move(int pos, int str1, int str2, int is_threat);
 void add_block_territory_move(int pos);
 void add_expand_territory_move(int pos);
 void add_expand_moyo_move(int pos);
diff -ur gnugo-sync/engine/move_reasons.c gnugo-iw/engine/move_reasons.c
--- gnugo-sync/engine/move_reasons.c    Tue Dec 11 03:40:47 2001
+++ gnugo-iw/engine/move_reasons.c      Sun Dec 16 23:30:26 2001
@@ -313,18 +313,22 @@
  * Find a reason in the list of reasons. If necessary, add a new entry.
  */
 static int
-find_reason(int type, int what)
+find_reason(int type, int what, int is_threat)
 {
   int k;
   for (k = 0; k < next_reason; k++)
-    if ((move_reasons[k].type == type) && (move_reasons[k].what == what))
+    if ((move_reasons[k].type == type)
+       && (move_reasons[k].what == what)
+       && (move_reasons[k].is_threat == is_threat))
       return k;
   
   /* Add a new entry. */
   gg_assert(next_reason < MAX_MOVE_REASONS);
   move_reasons[next_reason].type = type;
   move_reasons[next_reason].what = what;
+  move_reasons[next_reason].is_threat = is_threat;
   next_reason++;
+
   return next_reason - 1;
 }
 
@@ -333,7 +337,7 @@
  * table is full.
  */ 
 static void
-add_move_reason(int pos, int type, int what)
+add_move_reason(int pos, int type, int what, int is_threat)
 {
   int k;
 
@@ -347,12 +351,13 @@
     if (r < 0)
       break;
     if (move_reasons[r].type == type
-       && move_reasons[r].what == what)
+       && move_reasons[r].what == what
+       && move_reasons[r].is_threat == is_threat)
       return;  /* Reason already listed. */
   }
   /* Reason not found, add it if there is place left. */
   if (k<MAX_REASONS)
-    move[pos].reason[k] = find_reason(type, what);
+    move[pos].reason[k] = find_reason(type, what, is_threat);
 }
 
 /*
@@ -360,7 +365,7 @@
  * wasn't there.
  */ 
 static void
-remove_move_reason(int pos, int type, int what)
+remove_move_reason(int pos, int type, int what, int is_threat)
 {
   int k;
   int n = -1; /* Position of the move reason to be deleted. */
@@ -371,7 +376,8 @@
     if (r < 0)
       break;
     if (move_reasons[r].type == type
-       && move_reasons[r].what == what)
+       && move_reasons[r].what == what
+       && move_reasons[r].is_threat == is_threat)
       n = k;
   }
   
@@ -389,10 +395,10 @@
 
 /*
  * Check whether a move reason already is recorded for a move.
- * A negative value for 'what' means only match 'type'.
+ * A negative value for 'what' means only match 'type' and 'is_threat'.
  */
 static int
-move_reason_known(int pos, int type, int what)
+move_reason_known(int pos, int type, int what, int is_threat)
 {
   int k;
   int r;
@@ -404,7 +410,8 @@
       break;
     if (move_reasons[r].type == type
        && (what < 0
-           || move_reasons[r].what == what))
+           || move_reasons[r].what == what)
+       && move_reasons[r].is_threat == is_threat)
       return 1;
   }
   return 0;
@@ -415,11 +422,11 @@
  * A negative value for 'what' means only match 'type'.
  */
 static int
-attack_move_reason_known(int pos, int what)
+attack_move_reason_known(int pos, int what, int is_threat)
 {
-  return (move_reason_known(pos, ATTACK_MOVE, what)
-         || move_reason_known(pos, ATTACK_MOVE_GOOD_KO, what)
-         || move_reason_known(pos, ATTACK_MOVE_BAD_KO, what));
+  return (move_reason_known(pos, ATTACK_MOVE, what, is_threat)
+         || move_reason_known(pos, ATTACK_MOVE_GOOD_KO, what, is_threat)
+         || move_reason_known(pos, ATTACK_MOVE_BAD_KO, what, is_threat));
 }
 
 /*
@@ -427,11 +434,11 @@
  * A negative value for 'what' means only match 'type'.
  */
 static int
-defense_move_reason_known(int pos, int what)
+defense_move_reason_known(int pos, int what, int is_threat)
 {
-  return (move_reason_known(pos, DEFEND_MOVE, what)
-         || move_reason_known(pos, DEFEND_MOVE_GOOD_KO, what)
-         || move_reason_known(pos, DEFEND_MOVE_BAD_KO, what));
+  return (move_reason_known(pos, DEFEND_MOVE, what, is_threat)
+         || move_reason_known(pos, DEFEND_MOVE_GOOD_KO, what, is_threat)
+         || move_reason_known(pos, DEFEND_MOVE_BAD_KO, what, is_threat));
 }
 
 /*
@@ -439,11 +446,11 @@
  * A negative value for 'what' means only match 'type'.
  */
 static int
-owl_attack_move_reason_known(int pos, int what)
+owl_attack_move_reason_known(int pos, int what, int is_threat)
 {
-  return (move_reason_known(pos, OWL_ATTACK_MOVE, what)
-         || move_reason_known(pos, OWL_ATTACK_MOVE_GOOD_KO, what)
-         || move_reason_known(pos, OWL_ATTACK_MOVE_BAD_KO, what));
+  return (move_reason_known(pos, OWL_ATTACK_MOVE, what, is_threat)
+         || move_reason_known(pos, OWL_ATTACK_MOVE_GOOD_KO, what, is_threat)
+         || move_reason_known(pos, OWL_ATTACK_MOVE_BAD_KO, what, is_threat));
 }
 
 /*
@@ -451,11 +458,11 @@
  * A negative value for 'what' means only match 'type'.
  */
 static int
-owl_defense_move_reason_known(int pos, int what)
+owl_defense_move_reason_known(int pos, int what, int is_threat)
 {
-  return (move_reason_known(pos, OWL_DEFEND_MOVE, what)
-         || move_reason_known(pos, OWL_DEFEND_MOVE_GOOD_KO, what)
-         || move_reason_known(pos, OWL_DEFEND_MOVE_BAD_KO, what));
+  return (move_reason_known(pos, OWL_DEFEND_MOVE, what, is_threat)
+         || move_reason_known(pos, OWL_DEFEND_MOVE_GOOD_KO, what, is_threat)
+         || move_reason_known(pos, OWL_DEFEND_MOVE_BAD_KO, what, is_threat));
 }
 
 /*
@@ -463,58 +470,26 @@
  * at (ww).
  */
 void
-add_attack_move(int pos, int ww, int code)
-{
-  int worm_number = find_worm(worm[ww].origin);
-
-  ASSERT_ON_BOARD1(ww);
-  if (code == WIN)
-    add_move_reason(pos, ATTACK_MOVE, worm_number);
-  else if (code == KO_A)
-    add_move_reason(pos, ATTACK_MOVE_GOOD_KO, worm_number);
-  else if (code == KO_B)
-    add_move_reason(pos, ATTACK_MOVE_BAD_KO, worm_number);
-}
-
-/*
- * Add to the reasons for the move at (pos) that it defends the worm
- * at (ww).
- */
-void
-add_defense_move(int pos, int ww, int code)
+add_attack_move(int pos, int ww, int code, int is_threat)
 {
   int worm_number = find_worm(worm[ww].origin);
 
   ASSERT_ON_BOARD1(ww);
   if (code == WIN)
-    add_move_reason(pos, DEFEND_MOVE, worm_number);
+    add_move_reason(pos, ATTACK_MOVE, worm_number, is_threat);
   else if (code == KO_A)
-    add_move_reason(pos, DEFEND_MOVE_GOOD_KO, worm_number);
+    add_move_reason(pos, ATTACK_MOVE_GOOD_KO, worm_number, is_threat);
   else if (code == KO_B)
-    add_move_reason(pos, DEFEND_MOVE_BAD_KO, worm_number);
-}
-
-/*
- * Add to the reasons for the move at (pos) that it threatens to
- * attack the worm at (ww). 
- */
-void
-add_attack_threat_move(int pos, int ww, int code)
-{
-  int worm_number = find_worm(worm[ww].origin);
-  UNUSED(code);
-  
-  ASSERT_ON_BOARD1(ww);
-  add_move_reason(pos, ATTACK_THREAT_MOVE, worm_number);
+    add_move_reason(pos, ATTACK_MOVE_BAD_KO, worm_number, is_threat);
 }
 
 void
-remove_attack_threat_move(int pos, int ww)
+remove_attack_move(int pos, int ww, int is_threat)
 {
   int worm_number = find_worm(worm[ww].origin);
 
   ASSERT_ON_BOARD1(ww);
-  remove_move_reason(pos, ATTACK_THREAT_MOVE, worm_number);
+  remove_move_reason(pos, ATTACK_MOVE, worm_number, is_threat);
 }
 
 /*
@@ -522,13 +497,17 @@
  * at (ww).
  */
 void
-add_defense_threat_move(int pos, int ww, int code)
+add_defense_move(int pos, int ww, int code, int is_threat)
 {
   int worm_number = find_worm(worm[ww].origin);
-  UNUSED(code);
 
   ASSERT_ON_BOARD1(ww);
-  add_move_reason(pos, DEFEND_THREAT_MOVE, worm_number);
+  if (code == WIN)
+    add_move_reason(pos, DEFEND_MOVE, worm_number, is_threat);
+  else if (code == KO_A)
+    add_move_reason(pos, DEFEND_MOVE_GOOD_KO, worm_number, is_threat);
+  else if (code == KO_B)
+    add_move_reason(pos, DEFEND_MOVE_BAD_KO, worm_number, is_threat);
 }
 
 
@@ -547,7 +526,8 @@
     if (r < 0)
       break;
 
-    if (move_reasons[r].type == ATTACK_THREAT_MOVE)
+    if (move_reasons[r].type == ATTACK_MOVE
+       && move_reasons[r].is_threat == TRUE)
       strings[num_strings++] = worms[move_reasons[r].what];
 
     if (num_strings == max_strings)
@@ -571,7 +551,8 @@
     if (r < 0)
       break;
 
-    if (move_reasons[r].type == DEFEND_THREAT_MOVE)
+    if (move_reasons[r].type == DEFEND_MOVE
+       && move_reasons[r].is_threat == TRUE)
       strings[num_strings++] = worms[move_reasons[r].what];
 
     if (num_strings == max_strings)
@@ -599,7 +580,7 @@
   if (dragon1 == dragon2)
     return;
   connection = find_connection(dragon1, dragon2);
-  add_move_reason(pos, CONNECT_MOVE, connection);
+  add_move_reason(pos, CONNECT_MOVE, connection, FALSE);
 }
 
 /*
@@ -629,7 +610,7 @@
       || (worm[dr2].attack_codes[0] != 0 && worm[dr2].defend_codes[0] == 0))
     return;
   
-  add_move_reason(pos, CUT_MOVE, connection);
+  add_move_reason(pos, CUT_MOVE, connection, FALSE);
 }
 
 /*
@@ -640,7 +621,7 @@
 void
 add_antisuji_move(int pos)
 {
-  add_move_reason(pos, ANTISUJI_MOVE, 0);
+  add_move_reason(pos, ANTISUJI_MOVE, 0, FALSE);
 }
 
 /*
@@ -652,28 +633,12 @@
  * must be added for the two dragons.
  */
 void
-add_semeai_move(int pos, int dr)
-{
-  int the_dragon = find_dragon(dragon[dr].origin);
-
-  ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, SEMEAI_MOVE, the_dragon);
-}
-
-/*
- * Add to the reasons for the move at (pos) that given two
- * moves in a row a move here can win the dragon (friendly or
- * not) at (dr) in semeai. Such a move can be used as a 
- * ko threat, and it is also given some value due to uncertainty
- * in the counting of liberties.
- */
-void
-add_semeai_threat(int pos, int dr)
+add_semeai_move(int pos, int dr, int is_threat)
 {
   int the_dragon = find_dragon(dragon[dr].origin);
 
   ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, SEMEAI_THREAT, the_dragon);
+  add_move_reason(pos, SEMEAI_MOVE, the_dragon, is_threat);
 }
 
 /*
@@ -681,7 +646,7 @@
  * point for the eye space at (eyespace) of color.
  */
 void
-add_vital_eye_move(int pos, int eyespace, int color)
+add_vital_eye_move(int pos, int eyespace, int color, int is_threat)
 {
   int eye;
 
@@ -690,7 +655,7 @@
     eye = find_eye(white_eye[eyespace].origin, color);
   else
     eye = find_eye(black_eye[eyespace].origin, color);
-  add_move_reason(pos, VITAL_EYE_MOVE, eye);
+  add_move_reason(pos, VITAL_EYE_MOVE, eye, is_threat);
 }
 
 /*
@@ -702,7 +667,7 @@
  * distinct and that neither is undefendable.
  */
 void
-add_attack_either_move(int pos, int str1, int str2)
+add_attack_either_move(int pos, int str1, int str2, int is_threat)
 {
   int worm1 = find_worm(worm[str1].origin);
   int worm2 = find_worm(worm[str2].origin);
@@ -720,7 +685,7 @@
     return;
   
   worm_pair = find_worm_pair(worm1, worm2);
-  add_move_reason(pos, ATTACK_EITHER_MOVE, worm_pair);
+  add_move_reason(pos, ATTACK_EITHER_MOVE, worm_pair, is_threat);
 }
 
 /*
@@ -729,7 +694,7 @@
  * reason is only used for defense of own stones.
  */
 void
-add_defend_both_move(int pos, int str1, int str2)
+add_defend_both_move(int pos, int str1, int str2, int is_threat)
 {
   int worm1 = find_worm(worm[str1].origin);
   int worm2 = find_worm(worm[str2].origin);
@@ -737,7 +702,7 @@
 
   ASSERT_ON_BOARD1(str1);
   ASSERT_ON_BOARD1(str2);
-  add_move_reason(pos, DEFEND_BOTH_MOVE, worm_pair);
+  add_move_reason(pos, DEFEND_BOTH_MOVE, worm_pair, is_threat);
 }
 
 /*
@@ -747,7 +712,7 @@
 void
 add_block_territory_move(int pos)
 {
-  add_move_reason(pos, BLOCK_TERRITORY_MOVE, 0);
+  add_move_reason(pos, BLOCK_TERRITORY_MOVE, 0, FALSE);
 }
 
 /*
@@ -757,7 +722,7 @@
 void
 add_expand_territory_move(int pos)
 {
-  add_move_reason(pos, EXPAND_TERRITORY_MOVE, 0);
+  add_move_reason(pos, EXPAND_TERRITORY_MOVE, 0, FALSE);
 }
 
 /*
@@ -767,7 +732,7 @@
 void
 add_expand_moyo_move(int pos)
 {
-  add_move_reason(pos, EXPAND_MOYO_MOVE, 0);
+  add_move_reason(pos, EXPAND_MOYO_MOVE, 0, FALSE);
 }
 
 /*
@@ -845,7 +810,7 @@
   int dragon1 = find_dragon(dragon[dr].origin);
 
   ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, STRATEGIC_ATTACK_MOVE, dragon1);
+  add_move_reason(pos, STRATEGIC_ATTACK_MOVE, dragon1, FALSE);
 }
 
 /*
@@ -858,7 +823,7 @@
   int dragon1 = find_dragon(dragon[dr].origin);
 
   ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, STRATEGIC_DEFEND_MOVE, dragon1);
+  add_move_reason(pos, STRATEGIC_DEFEND_MOVE, dragon1, FALSE);
 }
 
 /*
@@ -866,17 +831,17 @@
  * code reports an attack on the dragon (dr).
  */
 void
-add_owl_attack_move(int pos, int dr, int code)
+add_owl_attack_move(int pos, int dr, int code, int is_threat)
 {
   int dragon1 = find_dragon(dragon[dr].origin);
 
   ASSERT_ON_BOARD1(dr);
   if (code == WIN)
-    add_move_reason(pos, OWL_ATTACK_MOVE, dragon1);
+    add_move_reason(pos, OWL_ATTACK_MOVE, dragon1, is_threat);
   else if (code == KO_A)
-    add_move_reason(pos, OWL_ATTACK_MOVE_GOOD_KO, dragon1);
+    add_move_reason(pos, OWL_ATTACK_MOVE_GOOD_KO, dragon1, is_threat);
   else if (code == KO_B)
-    add_move_reason(pos, OWL_ATTACK_MOVE_BAD_KO, dragon1);
+    add_move_reason(pos, OWL_ATTACK_MOVE_BAD_KO, dragon1, is_threat);
 }
 
 /*
@@ -884,34 +849,17 @@
  * code reports a defense of the dragon (dr).
  */
 void
-add_owl_defense_move(int pos, int dr, int code)
+add_owl_defense_move(int pos, int dr, int code, int is_threat)
 {
   int dragon1 = find_dragon(dragon[dr].origin);
 
   ASSERT_ON_BOARD1(dr);
   if (code == WIN)
-    add_move_reason(pos, OWL_DEFEND_MOVE, dragon1);
+    add_move_reason(pos, OWL_DEFEND_MOVE, dragon1, is_threat);
   else if (code == KO_A)
-    add_move_reason(pos, OWL_DEFEND_MOVE_GOOD_KO, dragon1);
+    add_move_reason(pos, OWL_DEFEND_MOVE_GOOD_KO, dragon1, is_threat);
   else if (code == KO_B)
-    add_move_reason(pos, OWL_DEFEND_MOVE_BAD_KO, dragon1);
-}
-
-/*
- * Add to the reasons for the move at (pos) that the owl
- * code reports a move threatening to attack the dragon enemy (dr).
- * That is, if the attacker is given two moves in a row, (pos)
- * can be the first move.
- */
-void
-add_owl_attack_threat_move(int pos, int dr, int code)
-{
-  int dragon1 = find_dragon(dragon[dr].origin);
-  UNUSED(code);
-  
-  ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, OWL_ATTACK_THREAT, dragon1);
-  add_worthwhile_threat_move(pos);
+    add_move_reason(pos, OWL_DEFEND_MOVE_BAD_KO, dragon1, is_threat);
 }
 
 /* The owl code found the friendly dragon alive, or the unfriendly dragon
@@ -925,7 +873,7 @@
   int dragon1 = find_dragon(dragon[dr].origin);
 
   ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, UNCERTAIN_OWL_DEFENSE, dragon1);
+  add_move_reason(pos, UNCERTAIN_OWL_DEFENSE, dragon1, FALSE);
 }
 
 /* The owl code found the opponent dragon alive, or the friendly
@@ -939,24 +887,7 @@
   int dragon1 = find_dragon(dragon[dr].origin);
 
   ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, UNCERTAIN_OWL_ATTACK, dragon1);
-}
-
-/*
- * Add to the reasons for the move at (pos) that the owl
- * code reports a move threatening to rescue the dragon (dr).
- * That is, if the defender is given two moves in a row, (pos)
- * can be the first move.
- */
-void
-add_owl_defense_threat_move(int pos, int dr, int code)
-{
-  int dragon1 = find_dragon(dragon[dr].origin);
-  UNUSED(code);
-
-  ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, OWL_DEFENSE_THREAT, dragon1);
-  add_worthwhile_threat_move(pos);
+  add_move_reason(pos, UNCERTAIN_OWL_ATTACK, dragon1, FALSE);
 }
 
 /* Add to the reasons for the move at (ti, tj) that it captures
@@ -965,9 +896,9 @@
  * permitted per move.
  */
 void
-add_my_atari_atari_move(int pos, int size)
+add_my_atari_atari_move(int pos, int size, int is_threat)
 {
-  add_move_reason(pos, MY_ATARI_ATARI_MOVE, size);
+  add_move_reason(pos, MY_ATARI_ATARI_MOVE, size, is_threat);
 }
 
 /* Add to the reasons for the move at (ti, tj) that an opponent move there
@@ -976,9 +907,9 @@
  * by the defender is safe---presumably it defends the threat.
  * Only one such move reason is permitted per move.  */
 void
-add_your_atari_atari_move(int pos, int size)
+add_your_atari_atari_move(int pos, int size, int is_threat)
 {
-  add_move_reason(pos, YOUR_ATARI_ATARI_MOVE, size);
+  add_move_reason(pos, YOUR_ATARI_ATARI_MOVE, size, is_threat);
 }
 
 
@@ -996,7 +927,7 @@
   int dragon1 = find_dragon(dragon[dr].origin);
 
   ASSERT_ON_BOARD1(dr);
-  add_move_reason(pos, OWL_PREVENT_THREAT, dragon1);
+  add_move_reason(pos, OWL_PREVENT_THREAT, dragon1, FALSE);
 }
 
 /*
@@ -1131,9 +1062,10 @@
       break;
     
     what = move_reasons[r].what;
-    if (move_reasons[r].type == DEFEND_MOVE
-       || move_reasons[r].type == DEFEND_MOVE_GOOD_KO
-       || move_reasons[r].type == DEFEND_MOVE_BAD_KO) {
+    if ((move_reasons[r].type == DEFEND_MOVE
+        || move_reasons[r].type == DEFEND_MOVE_GOOD_KO
+        || move_reasons[r].type == DEFEND_MOVE_BAD_KO)
+       && move_reasons[r].is_threat == FALSE) {
       int origin = worm[worms[what]].origin;
       int ii;
       for (ii = BOARDMIN; ii < BOARDMAX; ii++)
@@ -1158,9 +1090,10 @@
       break;
     
     what = move_reasons[r].what;
-    if (move_reasons[r].type == OWL_DEFEND_MOVE
-       || move_reasons[r].type == OWL_DEFEND_MOVE_GOOD_KO
-       || move_reasons[r].type == OWL_DEFEND_MOVE_BAD_KO) {
+    if ((move_reasons[r].type == OWL_DEFEND_MOVE
+        || move_reasons[r].type == OWL_DEFEND_MOVE_GOOD_KO
+        || move_reasons[r].type == OWL_DEFEND_MOVE_BAD_KO)
+       && move_reasons[r].is_threat == FALSE) {
       int origin = dragon[dragons[what]].origin;
       int ii;
       for (ii = BOARDMIN; ii < BOARDMAX; ii++)
@@ -1223,16 +1156,17 @@
        if (r < 0)
          break;
        what = move_reasons[r].what;
-       if (move_reasons[r].type == ATTACK_MOVE
-           || move_reasons[r].type == ATTACK_MOVE_GOOD_KO
-           || move_reasons[r].type == ATTACK_MOVE_BAD_KO
-           || move_reasons[r].type == DEFEND_MOVE
-           || move_reasons[r].type == DEFEND_MOVE_GOOD_KO
-           || move_reasons[r].type == DEFEND_MOVE_BAD_KO
-           || move_reasons[r].type == CONNECT_MOVE
-           || move_reasons[r].type == CUT_MOVE
-           || move_reasons[r].type == ATTACK_EITHER_MOVE
-           || move_reasons[r].type == DEFEND_BOTH_MOVE)
+       if ((move_reasons[r].type == ATTACK_MOVE
+            || move_reasons[r].type == ATTACK_MOVE_GOOD_KO
+            || move_reasons[r].type == ATTACK_MOVE_BAD_KO
+            || move_reasons[r].type == DEFEND_MOVE
+            || move_reasons[r].type == DEFEND_MOVE_GOOD_KO
+            || move_reasons[r].type == DEFEND_MOVE_BAD_KO
+            || move_reasons[r].type == CONNECT_MOVE
+            || move_reasons[r].type == CUT_MOVE
+            || move_reasons[r].type == ATTACK_EITHER_MOVE
+            || move_reasons[r].type == DEFEND_BOTH_MOVE)
+           && move_reasons[r].is_threat == FALSE)
          break;
       }
       
@@ -1250,21 +1184,21 @@
             * unless we already know the move works as defense move.
             */
            if (board[aa] == color
-               && !defense_move_reason_known(ii, unstable_worms[k]))
+               && !defense_move_reason_known(ii, unstable_worms[k], FALSE))
              if (!attack(aa, NULL)) {
                if (!cursor_at_start_of_line)
                  TRACE("\n");
                TRACE("%ofound extra point of defense of %1m at %1m\n", 
                      aa, ii);
                cursor_at_start_of_line = 1;
-               add_defense_move(ii, aa, WIN);
+               add_defense_move(ii, aa, WIN, FALSE);
              }
            
            /* string of opponent color, see if there still is a defense,
             * unless we already know the move works as attack move.
             */
            if (board[aa] == other
-               && !attack_move_reason_known(ii, unstable_worms[k]))
+               && !attack_move_reason_known(ii, unstable_worms[k], FALSE))
              if (!find_defense(aa, NULL)) {
                /* Maybe find_defense() doesn't find the defense. Try to
                 * defend with the stored defense move.
@@ -1285,7 +1219,7 @@
                  TRACE("%ofound extra point of attack of %1m at %1m\n",
                        aa, ii);
                  cursor_at_start_of_line = 1;
-                 add_attack_move(ii, aa, WIN);
+                 add_attack_move(ii, aa, WIN, FALSE);
                }
              }
          }
@@ -1334,14 +1268,16 @@
       if (move_reasons[r].type == STRATEGIC_ATTACK_MOVE
          || move_reasons[r].type == STRATEGIC_DEFEND_MOVE)
        dd1 = dragons[what];
-      else if (move_reasons[r].type == ATTACK_MOVE
-              || move_reasons[r].type == ATTACK_MOVE_GOOD_KO
-              || move_reasons[r].type == ATTACK_MOVE_BAD_KO
-              || move_reasons[r].type == DEFEND_MOVE
-              || move_reasons[r].type == DEFEND_MOVE_GOOD_KO
-              || move_reasons[r].type == DEFEND_MOVE_BAD_KO)
+      else if ((move_reasons[r].type == ATTACK_MOVE
+               || move_reasons[r].type == ATTACK_MOVE_GOOD_KO
+               || move_reasons[r].type == ATTACK_MOVE_BAD_KO
+               || move_reasons[r].type == DEFEND_MOVE
+               || move_reasons[r].type == DEFEND_MOVE_GOOD_KO
+               || move_reasons[r].type == DEFEND_MOVE_BAD_KO)
+              && move_reasons[r].is_threat == FALSE)
        dd1 = worms[what];
-      else if (move_reasons[r].type == VITAL_EYE_MOVE) {
+      else if (move_reasons[r].type == VITAL_EYE_MOVE
+              && move_reasons[r].is_threat == FALSE) {
        int ee = eyes[move_reasons[r].what];
        int ecolor = eyecolor[move_reasons[r].what];
        
@@ -1353,7 +1289,8 @@
        if (dd1 == NO_MOVE) /* Maybe we should assert this not to happen. */
          continue;
       }      
-      else if (move_reasons[r].type == CONNECT_MOVE) {
+      else if (move_reasons[r].type == CONNECT_MOVE
+              && move_reasons[r].is_threat == FALSE) {
        int dragon1 = conn_dragon1[move_reasons[r].what];
        int dragon2 = conn_dragon2[move_reasons[r].what];
        dd1 = dragons[dragon1];
@@ -1379,30 +1316,32 @@
          continue;
        
        if ((move_reasons[r].type == STRATEGIC_ATTACK_MOVE 
-            || move_reasons[r].type == ATTACK_MOVE
-            || move_reasons[r].type == ATTACK_MOVE_GOOD_KO
-            || move_reasons[r].type == ATTACK_MOVE_BAD_KO
-            || (move_reasons[r].type == VITAL_EYE_MOVE
-                && board[dd] == OTHER_COLOR(color)))
-           && !owl_attack_move_reason_known(pos, find_dragon(dd))) {
+            || ((move_reasons[r].type == ATTACK_MOVE
+                 || move_reasons[r].type == ATTACK_MOVE_GOOD_KO
+                 || move_reasons[r].type == ATTACK_MOVE_BAD_KO
+                 || (move_reasons[r].type == VITAL_EYE_MOVE
+                     && board[dd] == OTHER_COLOR(color)))
+                && move_reasons[r].is_threat == FALSE))
+           && !owl_attack_move_reason_known(pos, find_dragon(dd), FALSE)) {
          int acode = owl_does_attack(pos, dd);
          if (acode >= dragon[dd].owl_attack_code) {
-           add_owl_attack_move(pos, dd, acode);
+           add_owl_attack_move(pos, dd, acode, FALSE);
            TRACE("Move at %1m owl attacks %1m, result %d.\n", pos, dd, acode);
          }
        }
        
        if ((move_reasons[r].type == STRATEGIC_DEFEND_MOVE
-            || move_reasons[r].type == CONNECT_MOVE
-            || move_reasons[r].type == DEFEND_MOVE
-            || move_reasons[r].type == DEFEND_MOVE_GOOD_KO
-            || move_reasons[r].type == DEFEND_MOVE_BAD_KO
-            || (move_reasons[r].type == VITAL_EYE_MOVE
-                && board[dd] == color))
-           && !owl_defense_move_reason_known(pos, find_dragon(dd))) {
+            || ((move_reasons[r].type == CONNECT_MOVE
+                 || move_reasons[r].type == DEFEND_MOVE
+                 || move_reasons[r].type == DEFEND_MOVE_GOOD_KO
+                 || move_reasons[r].type == DEFEND_MOVE_BAD_KO
+                 || (move_reasons[r].type == VITAL_EYE_MOVE
+                     && board[dd] == color))
+                && move_reasons[r].is_threat == FALSE))
+           && !owl_defense_move_reason_known(pos, find_dragon(dd), FALSE)) {
          int dcode = owl_does_defend(pos, dd);
          if (dcode >= dragon[dd].owl_defense_code) {
-           add_owl_defense_move(pos, dd, dcode);
+           add_owl_defense_move(pos, dd, dcode, FALSE);
            TRACE("Move at %1m owl defends %1m, result %d.\n", pos, dd, dcode);
          }
        }
@@ -1426,12 +1365,13 @@
          
          if (r < 0)
            break;
-         if (move_reasons[r].type == OWL_ATTACK_MOVE
-             || move_reasons[r].type == OWL_ATTACK_MOVE_GOOD_KO
-             || move_reasons[r].type == OWL_ATTACK_MOVE_BAD_KO
-             || move_reasons[r].type == OWL_DEFEND_MOVE
-             || move_reasons[r].type == OWL_DEFEND_MOVE_GOOD_KO
-             || move_reasons[r].type == OWL_DEFEND_MOVE_BAD_KO) {
+         if ((move_reasons[r].type == OWL_ATTACK_MOVE
+              || move_reasons[r].type == OWL_ATTACK_MOVE_GOOD_KO
+              || move_reasons[r].type == OWL_ATTACK_MOVE_BAD_KO
+              || move_reasons[r].type == OWL_DEFEND_MOVE
+              || move_reasons[r].type == OWL_DEFEND_MOVE_GOOD_KO
+              || move_reasons[r].type == OWL_DEFEND_MOVE_BAD_KO)
+             && move_reasons[r].is_threat == FALSE) {
            dd = dragons[move_reasons[r].what];
            if (are_neighbor_dragons(dd, pos)) {
              worth_trying = 1;
@@ -1442,16 +1382,16 @@
 
        if (worth_trying) {
          if (board[pos] == color
-             && !owl_defense_move_reason_known(pos2, find_dragon(pos))) {
+             && !owl_defense_move_reason_known(pos2, find_dragon(pos), FALSE)) 
{
            int dcode = owl_does_defend(pos2, pos);
            if (dcode >= dragon[pos].owl_defense_code)
-             add_owl_defense_move(pos2, pos, dcode);
+             add_owl_defense_move(pos2, pos, dcode, FALSE);
          }
          else if (board[pos] != color
-                  && !owl_attack_move_reason_known(pos2, find_dragon(pos))) {
+                  && !owl_attack_move_reason_known(pos2, find_dragon(pos), 
FALSE)) {
            int acode = owl_does_attack(pos2, pos);
            if (acode >= dragon[pos].owl_attack_code)
-             add_owl_attack_move(pos2, pos, acode);
+             add_owl_attack_move(pos2, pos, acode, FALSE);
          }
        }
       }
@@ -1463,7 +1403,7 @@
 /*
  * It's often bad to run away with a worm that is in a strategically
  * weak position. This function gives heuristics for determining
- * whether a move at (ti, tj) to defend the worm (ai, aj) is
+ * whether a move at (tt) to defend the worm (aa) is
  * strategically sound.
  *
  * FIXME: This function has played out its role. Should be eliminated.
@@ -1494,7 +1434,6 @@
  *        few liberties. Thus a defense move isn't necessarily a cut
  *        move. This problem can be solved when we have a working
  *        connection reader.
- *
  */
 
 static void
@@ -1519,8 +1458,9 @@
        if (r < 0)
          break;
        
-       if (move_reasons[r].type == ATTACK_MOVE
-           || move_reasons[r].type == DEFEND_MOVE) {
+       if ((move_reasons[r].type == ATTACK_MOVE
+            || move_reasons[r].type == DEFEND_MOVE)
+           && move_reasons[r].is_threat == FALSE) {
          aa = worms[move_reasons[r].what];
 
          if (worm[aa].defend_codes[0] == 0)
@@ -1536,6 +1476,7 @@
           * reason.
           */
          if (move_reasons[r].type == DEFEND_MOVE
+             && move_reasons[r].is_threat == FALSE
              && !strategically_sound_defense(aa, pos))
            continue;
          
@@ -1575,7 +1516,8 @@
                continue;
              
              if (dd != ee) {
-               if (move_reasons[r].type == ATTACK_MOVE) {
+               if (move_reasons[r].type == ATTACK_MOVE
+                   && move_reasons[r].is_threat == FALSE) {
                  /* Exclude the case when (aa) is dead and both
                   * (dd) and (ee) are strongly alive or
                   * better. Then the move would only be losing
@@ -1636,7 +1578,8 @@
                continue;
              
              if (dd != ee) {
-               if (move_reasons[r].type == ATTACK_MOVE) {
+               if (move_reasons[r].type == ATTACK_MOVE
+                   && move_reasons[r].is_threat == FALSE) {
                  /* Exclude the case when (aa) is dead and both
                   * (dd) and (ee) are strongly alive or
                   * better. Then the move would only be losing
@@ -1664,7 +1607,8 @@
            }
          }
        }
-       else if (move_reasons[r].type == OWL_ATTACK_MOVE) {
+       else if (move_reasons[r].type == OWL_ATTACK_MOVE
+                && move_reasons[r].is_threat == FALSE) {
          aa = dragons[move_reasons[r].what];
          for (i = 0; i < DRAGON2(aa).neighbors; i++) {
            int bb = dragon2[DRAGON2(aa).adjacent[i]].origin;
@@ -1700,11 +1644,17 @@
        int r = move[pos].reason[k];
        int type;
        int what;
+       int is_threat;
 
        if (r == -1)
          break;
        type = move_reasons[r].type;
        what = move_reasons[r].what;
+       is_threat = move_reasons[r].is_threat;
+
+       /* FIXME: Check if threats should really just be dismissed
+        *        (the old code did).
+        */
        switch (type) {
        case CUT_MOVE:
          /* We don't trust cut moves, unless some other move reason
@@ -1718,6 +1668,8 @@
        case OWL_DEFEND_MOVE_GOOD_KO:
        case OWL_DEFEND_MOVE_BAD_KO:
        case MY_ATARI_ATARI_MOVE:
+         if (is_threat)
+           break;
          tactical_safety = 1;
          safety = 1;
          break;
@@ -1732,7 +1684,9 @@
        case OWL_ATTACK_MOVE:
        case OWL_ATTACK_MOVE_GOOD_KO:
        case OWL_ATTACK_MOVE_BAD_KO:
-         {
+         if (is_threat)
+           break;
+         else {
            int aa = NO_MOVE;
            int bb = NO_MOVE;
            int size;
@@ -1866,9 +1820,14 @@
        case DEFEND_MOVE:
        case DEFEND_MOVE_GOOD_KO:
        case DEFEND_MOVE_BAD_KO:
-         {
+         if (is_threat)
+           break;
+         else {
            int aa = worms[what];
 
+           if (is_threat)
+             break;
+
            if (dragon[aa].matcher_status == ALIVE)
              /* It would be better if this never happened, but it does
               * sometimes. The owl reading can be very slow then.
@@ -1879,13 +1838,11 @@
              safety = 1;
            break;
          }
-         
-       case ATTACK_THREAT_MOVE:
-       case DEFEND_THREAT_MOVE:
-         break;
 
        case CONNECT_MOVE:
-         {
+         if (is_threat)
+           break;
+         else {
            int dragon1 = conn_dragon1[move_reasons[r].what];
            int dragon2 = conn_dragon2[move_reasons[r].what];
            int aa = dragons[dragon1];
@@ -1945,51 +1902,49 @@
       pos = POS(m, n);
 
       for (k = 0; k < MAX_REASONS; k++) {
-       
+       int is_threat;
+
        int r = move[pos].reason[k];
        if (r < 0)
          break;
        
-       switch(move_reasons[r].type) {
+       is_threat = move_reasons[r].is_threat;
+       switch (move_reasons[r].type) {
        case ATTACK_MOVE:
          aa = worms[move_reasons[r].what];
-         gprintf("Move at %1m attacks %1m%s\n", pos, aa,
-                 (worm[aa].defend_codes[0] == 0) ? " (defenseless)" : "");
+         gprintf("Move at %1m %s %1m%s\n", pos, 
+                 is_threat ? "threatens to attack" : "attacks", aa,
+                 (!is_threat && worm[aa].defend_codes[0] == 0) ? " 
(defenseless)" : "");
          break;
        case ATTACK_MOVE_GOOD_KO:
          aa = worms[move_reasons[r].what];
-         gprintf("Move at %1m attacks %1m%s with good ko\n", pos, aa,
-                 (worm[aa].defend_codes[0] == 0) ? " (defenseless)" : "");
+         gprintf("Move at %1m %s %1m%s with good ko\n", pos, 
+                 is_threat ? "threatens to attack" : "attacks", aa,
+                 (!is_threat && worm[aa].defend_codes[0] == 0) ? " 
(defenseless)" : "");
          break;
        case ATTACK_MOVE_BAD_KO:
          aa = worms[move_reasons[r].what];
-         gprintf("Move at %1m attacks %1m%s with bad ko\n", pos, aa,
-                 (worm[aa].defend_codes[0] == 0) ? " (defenseless)" : "");
+         gprintf("Move at %1m %s %1m%s with bad ko\n", pos, 
+                 is_threat ? "threatens to attack" : "attacks", aa,
+                 (!is_threat && worm[aa].defend_codes[0] == 0) ? " 
(defenseless)" : "");
          break;
          
        case DEFEND_MOVE:
          aa = worms[move_reasons[r].what];
-         gprintf("Move at %1m defends %1m\n", pos, aa);
+         gprintf("Move at %1m %s %1m\n", pos, 
+                 is_threat ? "threatens to defend" : "defends", aa);
          break;
        case DEFEND_MOVE_GOOD_KO:
          aa = worms[move_reasons[r].what];
-         gprintf("Move at %1m defends %1m with good ko\n", pos, aa);
+         gprintf("Move at %1m %s %1m with good ko\n", pos, 
+                 is_threat ? "threatens to defend" : "defends", aa);
          break;
        case DEFEND_MOVE_BAD_KO:
          aa = worms[move_reasons[r].what];
-         gprintf("Move at %1m defends %1m with bad ko\n", pos, aa);
+         gprintf("Move at %1m %s %1m with bad ko\n", pos, 
+                 is_threat ? "threatens to defend" : "defends", aa);
          break;
          
-       case ATTACK_THREAT_MOVE:
-       case DEFEND_THREAT_MOVE:
-         aa = worms[move_reasons[r].what];
-         
-         if (move_reasons[r].type == ATTACK_THREAT_MOVE)
-           gprintf("Move at %1m threatens to attack %1m\n", pos, aa);
-         else if (move_reasons[r].type == DEFEND_THREAT_MOVE)
-           gprintf("Move at %1m threatens to defend %1m\n", pos, aa);
-         break;
-
        case UNCERTAIN_OWL_DEFENSE:
          aa = dragons[move_reasons[r].what];
          if (board[aa] == color)
@@ -2018,12 +1973,8 @@
          
        case SEMEAI_MOVE:
          aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m wins semeai for %1m\n", pos, aa);
-         break;
-         
-       case SEMEAI_THREAT:
-         aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m threatens to win semeai for %1m\n", pos, aa);
+         gprintf("Move at %1m %s semeai for %1m\n", pos, 
+                 is_threat ? "threatens to win" : "wins", aa);
          break;
          
        case VITAL_EYE_MOVE:
@@ -2052,38 +2003,34 @@
                
        case OWL_ATTACK_MOVE:
          aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m owl-attacks %1m\n", pos, aa);
+         gprintf("Move at %1m %s %1m\n", pos, 
+                 is_threat ? "threatens to owl-attack" : "owl-attacks", aa);
          break;
        case OWL_ATTACK_MOVE_GOOD_KO:
          aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m owl-attacks %1m with good ko\n", pos, aa);
+         gprintf("Move at %1m %s %1m with good ko\n", pos,
+                 is_threat ? "threatens to owl-attack" : "owl-attacks", aa);
          break;
        case OWL_ATTACK_MOVE_BAD_KO:
          aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m owl-attacks %1m with bad ko\n", pos, aa);
+         gprintf("Move at %1m %s %1m with bad ko\n", pos, 
+                 is_threat ? "threatens to owl-attack" : "owl-attacks", aa);
          break;
          
        case OWL_DEFEND_MOVE:
          aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m owl-defends %1m\n", pos, aa);
+         gprintf("Move at %1m %s %1m\n", pos, 
+                 is_threat ? "threatens to owl-defend" : "owl-defends", aa);
          break;
        case OWL_DEFEND_MOVE_GOOD_KO:
          aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m owl-defends %1m with good ko\n", pos, aa);
+         gprintf("Move at %1m %s %1m with good ko\n", pos, 
+                 is_threat ? "threatens to owl-defend" : "owl-defends", aa);
          break;
        case OWL_DEFEND_MOVE_BAD_KO:
          aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m owl-defends %1m with bad ko\n", pos, aa);
-         break;
-         
-       case OWL_ATTACK_THREAT:
-         aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m owl-threatens to attack %1m\n", pos, aa);
-         break;
-         
-       case OWL_DEFENSE_THREAT:
-         aa = dragons[move_reasons[r].what];
-         gprintf("Move at %1m owl-threatens to defend %1m\n", pos, aa);
+         gprintf("Move at %1m %s %1m with bad ko\n", pos,
+                 is_threat ? "threatens to owl-defend" : "owl-defends", aa);
          break;
          
        case OWL_PREVENT_THREAT:
@@ -2419,7 +2366,103 @@
     case ATTACK_MOVE_GOOD_KO:
     case ATTACK_MOVE_BAD_KO:
       aa = worms[move_reasons[r].what];
+
+      if (move_reasons[r].is_threat) {
+       /* Threat on our stones. */
+       if (board[aa] == color)
+         break;
+      
+       if (dragon[aa].matcher_status == DEAD) {
+         DEBUG(DEBUG_MOVE_REASONS,
+               "  %1m: 0.0 - threatens to capture %1m (dead)\n", pos, aa);
+         break;
+       }
+
+       if (DRAGON2(aa).safety == INESSENTIAL || worm[aa].inessential) {
+         DEBUG(DEBUG_MOVE_REASONS,
+               "  %1m: 0.0 - threatens to capture %1m (inessential)\n",
+               pos, aa);
+         break;
+       }
+
+       /* If the move also owl attacks the same stones, there is 
+        * no use to threaten tactically.
+        */
+       if (owl_attack_move_reason_known(pos, find_dragon(aa), FALSE)) {
+         DEBUG(DEBUG_MOVE_REASONS,
+               "  %1m: 0.0 - threaten to capture %1m (owl attacked as well)\n",
+               pos, aa);
+         break;
+       }
       
+       /* The followup value of a move threatening to attack (aa)
+        * is twice its effective size, with adjustments. If the
+        * worm has an adjacent (friendly) dead dragon we add its
+        * value. On the other hand if it has an adjacent critical
+        * worm, and if (pos) does not defend that worm, we subtract
+        * the value of the worm, since (aa) may be defended by
+        * attacking that worm. We make at most one adjustment
+        * of each type.
+        *
+        * FIXME: It might be possible that parts of the dragon
+        *        can be cut in the process of capturing the (aa)
+        *        worm. In that case, not the entire size of the 
+        *        adjacent dead dragon should be counted as a positive
+        *        adjustment.  However, it seems difficult to do this
+        *        analysis, and in most cases it won't apply, so we
+        *        leave it as it is for now.
+        *
+        * FIXME: The same analysis should be applied to
+        *        DEFEND_THREAT_MOVE,
+        *        ATTACK_EITHER_MOVE, DEFEND_BOTH_MOVE. It should be 
+        *        broken out as separate functions and dealt with in
+        *        a structured manner.
+        */
+
+       if (trymove(pos, color, "estimate_territorial_value",
+                   NO_MOVE, EMPTY, NO_MOVE)) {
+         int adjs[MAXCHAIN];
+         float adjusted_value = 2 * worm[aa].effective_size;
+         float adjustment_up = 0.0;
+         float adjustment_down = 0.0;
+         int s;
+         int num_adj;
+
+         /* In rare cases it may happen that the trymove() above
+          * actually removed the string at aa.
+          */
+         if (board[aa] == EMPTY)
+           num_adj = 0;
+         else
+           num_adj = chainlinks(aa, adjs);
+
+         for (s = 0; s < num_adj; s++) {
+           int adj = adjs[s];
+
+           if (same_string(pos, adj))
+             continue;
+           if (dragon[adj].color == color
+               && dragon[adj].matcher_status == DEAD
+               && 2*dragon[adj].effective_size > adjustment_up)
+             adjustment_up = 2*dragon[adj].effective_size;
+           if (dragon[adj].color == color
+               && attack(adj, NULL)
+               && 2*worm[adj].effective_size > adjustment_down)
+             adjustment_down = 2*worm[adj].effective_size;
+         }
+         adjusted_value += adjustment_up;
+         adjusted_value -= adjustment_down;
+         if (adjusted_value > 0.0) {
+           add_followup_value(pos, adjusted_value);
+           TRACE("  %1m: %f (followup) - threatens to capture %1m\n",
+                 pos, adjusted_value, aa);
+         }
+         popgo();
+       }
+       break;
+      }
+
+      /* Not a threat if we reach this point. */
       gg_assert(board[aa] != color);
       
       /* Defenseless stone. */
@@ -2460,7 +2503,7 @@
       /* If the move also owl attacks the same stones, count points
        * for that move reason instead.
        */
-      if (owl_attack_move_reason_known(pos, find_dragon(aa))) {
+      if (owl_attack_move_reason_known(pos, find_dragon(aa), FALSE)) {
        DEBUG(DEBUG_MOVE_REASONS,
              "  %1m: 0.0 - attack on %1m (owl attacked as well)\n", pos, aa);
        break;
@@ -2493,6 +2536,44 @@
     case DEFEND_MOVE_BAD_KO:
       aa = worms[move_reasons[r].what];
       
+      if (move_reasons[r].is_threat) {
+
+       /* Threat on our stones. FIXME: Bug?  Should be other_color? */
+       if (board[aa] == color)
+         break;
+      
+       if (dragon[aa].matcher_status == DEAD) {
+         DEBUG(DEBUG_MOVE_REASONS,
+               "  %1m: 0.0 - threatens to defend %1m (dead)\n", pos, aa);
+         break;
+       }
+
+       /* If the stones are inessential, there is no value in saving them. */
+       if (worm[aa].inessential || DRAGON2(aa).safety == INESSENTIAL) {
+         DEBUG(DEBUG_MOVE_REASONS,
+               "  %1m: 0.0 - threaten to defend %1m (inessential)\n", pos, aa);
+         break;
+       }
+      
+       /* If the move also owl defends the same stones, there is no
+        * use in saving them
+        */
+       if (owl_defense_move_reason_known(pos, find_dragon(aa), FALSE)) {
+         DEBUG(DEBUG_MOVE_REASONS,
+               "  %1m: 0.0 - threaten to defend of %1m (owl defended as 
well)\n",
+               pos, aa);
+         break;
+       }
+      
+       add_followup_value(pos, 2 * worm[aa].effective_size);
+
+       TRACE("  %1m: %f (followup) - threatens to defend %1m\n",
+             pos, 2 * worm[aa].effective_size, aa);
+
+       break;
+      }
+
+      /* Not a threat if we reach this point. */
       gg_assert(board[aa] == color);
       
       /* 
@@ -2530,7 +2611,7 @@
       /* If the move also owl defends the same stones, count points
        * for that move reason instead.
        */
-      if (owl_defense_move_reason_known(pos, find_dragon(aa))) {
+      if (owl_defense_move_reason_known(pos, find_dragon(aa), FALSE)) {
        DEBUG(DEBUG_MOVE_REASONS,
              "  %1m: 0.0 - defense of %1m (owl defended as well)\n", pos, aa);
        break;
@@ -2558,139 +2639,6 @@
       does_block = 1;
       break;
 
-    case ATTACK_THREAT_MOVE:
-      aa = worms[move_reasons[r].what];
-
-      /* Threat on our stones. */
-      if (board[aa] == color)
-       break;
-      
-      if (dragon[aa].matcher_status == DEAD) {
-       DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0.0 - threatens to capture %1m (dead)\n", pos, aa);
-       break;
-      }
-
-      if (DRAGON2(aa).safety == INESSENTIAL || worm[aa].inessential) {
-       DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0.0 - threatens to capture %1m (inessential)\n",
-             pos, aa);
-       break;
-      }
-
-      /* If the move also owl attacks the same stones, there is 
-       * no use to threaten tactically.
-       */
-      if (owl_attack_move_reason_known(pos, find_dragon(aa))) {
-       DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0.0 - threaten to capture %1m (owl attacked as well)\n",
-             pos, aa);
-       break;
-      }
-      
-      /* The followup value of a move threatening to attack (aa)
-       * is twice its effective size, with adjustments. If the
-       * worm has an adjacent (friendly) dead dragon we add its
-       * value. On the other hand if it has an adjacent critical
-       * worm, and if (pos) does not defend that worm, we subtract
-       * the value of the worm, since (aa) may be defended by
-       * attacking that worm. We make at most one adjustment
-       * of each type.
-       *
-       * FIXME: It might be possible that parts of the dragon
-       *        can be cut in the process of capturing the (aa)
-       *        worm. In that case, not the entire size of the 
-       *        adjacent dead dragon should be counted as a positive
-       *        adjustment.  However, it seems difficult to do this
-       *        analysis, and in most cases it won't apply, so we
-       *        leave it as it is for now.
-       *
-       * FIXME: The same analysis should be applied to
-       *        DEFEND_THREAT_MOVE,
-       *        ATTACK_EITHER_MOVE, DEFEND_BOTH_MOVE. It should be 
-       *        broken out as separate functions and dealt with in
-       *        a structured manner.
-       */
-
-      if (trymove(pos, color, "estimate_territorial_value",
-                  NO_MOVE, EMPTY, NO_MOVE)) {
-       int adjs[MAXCHAIN];
-       float adjusted_value = 2 * worm[aa].effective_size;
-       float adjustment_up = 0.0;
-       float adjustment_down = 0.0;
-       int s;
-       int num_adj;
-
-       /* In rare cases it may happen that the trymove() above
-         * actually removed the string at aa.
-        */
-       if (board[aa] == EMPTY)
-         num_adj = 0;
-       else
-         num_adj = chainlinks(aa, adjs);
-
-       for (s = 0; s < num_adj; s++) {
-         int adj = adjs[s];
-
-         if (same_string(pos, adj))
-           continue;
-         if (dragon[adj].color == color
-             && dragon[adj].matcher_status == DEAD
-             && 2*dragon[adj].effective_size > adjustment_up)
-           adjustment_up = 2*dragon[adj].effective_size;
-         if (dragon[adj].color == color
-             && attack(adj, NULL)
-             && 2*worm[adj].effective_size > adjustment_down)
-           adjustment_down = 2*worm[adj].effective_size;
-       }
-       adjusted_value += adjustment_up;
-       adjusted_value -= adjustment_down;
-       if (adjusted_value > 0.0) {
-         add_followup_value(pos, adjusted_value);
-         TRACE("  %1m: %f (followup) - threatens to capture %1m\n",
-               pos, adjusted_value, aa);
-       }
-       popgo();
-      }
-      break;
-
-    case DEFEND_THREAT_MOVE:
-      aa = worms[move_reasons[r].what];
-
-      /* Threat on our stones. */
-      if (board[aa] == color)
-       break;
-      
-      if (dragon[aa].matcher_status == DEAD) {
-       DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0.0 - threatens to defend %1m (dead)\n", pos, aa);
-       break;
-      }
-
-      /* If the stones are inessential, there is no value in saving them. */
-      if (worm[aa].inessential || DRAGON2(aa).safety == INESSENTIAL) {
-       DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0.0 - threaten to defend %1m (inessential)\n", pos, aa);
-       break;
-      }
-      
-      /* If the move also owl defends the same stones, there is no
-       * use in saving them
-       */
-      if (owl_defense_move_reason_known(pos, find_dragon(aa))) {
-       DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0.0 - threaten to defend of %1m (owl defended as well)\n",
-             pos, aa);
-       break;
-      }
-      
-      add_followup_value(pos, 2 * worm[aa].effective_size);
-
-      TRACE("  %1m: %f (followup) - threatens to defend %1m\n",
-           pos, 2 * worm[aa].effective_size, aa);
-
-      break;
-
     case UNCERTAIN_OWL_DEFENSE:
       /* This move reason is valued as a strategical value. */
       break;
@@ -2716,11 +2664,38 @@
       break;
       
     case SEMEAI_MOVE:
+      if (move_reasons[r].is_threat) {
+       /* If this move also owl attacks or defends the same dragon, we
+        * count the points for that move reason instead.
+        */
+       if (owl_attack_move_reason_known(pos, move_reasons[r].what, FALSE)
+           || owl_defense_move_reason_known(pos, move_reasons[r].what, FALSE))
+         break;
+      
+       aa = dragons[move_reasons[r].what];
+
+       /* If the dragon consists of a single worm, and this move
+        * tactically attacks or defends that worm, count the points for
+        * that move reason instead.
+        */
+       if (worm[aa].size == dragon[aa].size
+           && (attack_move_reason_known(pos, find_worm(aa), FALSE)
+               || defense_move_reason_known(pos, find_worm(aa), FALSE)))
+         break;
+      
+       /* threaten to win the semeai as a ko threat */
+       add_followup_value(pos, 2 * dragon[aa].effective_size);
+       TRACE("  %1m: %f (followup) - threatens to win semeai for %1m\n",
+             pos, 2 * dragon[aa].effective_size, aa);
+
+       break;
+      }
+
       /* If this move also owl attacks or defends the same dragon, we
        * count the points for that move reason instead.
        */
-      if (owl_attack_move_reason_known(pos, move_reasons[r].what)
-         || owl_defense_move_reason_known(pos, move_reasons[r].what))
+      if (owl_attack_move_reason_known(pos, move_reasons[r].what, FALSE)
+         || owl_defense_move_reason_known(pos, move_reasons[r].what, FALSE))
        break;
 
       aa = dragons[move_reasons[r].what];
@@ -2730,8 +2705,8 @@
        * that move reason instead.
        */
       if (worm[aa].size == dragon[aa].size
-         && (attack_move_reason_known(pos, find_worm(aa))
-             || defense_move_reason_known(pos, find_worm(aa))))
+         && (attack_move_reason_known(pos, find_worm(aa), FALSE)
+             || defense_move_reason_known(pos, find_worm(aa), FALSE)))
        break;
       
       this_value = 2 * dragon[aa].effective_size;
@@ -2739,32 +2714,6 @@
       tot_value += this_value;
       break;
       
-    case SEMEAI_THREAT:
-      /* If this move also owl attacks or defends the same dragon, we
-       * count the points for that move reason instead.
-       */
-      if (owl_attack_move_reason_known(pos, move_reasons[r].what)
-         || owl_defense_move_reason_known(pos, move_reasons[r].what))
-       break;
-      
-      aa = dragons[move_reasons[r].what];
-
-      /* If the dragon consists of a single worm, and this move
-       * tactically attacks or defends that worm, count the points for
-       * that move reason instead.
-       */
-      if (worm[aa].size == dragon[aa].size
-         && (attack_move_reason_known(pos, find_worm(aa))
-             || defense_move_reason_known(pos, find_worm(aa))))
-       break;
-      
-      /* threaten to win the semeai as a ko threat */
-      add_followup_value(pos, 2 * dragon[aa].effective_size);
-      TRACE("  %1m: %f (followup) - threatens to win semeai for %1m\n",
-           pos, 2 * dragon[aa].effective_size, aa);
-
-      break;
-      
     case VITAL_EYE_MOVE:
       /* These are upgraded to owl attacks or defenses in
        * find_more_owl_attack_and_defense_moves() and should no longer
@@ -2778,8 +2727,69 @@
     case OWL_DEFEND_MOVE:
     case OWL_DEFEND_MOVE_GOOD_KO:
     case OWL_DEFEND_MOVE_BAD_KO:
+
       aa = dragons[move_reasons[r].what];
+
+      if (move_reasons[r].is_threat) {
+       /* FIXME: currently we don't combine ko handling with threats. */
+
+       if (move_reasons[r].type == OWL_ATTACK_MOVE) {
+         if (dragon[aa].matcher_status == DEAD) {
+           DEBUG(DEBUG_MOVE_REASONS,
+                 "  %1m: 0.0 - threatens to owl attack %1m (dead)\n", 
+                 pos, aa);
+           break;
+         }
+
+         if (DRAGON2(aa).safety == INESSENTIAL) {
+           DEBUG(DEBUG_MOVE_REASONS,
+                 "  %1m: 0.0 - threatens to capture %1m (inessential)\n",
+                 pos, aa);
+           break;
+         }
+
+         /* The followup value of a move threatening to attack (aa) is
+          * twice its effective size, unless it has an adjacent
+          * (friendly) critical dragon. In that case it's probably a
+          * mistake to make the threat since it can defend itself with
+          * profit.
+          *
+          * FIXME: We probably need to verify that the critical dragon is
+          * substantial enough that capturing it saves the threatened
+          * dragon.
+          */    
+         {
+           float value = 2 * dragon[aa].effective_size;
+           int s;
+
+           for (s = 0; s < DRAGON2(aa).neighbors; s++) {
+             int d = DRAGON2(aa).adjacent[s];
+             int adj = dragon2[d].origin;
+
+             if (dragon[adj].color == color
+                 && dragon[adj].matcher_status == CRITICAL
+                 && dragon2[d].safety != INESSENTIAL
+                 && !owl_defense_move_reason_known(pos, find_dragon(adj), 
FALSE))
+               value = 0.0;
+           }
+       
+           if (value > 0.0) {
+             add_followup_value(pos, value);
+             TRACE("  %1m: %f (followup) - threatens to owl attack %1m\n",
+                   pos, value, aa);
+           }
+         }
+       }
+       else if (move_reasons[r].type == OWL_DEFEND_MOVE) {
+         add_followup_value(pos, 2 * dragon[aa].effective_size);
+         TRACE("  %1m: %f (followup) - threatens to owl defend %1m\n",
+               pos, 2 * dragon[aa].effective_size, aa);
+       }
+       break;
+      }
       
+      /* Not a threat if we reach this point. */
+
       if (DRAGON2(aa).safety == INESSENTIAL) {
        DEBUG(DEBUG_MOVE_REASONS,
              "  %1m: 0 - owl attack/defend for inessential dragon %1m\n",
@@ -2803,9 +2813,10 @@
        int ii;
        for (ii = BOARDMIN; ii < BOARDMAX; ii++) {
          if (IS_STONE(board[ii]) && is_same_dragon(ii, aa)) {
-           if (move_reasons[r].type == OWL_ATTACK_MOVE
-               || move_reasons[r].type == OWL_ATTACK_MOVE_GOOD_KO
-               || move_reasons[r].type == OWL_ATTACK_MOVE_BAD_KO)
+           if ((move_reasons[r].type == OWL_ATTACK_MOVE
+                || move_reasons[r].type == OWL_ATTACK_MOVE_GOOD_KO
+                || move_reasons[r].type == OWL_ATTACK_MOVE_BAD_KO)
+               && move_reasons[r].is_threat == FALSE)
              saved_stones[ii] = INFLUENCE_CAPTURED_STONE;
            else
              saved_stones[ii] = INFLUENCE_SAVED_STONE;
@@ -2816,17 +2827,20 @@
       
       /* FIXME: How much should we reduce the value for ko attacks? */
       this_value = 2 * dragon[aa].effective_size;
-      if (move_reasons[r].type == OWL_ATTACK_MOVE
-         || move_reasons[r].type == OWL_DEFEND_MOVE)
+      if ((move_reasons[r].type == OWL_ATTACK_MOVE
+          || move_reasons[r].type == OWL_DEFEND_MOVE)
+         && move_reasons[r].is_threat == FALSE)
        this_value = 0.0;
-      else if (move_reasons[r].type == OWL_ATTACK_MOVE_GOOD_KO
-              || move_reasons[r].type == OWL_DEFEND_MOVE_GOOD_KO) {
+      else if ((move_reasons[r].type == OWL_ATTACK_MOVE_GOOD_KO
+               || move_reasons[r].type == OWL_DEFEND_MOVE_GOOD_KO)
+              && move_reasons[r].is_threat == FALSE) {
        this_value *= 0.3;
        TRACE("  %1m: -%f - owl attack/defense of %1m only with good ko\n",
              pos, this_value, aa);
       }        
-      else if (move_reasons[r].type == OWL_ATTACK_MOVE_BAD_KO
-              || move_reasons[r].type == OWL_DEFEND_MOVE_BAD_KO) {
+      else if ((move_reasons[r].type == OWL_ATTACK_MOVE_BAD_KO
+               || move_reasons[r].type == OWL_DEFEND_MOVE_BAD_KO)
+              && move_reasons[r].is_threat == FALSE) {
        this_value *= 0.5;
        TRACE("  %1m: -%f - owl attack/defense of %1m only with bad ko\n",
              pos, this_value, aa);
@@ -2836,63 +2850,6 @@
       does_block = 1;
       break;
 
-    case OWL_ATTACK_THREAT:
-      aa = dragons[move_reasons[r].what];
-
-      if (dragon[aa].matcher_status == DEAD) {
-       DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0.0 - threatens to owl attack %1m (dead)\n", pos, aa);
-       break;
-      }
-
-      if (DRAGON2(aa).safety == INESSENTIAL) {
-       DEBUG(DEBUG_MOVE_REASONS,
-             "  %1m: 0.0 - threatens to capture %1m (inessential)\n",
-             pos, aa);
-       break;
-      }
-
-      /* The followup value of a move threatening to attack (aa) is
-       * twice its effective size, unless it has an adjacent
-       * (friendly) critical dragon. In that case it's probably a
-       * mistake to make the threat since it can defend itself with
-       * profit.
-       *
-       * FIXME: We probably need to verify that the critical dragon is
-       * substantial enough that capturing it saves the threatened
-       * dragon.
-       */       
-      {
-       float value = 2 * dragon[aa].effective_size;
-       int s;
-
-       for (s = 0; s < DRAGON2(aa).neighbors; s++) {
-         int d = DRAGON2(aa).adjacent[s];
-         int adj = dragon2[d].origin;
-
-         if (dragon[adj].color == color
-             && dragon[adj].matcher_status == CRITICAL
-             && dragon2[d].safety != INESSENTIAL
-             && !owl_defense_move_reason_known(pos, find_dragon(adj)))
-           value = 0.0;
-       }
-       
-       if (value > 0.0) {
-         add_followup_value(pos, value);
-         TRACE("  %1m: %f (followup) - threatens to owl attack %1m\n",
-               pos, value, aa);
-       }
-      }
-      break;
-
-    case OWL_DEFENSE_THREAT:
-      aa = dragons[move_reasons[r].what];
-
-      add_followup_value(pos, 2 * dragon[aa].effective_size);
-      TRACE("  %1m: %f (followup) - threatens to owl defend %1m\n",
-           pos, 2 * dragon[aa].effective_size, aa);
-      break;
-
     case OWL_PREVENT_THREAT:
       /* A move attacking a dragon whose defense can be threatened.
        */
@@ -3044,6 +3001,11 @@
       case DEFEND_MOVE:
       case DEFEND_MOVE_GOOD_KO:
       case DEFEND_MOVE_BAD_KO:
+
+       /* Only handle moves that work right out. */
+       if (move_reasons[r].is_threat)
+         break;
+
        worm1 = move_reasons[r].what;
        aa = worms[worm1];
       
@@ -3109,8 +3071,8 @@
             */
            if (dragon[bb].matcher_status != DEAD
                && dragon[bb].size == worm[bb].size
-               && (attack_move_reason_known(pos, find_worm(bb))
-                   || defense_move_reason_known(pos, find_worm(bb))))
+               && (attack_move_reason_known(pos, find_worm(bb), FALSE)
+                   || defense_move_reason_known(pos, find_worm(bb), FALSE)))
              this_value = 0.0;
 
            /* If this dragon can be tactically attacked and the move
@@ -3125,12 +3087,13 @@
 
        break;
        
-      case ATTACK_THREAT_MOVE:
-      case DEFEND_THREAT_MOVE:
-        break;
-
       case ATTACK_EITHER_MOVE:
       case DEFEND_BOTH_MOVE:
+
+       /* Only handle moves that work right out. */
+       if (move_reasons[r].is_threat)
+         break;
+
        /* This is complete nonsense, but still better than nothing.
         * FIXME: Do this in a reasonable way.
         */
@@ -3148,22 +3111,22 @@
          * either worm, this move reason has no additional value.
         */
        if (move_reasons[r].type == ATTACK_EITHER_MOVE
-           && (attack_move_reason_known(pos, worm1)
-               || attack_move_reason_known(pos, worm2)))
+           && (attack_move_reason_known(pos, worm1, FALSE)
+               || attack_move_reason_known(pos, worm2, FALSE)))
          break;
        if (move_reasons[r].type == DEFEND_BOTH_MOVE
-           && (defense_move_reason_known(pos, worm1)
-               || defense_move_reason_known(pos, worm2)))
+           && (defense_move_reason_known(pos, worm1, FALSE)
+               || defense_move_reason_known(pos, worm2, FALSE)))
          break;
 
        /* Also if there is a combination attack, we assume it covers
          * the same thing.
         */
        if (move_reasons[r].type == ATTACK_EITHER_MOVE
-           && move_reason_known(pos, MY_ATARI_ATARI_MOVE, -1))
+           && move_reason_known(pos, MY_ATARI_ATARI_MOVE, -1, FALSE))
          break;
        if (move_reasons[r].type == DEFEND_BOTH_MOVE
-           && move_reason_known(pos, YOUR_ATARI_ATARI_MOVE, -1))
+           && move_reason_known(pos, YOUR_ATARI_ATARI_MOVE, -1, FALSE))
          break;
 
        {
@@ -3197,6 +3160,10 @@
        if (doing_scoring && !move[pos].move_safety)
          break;
 
+       /* Only handle moves that work right out. */
+       if (move_reasons[r].is_threat)
+         break;
+
        d1 = conn_dragon1[move_reasons[r].what];
        d2 = conn_dragon2[move_reasons[r].what];
        aa = dragons[d1];
@@ -3251,12 +3218,16 @@
        if (bb == NO_MOVE) /* Maybe we should assert this not to happen. */
          break; 
 
+       /* Only handle moves that work right out. */
+       if (move_reasons[r].is_threat)
+         break;
+
        /* If there is an owl attack/defend move reason for this location,
         * we don't care about it, since otherwise we would count the
         * points twice.
         */
-       if (owl_defense_move_reason_known(pos, find_dragon(bb))
-           || owl_attack_move_reason_known(pos, find_dragon(bb))) {
+       if (owl_defense_move_reason_known(pos, find_dragon(bb), FALSE)
+           || owl_attack_move_reason_known(pos, find_dragon(bb), FALSE)) {
          DEBUG(DEBUG_MOVE_REASONS,
                "  %1m: 0.0 - vital for %1m: owl attack/defense as well\n",
                pos, bb);
@@ -3321,7 +3292,7 @@
            if (dragon[adj].color == color
                && dragon[adj].matcher_status == CRITICAL
                && dragon2[d].safety != INESSENTIAL
-               && !owl_defense_move_reason_known(pos, find_dragon(adj)))
+               && !owl_defense_move_reason_known(pos, find_dragon(adj), FALSE))
              this_value = 0.0;
          }
        }
@@ -3386,17 +3357,17 @@
      */
     if (dragon[aa].matcher_status != DEAD
        && dragon[aa].size == worm[aa].size
-       && (attack_move_reason_known(pos, find_worm(aa))
-           || defense_move_reason_known(pos, find_worm(aa))))
+       && (attack_move_reason_known(pos, find_worm(aa), FALSE)
+           || defense_move_reason_known(pos, find_worm(aa), FALSE)))
       continue;
     
     /* If the dragon has been owl captured, owl defended, or involved
      * in a semeai, we have likewise already counted the points as
      * territorial value.
      */
-    if (owl_attack_move_reason_known(pos, k)
-       || owl_defense_move_reason_known(pos, k)
-       || move_reason_known(pos, SEMEAI_MOVE, k)) {
+    if (owl_attack_move_reason_known(pos, k, FALSE)
+       || owl_defense_move_reason_known(pos, k, FALSE)
+       || move_reason_known(pos, SEMEAI_MOVE, k, FALSE)) {
       /* But if the strategical value was larger than the territorial
        * value (e.g. because connecting to strong dragon) we award the
        * excess value as a bonus.
@@ -3522,8 +3493,10 @@
 
   if (move_reasons[mr1].type != move_reasons[mr2].type)
     return move_reasons[mr2].type - move_reasons[mr1].type;
-  else
+  else if (move_reasons[mr2].what != move_reasons[mr1].what)
     return move_reasons[mr2].what - move_reasons[mr1].what;
+  else
+    return move_reasons[mr2].is_threat - move_reasons[mr1].is_threat;
 }
 
 
diff -ur gnugo-sync/engine/move_reasons.h gnugo-iw/engine/move_reasons.h
--- gnugo-sync/engine/move_reasons.h    Sat Nov 10 23:52:48 2001
+++ gnugo-iw/engine/move_reasons.h      Sun Dec 16 14:49:55 2001
@@ -24,13 +24,13 @@
 /* values for move_reason.type */
 #define ATTACK_MOVE              1
 #define DEFEND_MOVE              2
-#define ATTACK_THREAT_MOVE       3
-#define DEFEND_THREAT_MOVE       4
+/*#define ATTACK_THREAT_MOVE       3*/
+/*#define DEFEND_THREAT_MOVE       4*/
 #define CONNECT_MOVE             5
 #define CUT_MOVE                 6
 #define ANTISUJI_MOVE            7
 #define SEMEAI_MOVE              8
-#define SEMEAI_THREAT            9
+/*#define SEMEAI_THREAT            9*/
 #define VITAL_EYE_MOVE          12
 #define ATTACK_EITHER_MOVE      13
 #define DEFEND_BOTH_MOVE        14
@@ -41,8 +41,8 @@
 #define STRATEGIC_DEFEND_MOVE   19
 #define OWL_ATTACK_MOVE         20
 #define OWL_DEFEND_MOVE         21
-#define OWL_ATTACK_THREAT       22
-#define OWL_DEFENSE_THREAT      23
+/*#define OWL_ATTACK_THREAT       22*/
+/*#define OWL_DEFENSE_THREAT      23*/
 #define OWL_PREVENT_THREAT      24
 #define UNCERTAIN_OWL_ATTACK    25
 #define UNCERTAIN_OWL_DEFENSE   26
@@ -65,6 +65,7 @@
   int type;   /* e.g. attack, defend, or connect */
   int what;   /* pointer into list of strings, list of pair of dragons,
                 or similar */
+  int is_threat; /* 1 if this is only a threat, 0 if it works outright */
 };
 
 struct move_data {
diff -ur gnugo-sync/engine/optics.c gnugo-iw/engine/optics.c
--- gnugo-sync/engine/optics.c  Fri Dec 14 21:40:49 2001
+++ gnugo-iw/engine/optics.c    Sun Dec 16 13:54:18 2001
@@ -1656,11 +1656,11 @@
        if (add_moves) {
          if (eye_color != color) {
            for (k = 0; k < num_attacks; k++)
-             add_vital_eye_move(attack_points[k], pos, eye_color);
+             add_vital_eye_move(attack_points[k], pos, eye_color, FALSE);
          }
          else {
            for (k = 0; k < num_defenses; k++)
-             add_vital_eye_move(defense_points[k], pos, eye_color);
+             add_vital_eye_move(defense_points[k], pos, eye_color, FALSE);
          }
        }
       }
diff -ur gnugo-sync/engine/owl.c gnugo-iw/engine/owl.c
--- gnugo-sync/engine/owl.c     Thu Dec 13 20:23:22 2001
+++ gnugo-iw/engine/owl.c       Sun Dec 16 13:57:15 2001
@@ -2782,7 +2782,7 @@
        if (board[pos] == color) {
          if (dragon[pos].owl_defense_point != NO_MOVE) {
            add_owl_defense_move(dragon[pos].owl_defense_point, pos,
-                                dragon[pos].owl_defense_code);
+                                dragon[pos].owl_defense_code, FALSE);
            DEBUG(DEBUG_OWL, "owl: %1m defends %1m at move %d\n",
                  dragon[pos].owl_defense_point, pos, movenum+1);
          }
@@ -2842,7 +2842,7 @@
          }
          
          /* If we've reached this far, the attack is okay. */
-         add_owl_attack_move(move, pos, dragon[pos].owl_attack_code);
+         add_owl_attack_move(move, pos, dragon[pos].owl_attack_code, FALSE);
          DEBUG(DEBUG_OWL, "owl: %1m attacks %1m at move %d\n", move, pos,
                movenum+1);
        }
@@ -2852,12 +2852,12 @@
               && dragon[pos].owl_threat_status == CAN_THREATEN_DEFENSE) {
        if (board[pos] == color 
            && dragon[pos].owl_defense_point != NO_MOVE)
-         add_owl_defense_threat_move(dragon[pos].owl_defense_point, pos, WIN);
+         add_owl_defense_move(dragon[pos].owl_defense_point, pos, WIN, TRUE);
        if (board[pos] == color
            && dragon[pos].owl_second_defense_point != NO_MOVE
            && is_legal(dragon[pos].owl_second_defense_point, color))
-         add_owl_defense_threat_move(dragon[pos].owl_second_defense_point,
-                                     pos, WIN);
+         add_owl_defense_move(dragon[pos].owl_second_defense_point, 
+                              pos, WIN, TRUE);
        /* If the opponent can threaten to live, an attacking
         * move gets a small value to make sure it's really dead.
         */
@@ -2871,11 +2871,11 @@
               && board[pos] == OTHER_COLOR(color)
               && dragon[pos].owl_threat_status == CAN_THREATEN_ATTACK) {
        if (dragon[pos].owl_attack_point != NO_MOVE)
-         add_owl_attack_threat_move(dragon[pos].owl_attack_point, pos, WIN);
+         add_owl_attack_move(dragon[pos].owl_attack_point, pos, WIN, TRUE);
        if (dragon[pos].owl_second_attack_point != NO_MOVE
            && is_legal(dragon[pos].owl_second_attack_point, color))
-         add_owl_attack_threat_move(dragon[pos].owl_second_attack_point, pos,
-                                    WIN);
+         add_owl_attack_move(dragon[pos].owl_second_attack_point, pos, 
+                             WIN, TRUE);
       }
       /* The owl code found the friendly dragon alive, but was uncertain,
        * and an extra point of defense was found, so this might
diff -ur gnugo-sync/engine/semeai.c gnugo-iw/engine/semeai.c
--- gnugo-sync/engine/semeai.c  Tue Dec 11 03:41:01 2001
+++ gnugo-iw/engine/semeai.c    Sun Dec 16 13:55:27 2001
@@ -185,10 +185,10 @@
        else { /* pass == 1 */
          if (a_status == CRITICAL
              && best_result_a[k] != DEAD)
-           add_owl_defense_move(move[k], apos, WIN);
+           add_owl_defense_move(move[k], apos, WIN, FALSE);
          if (b_status == CRITICAL
              && worst_result_b[k] == DEAD)
-           add_owl_attack_move(move[k], bpos, WIN);
+           add_owl_attack_move(move[k], bpos, WIN, FALSE);
        }
       } /* loop over neighbor dragons */
       if (pass == 0 && semeai_found) {
@@ -285,7 +285,7 @@
     if (dragon[my_dragon].owl_defense_point != NO_MOVE
        && owl_does_attack(dragon[my_dragon].owl_defense_point, your_dragon)) {
       add_owl_attack_move(dragon[my_dragon].owl_defense_point, your_dragon,
-                         WIN);
+                         WIN, FALSE);
       DEBUG(DEBUG_SEMEAI, "added owl attack of %1m at %1m\n",
            your_dragon, dragon[my_dragon].owl_defense_point);
       owl_code_sufficient = 1;
@@ -307,7 +307,7 @@
     if (dragon[your_dragon].owl_attack_point != NO_MOVE
        && owl_does_defend(dragon[your_dragon].owl_attack_point, my_dragon)) {
       add_owl_defense_move(dragon[your_dragon].owl_attack_point, my_dragon,
-                          WIN);
+                          WIN, FALSE);
       DEBUG(DEBUG_SEMEAI, "added owl defense of %1m at %1m\n",
            my_dragon, dragon[your_dragon].owl_attack_point);
       if (dragon[my_dragon].owl_status == DEAD) {
@@ -724,13 +724,13 @@
                             int margin_of_safety)
 {
   if (my_status == CRITICAL)
-    add_semeai_move(move, my_dragon);
+    add_semeai_move(move, my_dragon, FALSE);
   else if (margin_of_safety == 1)
-    add_semeai_threat(move, my_dragon);
+    add_semeai_move(move, my_dragon, TRUE);
   if (your_status == CRITICAL)
-      add_semeai_move(move, your_dragon);
+      add_semeai_move(move, your_dragon, FALSE);
   else if (margin_of_safety == 1)
-    add_semeai_threat(move, your_dragon);
+    add_semeai_move(move, your_dragon, TRUE);
 }
 
 
diff -ur gnugo-sync/engine/worm.c gnugo-iw/engine/worm.c
--- gnugo-sync/engine/worm.c    Wed Dec  5 19:49:51 2001
+++ gnugo-iw/engine/worm.c      Sun Dec 16 13:48:20 2001
@@ -1324,10 +1324,10 @@
       for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
        if (worm[pos].attack_codes[k] != 0)
          add_attack_move(worm[pos].attack_points[k], pos,
-                         worm[pos].attack_codes[k]);
+                         worm[pos].attack_codes[k], FALSE);
        if (worm[pos].attack_threat_codes[k] != 0)
-         add_attack_threat_move(worm[pos].attack_threat_points[k], pos,
-                                worm[pos].attack_threat_codes[k]);
+         add_attack_move(worm[pos].attack_threat_points[k], pos,
+                         worm[pos].attack_threat_codes[k], TRUE);
       }
     }
       
@@ -1335,11 +1335,11 @@
       for (k = 0; k < MAX_TACTICAL_POINTS; k++) {
        if (worm[pos].defend_codes[k] != 0)
          add_defense_move(worm[pos].defense_points[k], pos,
-                          worm[pos].defend_codes[k]);
+                          worm[pos].defend_codes[k], FALSE);
 
        if (worm[pos].defense_threat_codes[k] != 0)
-         add_defense_threat_move(worm[pos].defense_threat_points[k], pos,
-                                 worm[pos].defense_threat_codes[k]);
+         add_defense_move(worm[pos].defense_threat_points[k], pos,
+                          worm[pos].defense_threat_codes[k], TRUE);
       }
     }
   }
diff -ur gnugo-sync/patterns/mkpat.c gnugo-iw/patterns/mkpat.c
--- gnugo-sync/patterns/mkpat.c Thu Dec 13 20:23:41 2001
+++ gnugo-iw/patterns/mkpat.c   Sun Dec 16 13:59:09 2001
@@ -223,8 +223,8 @@
   {"antisuji",        1, "add_antisuji_move(%s)"},
   {"add_connect_move",2, "add_connection_move(move,%s,%s)"},
   {"add_cut_move",    2, "add_cut_move(move,%s,%s)"},
-  {"add_attack_either_move",2,"add_attack_either_move(move,%s,%s)"},
-  {"add_defend_both_move",2, "add_defend_both_move(move,%s,%s)"},
+  {"add_attack_either_move",2,"add_attack_either_move(move,%s,%s,FALSE)"},
+  {"add_defend_both_move",2, "add_defend_both_move(move,%s,%s,FALSE)"},
   {"same_dragon",     2, "is_same_dragon(%s,%s)"},
   {"same_string",     2, "same_string(%s,%s)"},
   {"dragonsize",      1, "dragon[%s].size"},



reply via email to

[Prev in Thread] Current Thread [Next in Thread]