gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] new_semeai(void)


From: Arend Bayer
Subject: [gnugo-devel] new_semeai(void)
Date: Sun, 23 Mar 2003 00:12:34 +0100 (CET)


- semeai moves stored in dragon2 array
- new functions collect_move_reasons(), semeai_move_reasons()

This starts to eliminate the color parameter from examine_position().
My first victim was new_semeai(), which now just stores its result in
the dragon2 array (which gets two new fields to store the semeai moves).

Move reasons are generated later.

The old semeai code added SEMEAI_MOVE as move reason, the new one
OWL_ATTACK/DEFENSE_MOVE. Is there any reason for this?

I think we should stick with SEMEAI_MOVE. If we want to treat them
identically in value_moves.c, that should be an explicit decision there,
and not forced by the semeai code.

(I have changed the territory valuation of SEMEAI_MOVE, which was still
in old effective_size style, to match the OWL_..._MOVE version. The
other cases where the owl move reasons are treated differently look
convincing to me.)

The patch produces two lucky passes. global:3 shows an enormous semeai
misunderstanding, which I have added to semeai.tst. It shows a problem
Gunnar has pointed out recently (declaring dragons dead too quickly).

As usual, some tracing improvements as a bonus :-)

Arend

P.S.: The old function analyze_semeai() implicitly contains the color
parameter pretty hardwired. I don't think I want to touch that function.
Do we want to keep it at all?


Index: engine/aftermath.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/aftermath.c,v
retrieving revision 1.41
diff -u -p -r1.41 aftermath.c
--- engine/aftermath.c  18 Jan 2003 03:05:31 -0000      1.41
+++ engine/aftermath.c  22 Mar 2003 23:12:12 -0000
@@ -835,14 +835,11 @@ reduced_genmove(int *move, int color)
    * Ok, information gathering is complete. Now start to find some moves!
    */

-  /* Pick up tactical moves. */
-  worm_reasons(color);
-
-  /* Pick up owl moves. */
+  /* Pick up moves that we know of already. */
   save_verbose = verbose;
   if (verbose > 0)
     verbose--;
-  owl_reasons(color);
+  collect_move_reasons(color);
   verbose = save_verbose;

   /* Look for combination attacks and defenses against them. */
