gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] move valuation patch


From: Paul Pogonyshev
Subject: [gnugo-devel] move valuation patch
Date: Mon, 16 Feb 2004 00:24:57 +0200
User-agent: KMail/1.6.50

- new function do_find_more_owl_attack_and_defense_moves() broken out
  of find_more_owl_attack_and_defense_moves()
- induce_secondary_move_reasons() tries to upgrade induced reasons to
  owl attacks/defenses with do_find_more_owl_attack_and_defense_moves()
- strategical attack move reason is induced for saving certain worms
  adjoining weak opponent dragons

Summary: secondary move reasons can be upgraded to owl attacks/defenses
just as "normal" move reasons; new algorithmical strategical attacks.

<somewhat-offtopic>
I ran a twogtp match between 3.5.4 and 3.4 quite a while ago.  Results
were a bit disappointing, but not severe:

        White: GNU Go 3.5.4, black: GNU Go 3.4.
        Results: 44:56.

        White: GNU Go 3.4, black: GNU Go 3.5.4.
        Results: 46:54.

It might be possible that GNU Go 3.5.4 is more cautious (due to tuning,
break-in improvements, whatever), but doesn't know how to punish 3.4's
overplays.  Or there might be other reasons.  After all, number of games
was not too large.  Anyway, 3.5.4 must still be stronger, at least
against humans.

Recently I started looking throw game records and fixing mistakes I can.
I already have some new patterns, but will submit them later, when there
is more of them.
</somewhat-offtopic>

This patch is a result of analyzing move 180 (W H6) in the attached
game.  The third item in changelog is the direct fix for this problem,
the other two were required to make it work.

Regression breakage (in addition to solved targeted position):

strategy3:114   FAIL D9 [D7]

        Looks very bad, but seems to be problem with territory valuation
        and not directly related to the patch.  I don't know why D9 gets
        44.75 change in territory while D7 -- only 25.15.

nngs4:170       PASS S6 [S6]

        Looks good.  Many new move reasons for S6, including owl attack
        of O8.

ninestones:40   PASS C2 [!D2]

        Accidential.  C2 is not much better than D2.

ninestones:660  PASS P1 [P1]

        The patch does a good job, though it doesn't correct owl reading
        of course.  Now P1 is at least tried as an owl attack on L10 and
        is found to be working.  There is still a problem with O1 and Q2
        being valued almost as high as P1.

There is an insignificant increase in nodes:

Total nodes: 1502431752 2721480 10958589

Paul



Index: engine/move_reasons.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/move_reasons.c,v
retrieving revision 1.122
diff -u -p -r1.122 move_reasons.c
--- engine/move_reasons.c       24 Jan 2004 04:04:56 -0000      1.122
+++ engine/move_reasons.c       15 Feb 2004 22:11:48 -0000
@@ -142,7 +142,7 @@ clear_move_reasons(void)
  * Find the index of a connection in the list of connections.
  * If necessary, add a new entry.
  */
-static int
+int
 find_connection(int worm1, int worm2)
 {
   int k;
Index: engine/move_reasons.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/move_reasons.h,v
retrieving revision 1.38
diff -u -p -r1.38 move_reasons.h
--- engine/move_reasons.h       24 Jan 2004 04:04:56 -0000      1.38
+++ engine/move_reasons.h       15 Feb 2004 22:11:48 -0000
@@ -201,6 +201,8 @@ void mark_changed_string(int affected, c
                         float strength[BOARDMAX], char new_status);
 int adjacent_to_nondead_stone(int pos, int color);
 
+int find_connection(int worm1, int worm2);
+
 /*
  * Local Variables:
  * tab-width: 8
Index: engine/value_moves.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/value_moves.c,v
retrieving revision 1.118
diff -u -p -r1.118 value_moves.c
--- engine/value_moves.c        24 Jan 2004 04:04:56 -0000      1.118
+++ engine/value_moves.c        15 Feb 2004 22:11:55 -0000
@@ -274,6 +274,124 @@ find_more_attack_and_defense_moves(int c
 }
 
 
+/* Do the real job of find_more_attack_and_defense_moves() with given
+ * move reason at given position and for given target (`what').  This
+ * function is used from induce_secondary_move_reasons() for upgrading
+ * one specific move reason only.
+ */
+static void
+do_find_more_owl_attack_and_defense_moves(int color, int pos,
+                                         int move_reason_type, int what)
+{
+  int k;
+  int dd1 = NO_MOVE;
+  int dd2 = NO_MOVE;
+  int save_verbose;
+
+  save_verbose = verbose;
+  if (verbose > 0)
+    verbose --;
+
+  if (move_reason_type == STRATEGIC_ATTACK_MOVE
+      || move_reason_type == STRATEGIC_DEFEND_MOVE)
+    dd1 = what;
+  else if (move_reason_type == ATTACK_MOVE
+          || move_reason_type == ATTACK_MOVE_GOOD_KO
+          || move_reason_type == ATTACK_MOVE_BAD_KO
+          || move_reason_type == DEFEND_MOVE
+          || move_reason_type == DEFEND_MOVE_GOOD_KO
+          || move_reason_type == DEFEND_MOVE_BAD_KO)
+    dd1 = what;
+  else if (move_reason_type == VITAL_EYE_MOVE) {
+    int ee = eyes[what];
+    int ecolor = eyecolor[what];
+
+    if (ecolor == WHITE)
+      find_eye_dragons(ee, white_eye, WHITE, &dd1, 1);
+    else
+      find_eye_dragons(ee, black_eye, BLACK, &dd1, 1);
+
+    if (dd1 == NO_MOVE) { /* Maybe we should assert this not to happen. */
+      verbose = save_verbose;
+      return;
+    }
+  }
+  else if (move_reason_type == CONNECT_MOVE) {
+    int worm1 = conn_worm1[what];
+    int worm2 = conn_worm2[what];
+
+    dd1 = dragon[worm1].origin;
+    dd2 = dragon[worm2].origin;
+    if (dd1 == dd2)
+      dd2 = NO_MOVE;
+  }
+  else {
+    verbose = save_verbose;
+    return;
+  }
+
+  for (k = 0; k < 2; k++) {
+    int dd = (k == 0 ? dd1 : dd2);
+
+    if (dd == NO_MOVE)
+      continue;
+
+    /* Don't care about inessential dragons. */
+    if (DRAGON2(dd).safety == INESSENTIAL)
+      continue;
+
+    if (DRAGON2(dd).owl_status != CRITICAL)
+      continue;
+
+    if ((move_reason_type == STRATEGIC_ATTACK_MOVE
+        || move_reason_type == ATTACK_MOVE
+        || move_reason_type == ATTACK_MOVE_GOOD_KO
+        || move_reason_type == ATTACK_MOVE_BAD_KO
+        || (move_reason_type == VITAL_EYE_MOVE
+            && board[dd] == OTHER_COLOR(color)))
+       && !owl_attack_move_reason_known(pos, dd)) {
+      int kworm = NO_MOVE;
+      int acode = owl_does_attack(pos, dd, &kworm);
+
+      if (acode >= DRAGON2(dd).owl_attack_code) {
+       if (acode == GAIN)
+         add_gain_move(pos, dd, kworm);
+       else
+         add_owl_attack_move(pos, dd, acode);
+       if (save_verbose)
+         gprintf("Move at %1m upgraded to owl attack on %1m (%s).\n",
+                 pos, dd, result_to_string(acode));
+      }
+    }
+
+    if ((move_reason_type == STRATEGIC_DEFEND_MOVE
+        || move_reason_type == CONNECT_MOVE
+        || move_reason_type == DEFEND_MOVE
+        || move_reason_type == DEFEND_MOVE_GOOD_KO
+        || move_reason_type == DEFEND_MOVE_BAD_KO
+        || (move_reason_type == VITAL_EYE_MOVE
+            && board[dd] == color))
+       && !owl_defense_move_reason_known(pos, dd)) {
+      int kworm = NO_MOVE;
+      /* FIXME: Better use owl_connection_defend() for CONNECT_MOVE ? */
+      int dcode = owl_does_defend(pos, dd, &kworm);
+
+      if (dcode >= DRAGON2(dd).owl_defense_code) {
+       if (dcode == LOSS)
+         add_loss_move(pos, dd, kworm);
+       else
+         add_owl_defense_move(pos, dd, dcode);
+       if (save_verbose)
+         gprintf("Move at %1m upgraded to owl defense for %1m (%s).\n",
+                 pos, dd, result_to_string(dcode));
+      }
+    }
+  }
+
+  verbose = save_verbose;
+}
+
+
 /* Test certain moves to see whether they (too) can owl attack or
  * defend an owl critical dragon. Tested moves are
  * 1. Strategical attacks or defenses for the dragon.
@@ -282,16 +400,15 @@ find_more_attack_and_defense_moves(int c
  * 4. Moves connecting the dragon to something else.
  */
 static void
-find_more_owl_attack_and_defense_moves(int color, int save_verbose)
+find_more_owl_attack_and_defense_moves(int color)
 {
   int pos, pos2;
   int k;
-  int s;
-  int dd1, dd2;
   int dd = NO_MOVE;
   int worth_trying;
-  
-  if (save_verbose)
+  int save_verbose;
+
+  if (verbose)
     gprintf("\nTrying to upgrade strategical attack and defense moves.\n");
 
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
@@ -300,107 +417,19 @@ find_more_owl_attack_and_defense_moves(i
       
     for (k = 0; k < MAX_REASONS; k++) {
       int r = move[pos].reason[k];
-      int what;
-      dd1 = NO_MOVE;
-      dd2 = NO_MOVE;
-      
       if (r < 0)
        break;
-      what = move_reasons[r].what;
-      if (move_reasons[r].type == STRATEGIC_ATTACK_MOVE
-         || move_reasons[r].type == STRATEGIC_DEFEND_MOVE)
-       dd1 = 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)
-       dd1 = what;
-      else if (move_reasons[r].type == VITAL_EYE_MOVE) {
-       int ee = eyes[what];
-       int ecolor = eyecolor[what];
-       
-       if (ecolor == WHITE)
-         find_eye_dragons(ee, white_eye, WHITE, &dd1, 1);
-       else
-         find_eye_dragons(ee, black_eye, BLACK, &dd1, 1);
-       
-       if (dd1 == NO_MOVE) /* Maybe we should assert this not to happen. */
-         continue;
-      }      
-      else if (move_reasons[r].type == CONNECT_MOVE) {
-       int worm1 = conn_worm1[what];
-       int worm2 = conn_worm2[what];
-       dd1 = dragon[worm1].origin;
-       dd2 = dragon[worm2].origin;
-       if (dd1 == dd2)
-         dd2 = NO_MOVE;
-      }
-      else
-       continue;
-      
-      for (s = 0; s < 2; s++) {
-       if (s == 0)
-         dd = dd1;
-       else
-         dd = dd2;
-       
-       if (dd == NO_MOVE)
-         continue;
-       
-       /* Don't care about inessential dragons. */
-       if (DRAGON2(dd).safety == INESSENTIAL)
-         continue;
 
-       if (DRAGON2(dd).owl_status != CRITICAL)
-         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, dd)) {
-         int kworm = NO_MOVE;
-         int acode = owl_does_attack(pos, dd, &kworm);
-         if (acode >= DRAGON2(dd).owl_attack_code) {
-           if (acode == GAIN)
-             add_gain_move(pos, dd, kworm);
-           else
-             add_owl_attack_move(pos, dd, acode);
-           if (save_verbose)
-             gprintf("Move at %1m upgraded to owl attack on %1m (%s).\n",
-                     pos, dd, result_to_string(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, dd)) {
-         int kworm = NO_MOVE;
-         /* FIXME: Better use owl_connection_defend() for CONNECT_MOVE ? */
-         int dcode = owl_does_defend(pos, dd, &kworm);
-         if (dcode >= DRAGON2(dd).owl_defense_code) {
-           if (dcode == LOSS)
-             add_loss_move(pos, dd, kworm);
-           else
-             add_owl_defense_move(pos, dd, dcode);
-           if (save_verbose)
-             gprintf("Move at %1m upgraded to owl defense for %1m (%s).\n",
-                     pos, dd, result_to_string(dcode));
-         }
-       }
-      }
+      do_find_more_owl_attack_and_defense_moves(color, pos,
+                                               move_reasons[r].type,
+                                               move_reasons[r].what);
     }
   }
 
+  save_verbose = verbose;
+  if (verbose > 0)
+    verbose--;
+
   /* If two critical dragons are adjacent, test whether a move to owl
    * attack or defend one also is effective on the other.
    */
@@ -468,8 +497,9 @@ find_more_owl_attack_and_defense_moves(i
       }
     }
   }