Index: engine/dragon.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/dragon.c,v
retrieving revision 1.108
diff -u -p -r1.108 dragon.c
--- engine/dragon.c     22 Feb 2003 10:54:23 -0000      1.108
+++ engine/dragon.c     22 Mar 2003 23:12:15 -0000
@@ -566,7 +566,7 @@ make_dragons(int color, int stop_before_

   /* Resolve semeais. This may revise the safety and status fields. */
   if (experimental_semeai && level >= 8)
-    new_semeai(color);
+    new_semeai();
   else
     semeai(color);

@@ -767,15 +767,20 @@ initialize_supplementary_dragon_data(voi
   for (d = 0; d < number_of_dragons; d++) {
     dragon2[d].neighbors                = 0;
     dragon2[d].hostile_neighbors        = 0;
+
     dragon2[d].moyo_size               = -1;
     dragon2[d].moyo_territorial_value   = 0.0;
     dragon2[d].safety                   = -1;
     dragon2[d].escape_route             = 0;
     dragon2[d].heye                     = NO_MOVE;
     dragon2[d].lunch                    = NO_MOVE;
+    dragon2[d].surround_status          = 0;
+    set_eyevalue(&dragon2[d].genus, 0, 0, 0, 0);
+
     dragon2[d].semeai                   = 0;
     dragon2[d].semeai_margin_of_safety  = -1;
-    dragon2[d].surround_status          = 0;
+    dragon2[d].semeai_defense_point    = NO_MOVE;
+    dragon2[d].semeai_attack_point     = NO_MOVE;
     dragon2[d].owl_attack_point         = NO_MOVE;
     dragon2[d].owl_attack_code          = 0;
     dragon2[d].owl_attack_certain       = 1;
@@ -786,7 +791,6 @@ initialize_supplementary_dragon_data(voi
     dragon2[d].owl_threat_status        = UNCHECKED;
     dragon2[d].owl_second_attack_point  = NO_MOVE;
     dragon2[d].owl_second_defense_point = NO_MOVE;
-    set_eyevalue(&dragon2[d].genus, 0, 0, 0, 0);
   }

   dragon2_initialized = 1;
@@ -1540,6 +1544,12 @@ show_dragons(void)
                d2->owl_attack_point, d2->owl_attack_code);
        gprintf("... owl defendable at %1m, code %d\n",
                d2->owl_defense_point, d2->owl_defense_code);
+      }
+      if (dd->status == CRITICAL && d2->semeai) {
+       if (d2->semeai_defense_point)
+         gprintf("... semeai defense move at %1m\n", d2->semeai_defense_point);
+       if (d2->semeai_attack_point)
+         gprintf("... semeai attack move at %1m\n", d2->semeai_attack_point);
       }
       gprintf("... neighbors");
       for (k = 0; k < d2->neighbors; k++) {
Index: engine/genmove.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/genmove.c,v
retrieving revision 1.68
diff -u -p -r1.68 genmove.c
--- engine/genmove.c    22 Feb 2003 10:54:24 -0000      1.68
+++ engine/genmove.c    22 Mar 2003 23:12:16 -0000
@@ -282,6 +282,16 @@ genmove_restricted(int *i, int *j, int c
   return retval;
 }

+/* This function collects move reasons can be generated immediately from
+ * the data gathered in the examine_position() phase.
+ */
+void
+collect_move_reasons(int color)
+{
+  worm_reasons(color);
+  owl_reasons(color);
+  semeai_move_reasons(color);
+}

 /*
  * Perform the actual move generation.
@@ -402,14 +412,12 @@ do_genmove(int *move, int color, float p
    * Ok, information gathering is complete. Now start to find some moves!
    */

-  /* Pick up tactical moves. */
-  worm_reasons(color);

-  /* Pick up owl moves. */
+  /* Pick up moves that we know of already. */
   save_verbose = verbose;
   if (verbose > 0)
     verbose--;
-  owl_reasons(color);
+  collect_move_reasons(color);
   verbose = save_verbose;

   /* Try to find empty corner moves. */
Index: engine/liberty.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
retrieving revision 1.161
diff -u -p -r1.161 liberty.h
--- engine/liberty.h    22 Feb 2003 10:54:24 -0000      1.161
+++ engine/liberty.h    22 Mar 2003 23:12:17 -0000
@@ -434,6 +434,8 @@ void reset_surround_data(void);
 int surround_map(int dr, int pos);

 /* functions to add (or remove) move reasons */
+void collect_move_reasons(int color);
+
 void clear_move_reasons(void);
 void add_lunch(int eater, int food);
 void remove_lunch(int eater, int food);
@@ -533,8 +535,9 @@ int free_handicap_total_stones(void);
 /* Various different strategies for finding a move */
 void fuseki(int color);
 void semeai(int color);
-void new_semeai(int color);
+void new_semeai(void);
 void small_semeai(int save_verbose);
+void semeai_move_reasons(int color);
 void shapes(int color);
 void endgame(int color);
 void endgame_shapes(int color);
@@ -938,8 +941,9 @@ struct dragon_data2 {
   int adjacent[MAX_NEIGHBOR_DRAGONS]; /* adjacent dragons                    */
   int neighbors;                      /* number of adjacent dragons          */
   int hostile_neighbors;              /* neighbors of opposite color         */
+
   int moyo_size;                     /* size of surrounding influence moyo, */
-  float moyo_territorial_value;       /* ...and its territorial value */
+  float moyo_territorial_value;       /* ...and its territorial value        */
   int safety;                         /* a more detailed status estimate     */
   float weakness; /* A new (3.3.x) continuos estimate of the dragon's safety */
   float weakness_pre_owl;     /* Dragon safety based on pre-owl computations */
@@ -948,10 +952,13 @@ struct dragon_data2 {
   int heye;     /* coordinates of a half eye                                 */
   int lunch;    /* if lunch != 0 then lunch points to a boundary worm which  */
                 /* can be captured easily.                                   */
-  int semeai;          /* true if a dragon is part of a semeai               */
-  int semeai_margin_of_safety; /* if small, the semeai is close              */
   int surround_status;         /* Is it surrounded?                          */
   int surround_size;           /* Size of the surrounding area               */
+
+  int semeai;              /* true if a dragon is part of a semeai           */
+  int semeai_margin_of_safety; /* if small, the semeai is close              */
+  int semeai_defense_point;/* Move found by semeai code to rescue dragon     */
+  int semeai_attack_point;  /* Move found by semeai code to kill dragon       
*/
   int owl_threat_status;   /* CAN_THREATEN_ATTACK or CAN_THREATEN_DEFENSE    */
   int owl_status;          /* (ALIVE, DEAD, UNKNOWN, CRITICAL, UNCHECKED)    */
   int owl_attack_point;    /* vital point for attack                         */
Index: engine/move_reasons.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/move_reasons.c,v
retrieving revision 1.110
diff -u -p -r1.110 move_reasons.c
--- engine/move_reasons.c       22 Feb 2003 10:54:24 -0000      1.110
+++ engine/move_reasons.c       22 Mar 2003 23:12:18 -0000
@@ -1455,16 +1455,20 @@ mark_changed_dragon(int pos, int color,
   ASSERT1(board[pos] == EMPTY, pos);
   ASSERT1(IS_STONE(board[affected]), pos);

-  if (effective_size != NULL)
+  if (effective_size)
     *effective_size = 0.0;

+  /* For attack moves, we immediately can set the effective size.
+   * For defense moves, it will be calculated in the course of
+   * updating the worms' status.
+   */
   switch (move_reason_type) {
     case OWL_ATTACK_MOVE:
     case OWL_ATTACK_MOVE_GOOD_KO:
     case OWL_ATTACK_MOVE_BAD_KO:
       ASSERT1(board[affected] == OTHER_COLOR(color), pos);
       new_status = 0;
-      if (effective_size != NULL)
+      if (effective_size)
        *effective_size = dragon[affected].effective_size;
       break;
     case OWL_DEFEND_MOVE:
@@ -1482,16 +1486,27 @@ mark_changed_dragon(int pos, int color,
     case OWL_ATTACK_MOVE_GAIN:
       ASSERT1(board[affected] == OTHER_COLOR(color), pos);
       new_status = 0;
-      if (effective_size != NULL)
+      if (effective_size)
        *effective_size = worm[affected2].effective_size;
       break;
     case OWL_DEFEND_MOVE_LOSS:
       ASSERT1(board[affected] == color, pos);
-      if (effective_size != NULL)
+      if (effective_size)
        *effective_size = dragon[affected].effective_size
                          - worm[affected2].effective_size;
       result_to_beat = WIN;
       break;
+    case SEMEAI_MOVE:
+      ASSERT1(IS_STONE(board[affected]), pos);
+      if (board[affected] == color)
+       result_to_beat = WIN;
+      else {
+       new_status = 0;
+       if (effective_size)
+         *effective_size = dragon[affected].effective_size;
+      }
+      break;
+
     default:
       /* mark_changed_dragon() called with invalid move reason. */
       ASSERT1(0, pos);
@@ -1520,7 +1535,7 @@ mark_changed_dragon(int pos, int color,
           * whole string as such:
           */
          mark_changed_string(ii, safe_stones, strength, new_status);
-         if (effective_size != NULL)
+         if (effective_size)
            *effective_size += worm[ii].effective_size;
        }
       }
Index: engine/semeai.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/semeai.c,v
retrieving revision 1.53
diff -u -p -r1.53 semeai.c
--- engine/semeai.c     5 Mar 2003 18:52:56 -0000       1.53
+++ engine/semeai.c     22 Mar 2003 23:12:19 -0000
@@ -97,14 +97,13 @@ semeai(int color)
 #define MAX_DRAGONS 50

 void
-new_semeai(int color)
+new_semeai()
 {
   int semeai_results_first[MAX_DRAGONS][MAX_DRAGONS];
   int semeai_results_second[MAX_DRAGONS][MAX_DRAGONS];
   int semeai_move[MAX_DRAGONS][MAX_DRAGONS];
   int d1, d2;
   int k;
-  int other = OTHER_COLOR(color);
   int num_dragons = number_of_dragons;

   if (num_dragons > MAX_DRAGONS)
@@ -169,16 +168,17 @@ new_semeai(int color)
        * of d1 after the d1 d2 semeai, giving d2 the first move.
        */

+      DEBUG(DEBUG_SEMEAI, "Considering semeai between %1m and %1m\n",
+           apos, bpos);
       owl_analyze_semeai(apos, bpos,
                         &(semeai_results_first[d1][d2]),
                         &(semeai_results_second[d2][d1]),
                         &(semeai_move[d1][d2]), 1);
-      DEBUG(DEBUG_SEMEAI, "Considering semeai between %1m and %1m\n",
-           apos, bpos);
-      DEBUG(DEBUG_SEMEAI, "results if %s moves first: %s %s\n",
+      DEBUG(DEBUG_SEMEAI, "results if %s moves first: %s %s, %1m\n",
            board[apos] == BLACK ? "black" : "white",
            safety_to_string(semeai_results_first[d1][d2]),
-           safety_to_string(semeai_results_second[d2][d1]));
+           safety_to_string(semeai_results_second[d2][d1]),
+           semeai_move[d1][d2]);
     }

   for (d1 = 0; d1 < num_dragons; d1++) {
@@ -191,8 +191,8 @@ new_semeai(int color)
     for (d2 = 0; d2 < num_dragons; d2++) {
       if (semeai_results_first[d1][d2] == -1)
        continue;
-      gg_assert (semeai_results_second[d1][d2] != -1)
-       semeai_found = 1;
+      gg_assert(semeai_results_second[d1][d2] != -1);
+      semeai_found = 1;

       if (best_result == DEAD
          || best_result == UNKNOWN
@@ -210,20 +210,11 @@ new_semeai(int color)
       }
     }
     if (semeai_found) {
+      dragon2[d1].semeai = 1;
       if (best_result != DEAD && worst_result == DEAD) {
        update_status(DRAGON(d1).origin, CRITICAL, CRITICAL);
-       if (DRAGON(d1).color == color
-           && defense_move != PASS_MOVE) {
-         add_owl_defense_move(defense_move, DRAGON(d1).origin, WIN);
-         DEBUG(DEBUG_SEMEAI, "Adding owl defense move for %1m at %1m\n",
-               DRAGON(d1).origin, defense_move);
-       }
-       if (DRAGON(d1).color == other
-           && attack_move != PASS_MOVE) {
-         add_owl_attack_move(attack_move, DRAGON(d1).origin, WIN);
-         DEBUG(DEBUG_SEMEAI, "Adding owl attack move for %1m at %1m\n",
-               DRAGON(d1).origin, attack_move);
-       }
+       dragon2[d1].semeai_defense_point = defense_move;
+       dragon2[d1].semeai_attack_point = attack_move;
       }
       else if (worst_result == ALIVE_IN_SEKI)
        update_status(DRAGON(d1).origin, ALIVE, ALIVE_IN_SEKI);
@@ -233,6 +224,26 @@ new_semeai(int color)
   }
 }

+void
+semeai_move_reasons(int color)
+{
+  int other = OTHER_COLOR(color);
+  int d;
+
+  for (d = 0; d < number_of_dragons; d++)
+    if (dragon2[d].semeai && DRAGON(d).status == CRITICAL) {
+      if (DRAGON(d).color == color && dragon2[d].semeai_defense_point) {
+       add_semeai_move(dragon2[d].semeai_defense_point, dragon2[d].origin);
+       DEBUG(DEBUG_SEMEAI, "Adding semeai defense move for %1m at %1m\n",
+             DRAGON(d).origin, dragon2[d].semeai_defense_point);
+      }
+      else if (DRAGON(d).color == other && dragon2[d].semeai_attack_point) {
+       add_semeai_move(dragon2[d].semeai_attack_point, dragon2[d].origin);
+       DEBUG(DEBUG_SEMEAI, "Adding owl attack move for %1m at %1m\n",
+             DRAGON(d).origin, dragon2[d].semeai_attack_point);
+      }
+    }
+}

 /* liberty_of_dragon(pos, origin) returns true if the vertex at (pos) is a
  * liberty of the dragon with origin at (origin).
Index: engine/value_moves.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/value_moves.c,v
retrieving revision 1.83
diff -u -p -r1.83 value_moves.c
--- engine/value_moves.c        17 Mar 2003 21:57:26 -0000      1.83
+++ engine/value_moves.c        22 Mar 2003 23:12:22 -0000
@@ -592,8 +592,11 @@ induce_secondary_move_reasons(int color)
        aa = move_reasons[r].what;
        for (i = 0; i < DRAGON2(aa).neighbors; i++) {
          int bb = dragon2[DRAGON2(aa).adjacent[i]].origin;
-         if (dragon[bb].color == color && worm[bb].attack_codes[0] == 0)
+         if (dragon[bb].color == color && worm[bb].attack_codes[0] == 0) {
            add_strategical_defense_move(pos, bb);
+           DEBUG(DEBUG_MOVE_REASONS, "Strategic defense at %1m induced for %1m 
due to owl attack on %1m\n",
+                 pos, bb, aa);
+         }
        }
       }
       else if (move_reasons[r].type == CONNECT_MOVE
@@ -612,10 +615,16 @@ induce_secondary_move_reasons(int color)
                  && !is_same_worm(pos3, worm2)) {
                if (trymove(pos, color, "induce_secondary_move_reasons-B",
                            worm1, EMPTY, NO_MOVE)) {
-                 if (!disconnect(pos3, worm1, NULL))
+                 if (!disconnect(pos3, worm1, NULL)) {
                    add_connection_move(pos, pos3, worm1);
-                 if (!disconnect(pos3, worm2, NULL))
+                   DEBUG(DEBUG_MOVE_REASONS, "Connection at %1m induced for 
%1m/%1m due to connection at %1m/%1m",
+                         pos, worm1, worm2, pos3, worm1);
+                 }
+                 if (!disconnect(pos3, worm2, NULL)) {
                    add_connection_move(pos, pos3, worm2);
+                   DEBUG(DEBUG_MOVE_REASONS, "Connection at %1m induced for 
%1m/%1m due to connection at %1m/%1m",
+                         pos, worm1, worm2, pos3, worm2);
+                 }
                  popgo();
                }
              }
@@ -1677,14 +1686,6 @@ estimate_territorial_value(int pos, int
       does_block = 1;
       break;

-    case SEMEAI_MOVE:
-      aa = move_reasons[r].what;
-
-      this_value = 2 * dragon[aa].effective_size;
-      TRACE("  %1m: %f - semeai involving %1m\n", pos, this_value, aa);
-      tot_value += this_value;
-      break;
-
     case SEMEAI_THREAT:
       aa = move_reasons[r].what;

@@ -1701,6 +1702,7 @@ estimate_territorial_value(int pos, int
        */
       break;

+    case SEMEAI_MOVE:
     case OWL_ATTACK_MOVE:
     case OWL_ATTACK_MOVE_GOOD_KO:
     case OWL_ATTACK_MOVE_BAD_KO:
@@ -1742,7 +1744,8 @@ estimate_territorial_value(int pos, int

       /* FIXME: How much should we reduce the value for ko attacks? */
       if (move_reasons[r].type == OWL_ATTACK_MOVE
-         || move_reasons[r].type == OWL_DEFEND_MOVE)
+         || move_reasons[r].type == OWL_DEFEND_MOVE
+         || move_reasons[r].type == SEMEAI_MOVE)
        this_value = 0.0;
       else if (move_reasons[r].type == OWL_ATTACK_MOVE_GOOD_KO
               || move_reasons[r].type == OWL_DEFEND_MOVE_GOOD_KO) {
Index: regression/semeai.tst
===================================================================
RCS file: /cvsroot/gnugo/gnugo/regression/semeai.tst,v
retrieving revision 1.27
diff -u -p -r1.27 semeai.tst
--- regression/semeai.tst       15 Feb 2003 03:48:57 -0000      1.27
+++ regression/semeai.tst       22 Mar 2003 23:12:23 -0000
@@ -209,6 +209,13 @@ loadsgf games/semeai/semeai11.sgf
 38 owl_analyze_semeai B9 B8
 #? [ALIVE DEAD PASS]*

+# See also global:3.
+loadsgf golois/Aya991113-13.sgf
+39 owl_analyze_semeai R12 H9
+#? [!ALIVE DEAD J4]
+
+40 owl_analyze_semeai H9 R12
+#? [ALIVE DEAD (J4|H4)]

 ########### end of semeai tests #################






reply via email to

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