-}
 
+  verbose = save_verbose;
+}
 
 
 /*
@@ -578,8 +608,10 @@ induce_secondary_move_reasons(int color)
                      "Connection move at %1m induced for %1m/%1m due to attack 
of %1m\n",
                      pos, adj1, adj2, aa);
                add_connection_move(pos, adj1, adj2);
+               do_find_more_owl_attack_and_defense_moves(color, pos, 
CONNECT_MOVE,
+                                                         find_connection(adj1, 
adj2));
              }
-                 
+
              if (!attack_move
                  && board[adj1] != board[aa]
                  && !string_connect(adj1, adj2, NULL)) {
@@ -596,12 +628,68 @@ induce_secondary_move_reasons(int color)
                      "Connection move at %1m induced for %1m/%1m due to 
defense of %1m\n",
                      pos, adj1, adj2, aa);
                add_connection_move(pos, adj1, adj2);
+               do_find_more_owl_attack_and_defense_moves(color, pos, 
CONNECT_MOVE,
+                                                         find_connection(adj1, 
adj2));
              }
-                 
+
              popgo();
            }
          }
-       }  
+       }
+
+       /* Strategical attack move reason is induced for moves that
+        * defend neighbor strings of weak opponent dragons a.  We
+        * only count strings that are large (more than three stones)
+        * or adjoin at least two non-dead non-single-stone opponent
+        * dragons.
+        */
+       if (!attack_move) {
+         int strategically_valuable = (worm[aa].size > 3);
+         char neighbor_dragons[BOARDMAX];
+
+         memset(neighbor_dragons, 0, sizeof(neighbor_dragons));
+
+         if (!strategically_valuable) {
+           int num_dragons = 0;
+
+           for (i = 0; i < num_adj; i++) {
+             int origin = dragon[adjs[i]].origin;
+
+             if (board[origin] != color_to_move
+                 && neighbor_dragons[origin] != 1
+                 && dragon[origin].size > 1
+                 && dragon[origin].status != DEAD) {
+               if (++num_dragons == 2) {
+                 strategically_valuable = 1;
+                 break;
+               }
+
+               neighbor_dragons[origin] = 1;
+             }
+           }
+         }
+
+         if (strategically_valuable) {
+           for (i = 0; i < num_adj; i++) {
+             int origin = dragon[adjs[i]].origin;
+
+             if (board[origin] != color_to_move
+                 && neighbor_dragons[origin] != 2
+                 && dragon[origin].status != DEAD
+                 && dragon_weak(origin)) {
+               DEBUG(DEBUG_MOVE_REASONS,
+                     "Strategical attack move at %1m induced for %1m due to 
defense of %1m\n",
+                     pos, origin, aa);
+               add_strategical_attack_move(pos, origin);
+               do_find_more_owl_attack_and_defense_moves(color, pos,
+                                                         STRATEGIC_ATTACK_MOVE,
+                                                         origin);
+
+               neighbor_dragons[origin] = 2;
+             }
+           }
+         }
+       }
       }
       else if (move_reasons[r].type == OWL_ATTACK_MOVE) {
        aa = move_reasons[r].what;
@@ -610,6 +698,9 @@ induce_secondary_move_reasons(int color)
          if (dragon[bb].color == color && worm[bb].attack_codes[0] == 0
              && !DRAGON2(bb).semeai) {
            add_strategical_defense_move(pos, bb);
+           do_find_more_owl_attack_and_defense_moves(color, pos,
+                                                     STRATEGIC_DEFEND_MOVE,
+                                                     bb);
            DEBUG(DEBUG_MOVE_REASONS, "Strategic defense at %1m induced for %1m 
due to owl attack on %1m\n",
                  pos, bb, aa);
          }
@@ -633,11 +724,15 @@ induce_secondary_move_reasons(int color)
                            worm1, EMPTY, NO_MOVE)) {
                  if (!disconnect(pos3, worm1, NULL)) {
                    add_connection_move(pos, pos3, worm1);
+                   do_find_more_owl_attack_and_defense_moves(color, pos, 
CONNECT_MOVE,
+                                                             
find_connection(pos3, worm1));
                    DEBUG(DEBUG_MOVE_REASONS, "Connection at %1m induced for 
%1m/%1m due to connection at %1m/%1m\n",
                          pos, worm1, worm2, pos3, worm1);
                  }
                  if (!disconnect(pos3, worm2, NULL)) {
                    add_connection_move(pos, pos3, worm2);
+                   do_find_more_owl_attack_and_defense_moves(color, pos, 
CONNECT_MOVE,
+                                                             
find_connection(pos3, worm2));
                    DEBUG(DEBUG_MOVE_REASONS, "Connection at %1m induced for 
%1m/%1m due to connection at %1m/%1m\n",
                          pos, worm1, worm2, pos3, worm2);
                  }
@@ -3285,15 +3380,12 @@ review_move_reasons(int *the_move, float
   find_more_attack_and_defense_moves(color);
   time_report(2, "  find_more_attack_and_defense_moves", NO_MOVE, 1.0);
 
-  save_verbose = verbose;
-  if (verbose > 0)
-    verbose--;
   if (level >= 6) {
-    find_more_owl_attack_and_defense_moves(color, save_verbose);
+    find_more_owl_attack_and_defense_moves(color);
     time_report(2, "  find_more_owl_attack_and_defense_moves", NO_MOVE, 1.0);
   }
-  verbose = save_verbose;
 
+  save_verbose = verbose;
   if (verbose > 0)
     verbose--;
   examine_move_safety(color);

Attachment: twogtp-1-002.sgf
Description: Text document


reply via email to

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