gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] corner matcher


From: Paul Pogonyshev
Subject: [gnugo-devel] corner matcher
Date: Fri, 24 Jan 2003 00:19:17 +0200
User-agent: KMail/1.4.3

finally it is completed :)

- joseki patterns are matched using corner matcher
- symmetrical joseki patterns no longer match twice
- antisuji joseki patterns are handled by callback now

there seemed to be a single bug which showed up when i ran
regressions. the problem was in num_stones[] array on small
boards (e.g. 9x9) and is now fixed.

there are no regression changes if compared with current cvs
after the fix.

i have added a new callback to shapes.c called joseki_callback().
it is only used with corner matcher. i just copied shapes_callback
and then deleted everything which is not needed by joseki patterns.
shapes_callback() is not modified, since there are some joseki
patterns in patterns.db.

i have added support for symmetrical joseki patterns in joseki.c,
mkpat.c and matchpat.c. actually, it doesn't seem to influence
move valuation and there are only four symmetrical patterns at
the moment, but i think it was a right thing to do nevertheless.

antisuji patterns are now handled in joseki_callback(), not in
autohelpers. it saved some debug information in executable ;),
but i made it taking in mind joseki reader (which will be written
one day, i hope) - it certainly shouldn't read antisuji variations.

i haven't eliminated the warnings in hoshi.db (duplicated variations
in hoshi.sgf), but they don't influence database generation, so this
issue can wait for a bit. there are now two more warnings: komoku.sgf
uses value() directive twice and it is (currently?) not supported by
corner matcher. omitting value() directives has no impact on move
valuation, since J class patterns are already valued to at least 35
points, while komoku.sgf contains value(28).

the gain at the moment is a large decrease in executable size (it is
now 4.4 mb with gcc 3.2) and probably a tiny overall speedup.

i can see two ways in which this matcher can bring benefits in
future. first of all, since joseki database is stored in much more
compact way now (though not even nearly that compact as by many
faces), it can be significantly extended if anyone is willing to
do that.

the second potential use is a joseki reader. it will allow to
choose a joseki variation based on influence of other stones and
generally value joseki moves better (not just fixed valuation
based on whether a move is urgent/standard/less urgent/tenuki ok).

i'm not too familiar with automake, so i changed Makefile, Makefile.am
and Makefile.in. please, edit the patch if i did something wrong at this
point. it may also be possible to add an option to configure script to
select joseki matcher (corner/standard), but i'm unsure how to do that.
if you decide to do this, you should only put three conditional clauses:

in patterns/Makefile:
  for standard matcher:
        cat  $(DBBUILT) | ./mkpat -b joseki >josekidb.c

  for corner matcher:
        cat  $(DBBUILT) | ./mkpat -C joseki >josekidb.c

in patterns/patterns.h:
  for standard matcher:
extern struct pattern_db joseki_db;

  for corner matcher:
extern struct corner_db  joseki_db;

and in engine/shapes.c:
  for standard matcher:
     matchpat(shapes_callback, color, &joseki_db, NULL, NULL);

  for corner matcher:
     corner_matchpat(joseki_callback, color, &joseki_db);
(this is already #if'ed with 1 - corner matcher by default)

in addition you may #if out corner matcher in matchpat.c and
joseki_callback() in shapes.c.

Paul


p.s. my editor deleted spaces at the end of lines, so the patch looks
     somewhat larger than it really is.



Index: engine/liberty.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/liberty.h,v
retrieving revision 1.152
diff -u -p -r1.152 liberty.h
--- engine/liberty.h    12 Jan 2003 20:51:45 -0000      1.152
+++ engine/liberty.h    23 Jan 2003 21:37:38 -0000
@@ -268,8 +268,8 @@ struct tree_node_list;
 struct match_node;
 
 /*
- * Try to match a pattern in the database to the board. Callback for
- * each match
+ * Try to match a pattern in the database to the board. Callbacks for
+ * each match.
  */
 typedef void (*matchpat_callback_fn_ptr)(int anchor, int color,
                                          struct pattern *, int rotation,
@@ -279,7 +279,8 @@ typedef void (*fullboard_matchpat_callba
                                                    int rotation);
 typedef void (*corner_matchpat_callback_fn_ptr)(int move, int color,
                                                struct corner_pattern *pattern,
-                                               int rotation);
+                                               int trans,
+                                               int *stones, int num_stones);
 void matchpat(matchpat_callback_fn_ptr callback, int color,
              struct pattern_db *pdb, void *callback_data,
              char goal[BOARDMAX]);
Index: engine/matchpat.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/matchpat.c,v
retrieving revision 1.51
diff -u -p -r1.51 matchpat.c
--- engine/matchpat.c   14 Jan 2003 20:50:33 -0000      1.51
+++ engine/matchpat.c   23 Jan 2003 21:38:26 -0000
@@ -205,7 +205,7 @@ static const int val_mask[2][8] = {
  * initially set to 0, and we overwrite the ones
  * we care about each time.
  */
-  
+
 static unsigned int class_mask[MAX_DRAGON_STATUS][3];
 
 
@@ -233,37 +233,37 @@ fixup_patterns_for_board_size(struct pat
        * below before we do them anew. The first time this function is
        * called, this step is effectively a no-op.
        */
-      
+
       if (pattern->edge_constraints & NORTH_EDGE)
        pattern->maxi = pattern->mini + pattern->height;
-       
+
       if (pattern->edge_constraints & SOUTH_EDGE)
        pattern->mini = pattern->maxi - pattern->height;
-       
+
       if (pattern->edge_constraints & WEST_EDGE)
        pattern->maxj = pattern->minj + pattern->width;
-      
+
       if (pattern->edge_constraints & EAST_EDGE)
        pattern->minj = pattern->maxj - pattern->width;
-      
+
       /* we extend the pattern in the direction opposite the constraint,
        * such that maxi (+ve) - mini (-ve) = board_size-1
        * Note : the pattern may be wider than the board, so
        * we need to be a bit careful !
        */
-      
+
       if (pattern->edge_constraints & NORTH_EDGE)
        if (pattern->maxi < (board_size-1) + pattern->mini)
          pattern->maxi = (board_size-1) + pattern->mini;
-      
+
       if (pattern->edge_constraints & SOUTH_EDGE)
        if (pattern->mini > pattern->maxi - (board_size-1))
          pattern->mini = pattern->maxi - (board_size-1);
-      
+
       if (pattern->edge_constraints & WEST_EDGE)
        if (pattern->maxj <  (board_size-1) + pattern->minj)
          pattern->maxj = (board_size-1) + pattern->minj;
-      
+
       if (pattern->edge_constraints & EAST_EDGE)
        if (pattern->minj > pattern->maxj - (board_size-1))
          pattern->minj = pattern->maxj - (board_size-1);
@@ -271,7 +271,7 @@ fixup_patterns_for_board_size(struct pat
 }
 
 
-/* 
+/*
  * prepare a pattern matching for color point of view
  */
 static void
@@ -299,7 +299,7 @@ prepare_for_match(int color)
  * in liberty.h.
  */
 
-void 
+void
 transform2(int i, int j, int *ti, int *tj, int trans)
 {
   TRANSFORM2(i, j, ti, tj, trans);
@@ -320,7 +320,7 @@ transform2(int i, int j, int *ti, int *t
 static void
 do_matchpat(int anchor, matchpat_callback_fn_ptr callback, int color,
            struct pattern *pattern, void *callback_data,
-           char goal[BOARDMAX]) 
+           char goal[BOARDMAX])
 {
   const int anchor_test = board[anchor] ^ color;  /* see below */
   int m = I(anchor);
@@ -364,7 +364,7 @@ do_matchpat(int anchor, matchpat_callbac
       int ll;   /* Iterate over transformations (rotations or reflections)  */
       int k;    /* Iterate over elements of pattern */
       int found_goal, found_nongoal;
-  
+
       /* We can check the color of the anchor stone now.
        * Roughly half the patterns are anchored at each
        * color, and since the anchor stone is invariant under
@@ -1215,20 +1215,20 @@ fullboard_matchpat(fullboard_matchpat_ca
   /* We transform around the center point. */
   int mid = POS((board_size-1)/2, (board_size-1)/2);
   int number_of_stones_on_board = stones_on_board(BLACK | WHITE);
-  
+
   /* Basic sanity check. */
   gg_assert(color != EMPTY);
   gg_assert(board_size % 2 == 1);
 
   /* Try each pattern - NULL pattern marks end of list. */
-  for (; pattern->patn; pattern++) { 
+  for (; pattern->patn; pattern++) {
     /* The number of stones on the board must be right. This is not
      * only an optimization because we never even look at the
      * intersections which are empty in the pattern.
      */
     if (pattern->patlen != number_of_stones_on_board)
       continue;
-    
+
     /* try each orientation transformation */
     for (ll = 0; ll < 8; ll++) {
       /* Now iterate over the elements of the pattern. */
@@ -1244,9 +1244,9 @@ fullboard_matchpat(fullboard_matchpat_ca
        if ((att == ATT_O && board[pos] != color)
            || (att == ATT_X && board[pos] != other))
          break;
-       
+
       } /* loop over elements */
-       
+
       if (k == pattern->patlen) {
        /* A match!  - Call back to the invoker to let it know. */
        int pos = AFFINE_TRANSFORM(pattern->move_offset, ll, mid);
@@ -1277,15 +1277,28 @@ static const int corner_y[8] = {0, 1, 1,
  * 1 |#####...         Their distances are "incomparable" since E < G but
  *   +--------         3 > 2.
  *    A   E
+ *
+ * Note that we need these values in at most MAX_BOARD x MAX_BOARD array.
+ * However, it may be anchored at any corner of the board, so if the board is
+ * small, we may calculate num_stones[] at negative coordinates. In addition,
+ * this array must have the same coordinate system as board[] (it must be
+ * (MAX_BOARD + 1 elements "wide"). That's why such a strange array allocation.
+ */
+static int real_num_stones[(MAX_BOARD + 1) * (2 * MAX_BOARD - MIN_BOARD)];
+static int *const num_stones = real_num_stones
+                            + (MAX_BOARD + 1) * (MAX_BOARD - MIN_BOARD);
+
+/* Stone locations are stored in this array. They might be needed by callback
+ * function.
  */
-static int num_stones[BOARDMAX];
+static int pattern_stones[BOARDMAX];
 
 
 /* Recursively performs corner matching. This function checks whether
  * `num_variation' variations pointed by `variation' parameter match.
- * If any of them do, it calls itself recursively. If any pattern
- * corresponding to those variations matches, it notifies callback
- * function.
+ * If any of them does, the fuunction calls itself recursively. If any
+ * pattern corresponding to those variations matches, it notifies
+ * callback function.
  */
 static void
 do_corner_matchpat(int num_variations, struct corner_variation *variation,
@@ -1301,11 +1314,12 @@ do_corner_matchpat(int num_variations, s
       int second_corner
          = AFFINE_TRANSFORM(pattern->second_corner_offset, trans, anchor);
 
-      if (num_stones[second_corner] == stones) {
+      if (num_stones[second_corner] == stones
+         && (!pattern->symmetric || trans < 4)) {
        /* We have found a matching pattern. */
        ASSERT1(board[move] == EMPTY, move);
 
-       callback(move, callback_color, pattern, trans);
+       callback(move, callback_color, pattern, trans, pattern_stones, stones);
       }
     }
 
@@ -1313,6 +1327,7 @@ do_corner_matchpat(int num_variations, s
        && num_stones[move] == variation->num_stones
        && board[move] == color_check) {
       /* A matching variation. */
+      pattern_stones[stones] = move;
       do_corner_matchpat(variation->num_variations, variation->variations,
                         match_color, callback, callback_color,
                         trans, anchor, stones + 1);
@@ -1372,10 +1387,10 @@ corner_matchpat(corner_matchpat_callback
 
        break;
       }
-      
+
       num_stones[pos] = num_stones[pos - dy] + IS_STONE(board[pos]);
     }
-    
+
     for (i = 1; i < database->max_height; i++) {
       pos = anchor + i * dy;
       for (j = 1; j < database->max_width; j++) {
@@ -1391,9 +1406,11 @@ corner_matchpat(corner_matchpat_callback
     for (i = 0; i < database->num_top_variations; i++) {
       int move = AFFINE_TRANSFORM(variation->move_offset, k, anchor);
 
-      if (num_stones[move] == 1 && IS_STONE(board[move]))
+      if (num_stones[move] == 1 && IS_STONE(board[move])) {
+       pattern_stones[0] = move;
        do_corner_matchpat(variation->num_variations, variation->variations,
                           board[move], callback, color, k, anchor, 1);
+      }
 
       variation++;
     }
Index: engine/shapes.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/shapes.c,v
retrieving revision 1.43
diff -u -p -r1.43 shapes.c
--- engine/shapes.c     2 Jan 2003 00:23:29 -0000       1.43
+++ engine/shapes.c     23 Jan 2003 21:40:26 -0000
@@ -39,7 +39,7 @@
 #define t_VALUE 17.0
 
 
-/* 
+/*
  * This callback is invoked for each matched pattern.
  */
 
@@ -48,15 +48,14 @@ shapes_callback(int anchor, int color, s
                void *data)
 {
   int other = OTHER_COLOR(color);
-  
+
   int k, l;
   int move;
-  /* For restricted search, the pattern must intersect the search area */
-  
+
   /* Dragons of our color. */
   int my_dragons[MAX_DRAGONS_PER_PATTERN];
   int my_ndragons = 0;
-  
+
   /* Dragons of other color. */
   int your_dragons[MAX_DRAGONS_PER_PATTERN];
   int your_ndragons = 0;
@@ -64,7 +63,7 @@ shapes_callback(int anchor, int color, s
   /* Strings of our color. */
   int my_strings[MAX_STRINGS_PER_PATTERN];
   int my_nstrings = 0;
-  
+
   /* Strings of other color. */
   int your_strings[MAX_STRINGS_PER_PATTERN];
   int your_nstrings = 0;
@@ -75,13 +74,14 @@ shapes_callback(int anchor, int color, s
   /* Don't accept fuseki marked patterns while scoring. */
   if (doing_scoring && (class & CLASS_F))
     return;
-  
+
   /* Don't need auxiliary data in this callback. */
   UNUSED(data);
-  
+
   /* Pick up the location of the move */
   move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor);
-  
+
+  /* For restricted search, the pattern must intersect the search area */
   if (limit_search && !within_search_area(move))
     return;
 
@@ -94,14 +94,14 @@ shapes_callback(int anchor, int color, s
     for (k = 0; k < pattern->patlen; ++k) {
       int pos; /* absolute (board) co-ord of (transformed) pattern element */
       int origin; /* dragon origin */
-      
+
       /* all the following stuff (currently) applies only at occupied cells */
       if (pattern->patn[k].att == ATT_dot)
        continue;
-      
+
       /* transform pattern real coordinate */
       pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor);
-      
+
       /* Already, matchpat rejects O patterns containing a friendly stone with
        * DEAD or CRITICAL matcher_status. If the stone is tactically
        * CRITICAL it still could have matcher_status ALIVE since it might
@@ -125,7 +125,7 @@ shapes_callback(int anchor, int color, s
        if (l == my_ndragons) {
          /* We found another dragon of our color. Check that it (or
            * rather the underlying worm) cannot be tactically
-           * captured before adding it to the list of my_dragons.  
+           * captured before adding it to the list of my_dragons.
           */
          if (worm[pos].attack_codes[0] == 0
              || does_defend(move, pos)) {
@@ -147,7 +147,7 @@ shapes_callback(int anchor, int color, s
          your_ndragons++;
        }
       }
-      
+
       if (pattern->patn[k].att == ATT_O || pattern->patn[k].att == ATT_X) {
        origin = find_origin(pos);
        if (board[pos] == color && my_nstrings < MAX_STRINGS_PER_PATTERN) {
@@ -207,7 +207,7 @@ shapes_callback(int anchor, int color, s
       && !(pattern->autohelper_flag & HAVE_ACTION)
       && !(class & (CLASS_MOVE_REASONS | CLASS_MOVE_VALUES)))
     return;
-  
+
   /* For sacrifice patterns, the survival of the stone to be played is
    * not checked (but it still needs to be legal). Otherwise we
    * discard moves which can be captured.
@@ -228,7 +228,7 @@ shapes_callback(int anchor, int color, s
       return;
     }
   }
-  
+
   /* For class n patterns, the pattern is contingent on an opponent
    * move at * not being captured.
    */
@@ -240,7 +240,7 @@ shapes_callback(int anchor, int color, s
       return;
     }
   }
-  
+
   /* If the pattern has a constraint, call the autohelper to see
    * if the pattern must be rejected.
    */
@@ -253,26 +253,26 @@ shapes_callback(int anchor, int color, s
   if (pattern->helper) {
     /* ask helper function to consider the move */
     int accepted;
-    DEBUG(DEBUG_HELPER, "  asking helper to consider '%s'+%d at %1m\n", 
+    DEBUG(DEBUG_HELPER, "  asking helper to consider '%s'+%d at %1m\n",
          pattern->name, ll, move);
     accepted = pattern->helper(pattern, ll, move, color);
-    
+
     if (accepted) {
       DEBUG(DEBUG_HELPER, "helper likes pattern '%s' at %1m\n",
            pattern->name, move);
     }
     else {
-      DEBUG(DEBUG_HELPER, "  helper does not like pattern '%s' at %1m\n", 
+      DEBUG(DEBUG_HELPER, "  helper does not like pattern '%s' at %1m\n",
            pattern->name, move);
       return;  /* pattern matcher does not like it */
     }
   }
-      
+
   /* If using -a, want to see all matches even if not -v */
   if (allpats || verbose) {
     TRACE("pattern '%s'+%d matched at %1m\n", pattern->name, ll, move);
   }
-  
+
   /* does the pattern have an action? */
   if (pattern->autohelper_flag & HAVE_ACTION)
     pattern->autohelper(ll, move, color, 1);
@@ -358,7 +358,7 @@ shapes_callback(int anchor, int color, s
       TRACE("...strategical attack on %1m\n", your_dragons[k]);
     }
   }
-  
+
   /* Pattern class d, strategical level defense of all own dragons. */
   if (class & CLASS_d) {
     for (k = 0; k < my_ndragons; k++) {
@@ -394,7 +394,7 @@ shapes_callback(int anchor, int color, s
 
     /* Board size modification. */
     min_value *= board_size / 19.0;
-    
+
     if (class & VALUE_SHAPE) {
       min_value *= (1 + 0.01 * pattern->shape);
       class &= ~VALUE_SHAPE;
@@ -407,7 +407,7 @@ shapes_callback(int anchor, int color, s
       scale_randomness(move, 5.);
       TRACE("...move value %f (shape %f)\n", min_value, pattern->shape);
     }
-    else 
+    else
       TRACE("...minimum move value %f (shape %f)\n",
             min_value, pattern->shape);
     set_minimum_move_value(move, min_value);
@@ -419,15 +419,15 @@ shapes_callback(int anchor, int color, s
   if (class & CLASS_t) {
     float min_value = t_VALUE;
     TRACE("...minor joseki move\n");
-    
+
     /* Board size modification. */
     min_value *= board_size / 19.0;
-    
+
     if (class & VALUE_SHAPE) {
       min_value *= (1 + 0.01 * pattern->shape);
       class &= ~VALUE_SHAPE;
     };
-    
+
     if ((board_size >= 17) && (class & CLASS_F)) {
       min_value *= 1.005; /* Otherwise, j patterns not of CLASS_F would */
                           /* get preferred in value_move_reasons */
@@ -435,13 +435,13 @@ shapes_callback(int anchor, int color, s
       scale_randomness(move, 5.);
       TRACE("...move value %f (shape %f)\n", min_value, pattern->shape);
     }
-    else 
+    else
       TRACE("...minimum move value %f (shape %f)\n",
             min_value, pattern->shape);
     set_minimum_move_value(move, min_value);
   }
 
-  /* Pattern class U, very urgent move joseki. Add strategical defense
+  /* Pattern class U, very urgent joseki move. Add strategical defense
    * and attack, plus a shape bonus of 15 and a minimum value of 40.
    */
   if (class & CLASS_U) {
@@ -520,8 +520,207 @@ shapes_callback(int anchor, int color, s
 }
 
 
+/* This callback is invoked for each matched pattern from joseki database.
+ * This function is just a copy of relevant parts of shapes_callback().
+ */
+static void
+joseki_callback(int move, int color, struct corner_pattern *pattern,
+               int trans, int *stones, int num_stones)
+{
+  int k, l;
+  int class = pattern->class;
+
+  /* Dragons of our color. */
+  int my_dragons[MAX_DRAGONS_PER_PATTERN];
+  int my_ndragons = 0;
+
+  /* Dragons of other color. */
+  int your_dragons[MAX_DRAGONS_PER_PATTERN];
+  int your_ndragons = 0;
+
+  /* For restricted search, the pattern must intersect the search area. */
+  if (limit_search && !within_search_area(move))
+    return;
+
+  /* For urgent joseki patterns we need to find all dragons present in the
+   * pattern since such patterns are assumed to have strategical effect on
+   * them.
+   */
+  if (class & CLASS_U) {
+    /* Loop over all stones in the pattern. */
+    for (k = 0; k < num_stones; k++) {
+      int pos = stones[k];
+      int origin = dragon[pos].origin;
+
+      if (board[pos] == color && my_ndragons < MAX_DRAGONS_PER_PATTERN) {
+       for (l = 0; l < my_ndragons; l++) {
+         if (my_dragons[l] == origin)
+           break;
+       }
+
+       if (l == my_ndragons) {
+         /* We found another dragon of our color. Check that it (or
+           * rather the underlying worm) cannot be tactically
+           * captured before adding it to the list of my_dragons.
+          */
+         if (worm[pos].attack_codes[0] == 0 || does_defend(move, pos)) {
+           /* Ok, add the dragon to the list. */
+           my_dragons[l] = origin;
+           my_ndragons++;
+         }
+       }
+      }
+
+      if (board[pos] != color && your_ndragons < MAX_DRAGONS_PER_PATTERN) {
+       for (l = 0; l < your_ndragons; l++) {
+         if (your_dragons[l] == origin)
+           break;
+       }
+       if (l == your_ndragons) {
+         /* We found another opponent dragon, add it to the list. */
+         your_dragons[l] = origin;
+         your_ndragons++;
+       }
+      }
+    }
+  }
+
+  /* For joseki patterns we don't check if the proposed move is safe or legal.
+   */
+
+  /* If the pattern has a constraint, call the autohelper to see
+   * if the pattern must be rejected.
+   */
+  if (pattern->autohelper_flag & HAVE_CONSTRAINT) {
+    if (!pattern->autohelper(trans, move, color, 0))
+      return;
+  }
+
+  /* If using -a, want to see all matches even if not -v. */
+  if (allpats || verbose)
+    TRACE("pattern '%s'+%d matched at %1m\n", pattern->name, trans, move);
+
+  /* Does the pattern have an action? */
+  if (pattern->autohelper_flag & HAVE_ACTION)
+    pattern->autohelper(trans, move, color, 1);
+
+  /* Pattern class J, joseki standard move. Add expand territory and
+   * moyo, and require the value at least J_value.
+   */
+  if (class & CLASS_J) {
+    TRACE("...joseki standard move\n");
+    add_expand_territory_move(move);
+    TRACE("...expands territory\n");
+    add_expand_moyo_move(move);
+    TRACE("...expands moyo\n");
+    set_minimum_move_value(move, J_VALUE);
+    TRACE("... minimum move value %f\n", J_VALUE);
+  }
+
+  /* Pattern class j, less urgent joseki move. Add expand territory and
+   * moyo, set a minimum value of j_VALUE. If it is a fuseki pattern, set also
+   * the maximum value to j_VALUE.
+   */
+  if (class & CLASS_j) {
+    float min_value = j_VALUE;
+    TRACE("...less urgent joseki move\n");
+    add_expand_territory_move(move);
+    TRACE("...expands territory\n");
+    add_expand_moyo_move(move);
+    TRACE("...expands moyo\n");
+
+    /* Board size modification. */
+    min_value *= board_size / 19.0;
+
+    if (class & VALUE_SHAPE) {
+      min_value *= (1 + 0.01 * pattern->shape);
+      class &= ~VALUE_SHAPE;
+    };
+
+    if (board_size >= 17) {
+      min_value *= 1.005; /* Otherwise, j patterns not of CLASS_F would */
+                          /* get preferred in value_move_reasons(). */
+      set_maximum_move_value(move, min_value);
+      scale_randomness(move, 5.);
+      TRACE("...move value %f (shape %f)\n", min_value, pattern->shape);
+    }
+    else
+      TRACE("...minimum move value %f (shape %f)\n",
+            min_value, pattern->shape);
+    set_minimum_move_value(move, min_value);
+  }
+
+  /* Pattern class t, minor joseki move (tenuki OK).
+   * Set the (min-)value at t_value
+   */
+  if (class & CLASS_t) {
+    float min_value = t_VALUE;
+    TRACE("...minor joseki move\n");
+
+    /* Board size modification. */
+    min_value *= board_size / 19.0;
+
+    if (class & VALUE_SHAPE) {
+      min_value *= (1 + 0.01 * pattern->shape);
+      class &= ~VALUE_SHAPE;
+    };
+
+    if ((board_size >= 17) && (class & CLASS_F)) {
+      min_value *= 1.005; /* Otherwise, j patterns not of CLASS_F would */
+                          /* get preferred in value_move_reasons */
+      set_maximum_move_value(move, min_value);
+      scale_randomness(move, 5.);
+      TRACE("...move value %f (shape %f)\n", min_value, pattern->shape);
+    }
+    else
+      TRACE("...minimum move value %f (shape %f)\n",
+            min_value, pattern->shape);
+    set_minimum_move_value(move, min_value);
+  }
+
+  /* Pattern class U, very urgent joseki move. Add strategical defense
+   * and attack, plus a shape bonus of 15 and a minimum value of 40.
+   */
+  if (class & CLASS_U) {
+    TRACE("...joseki urgent move\n");
+    for (k = 0; k < my_ndragons; k++) {
+      add_strategical_defense_move(move, my_dragons[k]);
+      TRACE("...strategical defense of %1m\n", my_dragons[k]);
+    }
+    urgent = 1;
+    for (k = 0; k < your_ndragons; k++) {
+      add_strategical_attack_move(move, your_dragons[k]);
+      TRACE("...strategical attack on %1m\n", your_dragons[k]);
+    }
+    add_shape_value(move, 15);
+    TRACE("...shape value 15\n");
+    set_minimum_move_value(move, U_VALUE);
+    TRACE("...(min) move value %f\n", U_VALUE);
+  }
+
+  /* Pattern class T, joseki trick move. For the moment we never play these. */
+  if (class & CLASS_T) {
+    TRACE("...joseki trick move\n");
+    add_antisuji_move(move);
+    TRACE("...antisuji\n");
+  }
+
+  /* Pattern class N, antisuji move. */
+  if (class & CLASS_N) {
+    TRACE("...antisuji move\n");
+    add_antisuji_move(move);
+  }
+
+  /* Shape value specified. */
+  if (class & VALUE_SHAPE) {
+    add_shape_value(move, pattern->shape);
+    TRACE("...shape value %f\n", pattern->shape);
+  }
+}
+
+
 /*
- * Match all patterns in patterns.db and patterns2.db on all positions.  
+ * Match all patterns in patterns.db and patterns2.db on all positions.
  *
  * This function is one of the basic generators of move reasons, called
  * by genmove().
@@ -534,8 +733,13 @@ shapes(int color)
 
   matchpat(shapes_callback, color, &pat_db, NULL, NULL);
 
-  if (josekidb)
+  /* Don't match joseki patterns while scoring. */
+  if (josekidb && !doing_scoring);
+#if 1
+    corner_matchpat(joseki_callback, color, &joseki_db);
+#else
     matchpat(shapes_callback, color, &joseki_db, NULL, NULL);
+#endif
 
   if (!disable_fuseki && !doing_scoring)
     matchpat(shapes_callback, color, &fusekipat_db, NULL, NULL);
Index: patterns/Makefile.am
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/Makefile.am,v
retrieving revision 1.16
diff -u -p -r1.16 Makefile.am
--- patterns/Makefile.am        16 Nov 2002 00:30:25 -0000      1.16
+++ patterns/Makefile.am        23 Jan 2003 21:40:32 -0000
@@ -102,7 +102,7 @@ patterns.c : $(srcdir)/patterns.db $(src
                | ./mkpat -b pat >patterns.c
 
 josekidb.c : $(DBBUILT) mkpat$(EXEEXT)
-       cat  $(DBBUILT) | ./mkpat -b joseki >josekidb.c
+       cat  $(DBBUILT) | ./mkpat -C joseki >josekidb.c
 
 apatterns.c : $(srcdir)/attack.db mkpat$(EXEEXT)
        cat $(srcdir)/attack.db | ./mkpat -X attpat >apatterns.c
Index: patterns/Makefile.in
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/Makefile.in,v
retrieving revision 1.34
diff -u -p -r1.34 Makefile.in
--- patterns/Makefile.in        16 Nov 2002 00:30:25 -0000      1.34
+++ patterns/Makefile.in        23 Jan 2003 21:40:35 -0000
@@ -502,7 +502,7 @@ patterns.c : $(srcdir)/patterns.db $(src
                | ./mkpat -b pat >patterns.c
 
 josekidb.c : $(DBBUILT) mkpat$(EXEEXT)
-       cat  $(DBBUILT) | ./mkpat -b joseki >josekidb.c
+       cat  $(DBBUILT) | ./mkpat -C joseki >josekidb.c
 
 apatterns.c : $(srcdir)/attack.db mkpat$(EXEEXT)
        cat $(srcdir)/attack.db | ./mkpat -X attpat >apatterns.c
Index: patterns/joseki.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/joseki.c,v
retrieving revision 1.16
diff -u -p -r1.16 joseki.c
--- patterns/joseki.c   3 Jan 2003 18:23:42 -0000       1.16
+++ patterns/joseki.c   23 Jan 2003 21:42:30 -0000
@@ -165,10 +165,10 @@ write_diagram(int movei, int movej, int 
 
 /* Write the colon line of the pattern. */
 static void
-write_colon_line(int move_type, char *text)
+write_colon_line(int move_type, char symmetry, char *text)
 {
   char *p;
-  
+
   /* Locate a possible colon line in the sgf file comment. */
   if (!text)
     p = NULL;
@@ -180,7 +180,7 @@ write_colon_line(int move_type, char *te
       p += 2;
   }
 
-  printf(":8,sF");
+  printf(":%c,sF", symmetry);
   switch (move_type) {
   case URGENT:
     printf("U");
@@ -216,6 +216,24 @@ write_colon_line(int move_type, char *te
 }
 
 
+/* Check if the board and labels are symmetric. */
+static int
+board_is_symmetric(int n, char labels[MAX_BOARD][MAX_BOARD])
+{
+  int i;
+  int j;
+
+  for (i = 0; i <= n; i++) {
+    for (j = 0; j < i; j++) {
+      if (BOARD(i, j) != BOARD(j, i)
+         || (labels && labels[i][j] != labels[j][i]))
+       return 0;
+    }
+  }
+
+  return 1;
+}
+
 /* Write a pattern to stdout. */
 static void
 make_pattern(int movei, int movej, int color,
@@ -225,24 +243,27 @@ make_pattern(int movei, int movej, int c
 {
   static int pattern_number = 0;
   int move_type;
-  
+  char symmetry = '8';
+
   pattern_number++;
   move_type = identify_move_type(text);
-  
+
   printf("Pattern %s%d\n", prefix, pattern_number);
 
   /* Write comments. */
   write_selected_lines(text, '#');
   printf("\n");
-  
+
   /* Write the main diagram. */
   write_diagram(movei, movej, color, marki, markj, NULL);
   printf("\n");
 
   /* Write the colon line. */
-  write_colon_line(move_type, text);
+  if (movei == movej && marki == markj && board_is_symmetric(marki, labels))
+    symmetry = '/';
+  write_colon_line(move_type, symmetry, text);
   printf("\n");
-  
+
   /* Write the constraint diagram if there are any labels, a
    * constraint line, or an action line.
    */
@@ -256,18 +277,11 @@ make_pattern(int movei, int movej, int c
     /* Write constraint and action lines. */
     write_selected_lines(text, ';');
     write_selected_lines(text, '>');
-    /* FIXME: Remove these antisuji autohelper lines once the joseki callback
-     *       handles antisuji moves itself.
-     */
-    if (move_type == ANTISUJI)
-      printf(">antisuji(*);\n");
     printf("\n");
   }
-  else if (move_type == ANTISUJI)
-    printf(">antisuji(*);\n\n");
 
   printf("\n");
-  
+
   /* Basic sanity checking. We do this at the end to simplify debugging. */
   if (multiple_marks)
     fprintf(stderr, "Warning: Multiple square marks in pattern %s%d\n",
@@ -301,7 +315,7 @@ analyze_node(SGFNode *node, const char *
 
   /* Clear the labels array. */
   memset(labels, 0, MAX_BOARD * MAX_BOARD);
-  
+
   /* Check the node properties for a move, a square mark, labels, and
    * a comment.
    */
@@ -316,13 +330,13 @@ analyze_node(SGFNode *node, const char *
        markj = boardsize - 1 - markj;
       }
       break;
-      
+
     case SGFW: /* White move */
       color = WHITE;
       get_moveXY(prop, &movei, &movej, boardsize);
       movej = boardsize - 1 - movej;
       break;
-      
+
     case SGFB: /* Black move */
       color = BLACK;
       get_moveXY(prop, &movei, &movej, boardsize);
@@ -363,6 +377,7 @@ analyze_node(SGFNode *node, const char *
   if (node->next)
     analyze_node(node->next, prefix);
 }
+
 
 int
 main(int argc, char *argv[])
Index: patterns/mkpat.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/mkpat.c,v
retrieving revision 1.111
diff -u -p -r1.111 mkpat.c
--- patterns/mkpat.c    14 Jan 2003 20:50:34 -0000      1.111
+++ patterns/mkpat.c    23 Jan 2003 21:44:13 -0000
@@ -850,7 +850,7 @@ read_constraint_diagram_line(char *p)
   /* Skip west boundary. */
   if (*p == '|')
     p++;
-  
+
   for (j = 0; 
        strchr(VALID_PATTERN_CHARS, *p) || strchr(VALID_CONSTRAINT_LABELS, *p);
        ++j, ++p) {
@@ -906,7 +906,6 @@ check_constraint_diagram_size(void)
 static void
 finish_pattern(char *line)
 {
-
   /* end of pattern layout */
   char symmetry;               /* the symmetry character */
   
@@ -996,7 +995,7 @@ finish_pattern(char *line)
     class[0] = 0;  /* in case sscanf doesn't get that far */
     s = sscanf(p, ":%c,%[^,]%n", &symmetry, class, &n);
     p += n;
-    
+
     if (s < 2) {
       fprintf(stderr, ": line must contain symmetry character and class\n");
       fatal_errors++;
@@ -1006,23 +1005,29 @@ finish_pattern(char *line)
       p += n;
 
       if (sscanf(entry, "%*[^(](%f)", &v) > 0) {
+       const char *corner_unsupported = NULL;
+
        if (strncmp(entry, "value", 5) == 0
            || strncmp(entry, "minvalue", 8) == 0) {
          pattern[patno].value = v;
          pattern[patno].class |= VALUE_MINVAL;
+         corner_unsupported = "value";
        }
        else if (strncmp(entry, "maxvalue", 8) == 0) {
          pattern[patno].maxvalue = v;
          pattern[patno].class |= VALUE_MAXVAL;
+         corner_unsupported = "maxvalue";
        }
        else if (strncmp(entry, "terri", 5) == 0
                 || strncmp(entry, "minterri", 8) == 0) {
          pattern[patno].minterritory = v;
          pattern[patno].class |= VALUE_MINTERRITORY;
+         corner_unsupported = "terri";
        }
        else if (strncmp(entry, "maxterri", 8) == 0) {
          pattern[patno].maxterritory = v;
          pattern[patno].class |= VALUE_MAXTERRITORY;
+         corner_unsupported = "maxterri";
        }
        else if (strncmp(entry, "shape", 5) == 0) {
          pattern[patno].shape = v;
@@ -1031,24 +1036,31 @@ finish_pattern(char *line)
        else if (strncmp(entry, "followup", 8) == 0) {
          pattern[patno].followup = v;
          pattern[patno].class |= VALUE_FOLLOWUP;
+         corner_unsupported = "followup";
        }
        else if (strncmp(entry, "reverse_followup", 16) == 0) {
          pattern[patno].reverse_followup = v;
          pattern[patno].class |= VALUE_REV_FOLLOWUP;
+         corner_unsupported = "reverse_followup";
        }
        else {
-         fprintf(stderr, "%s(%d) : error : Unknown value field: %s\n", 
+         fprintf(stderr, "%s(%d) : error : Unknown value field: %s\n",
                   current_file, current_line_number, entry);
           fatal_errors++;
          break;
        }
+
+       if (database_type == DB_CORNER && corner_unsupported) {
+         fprintf(stderr, "%s(%d) : warning : `%s' is unsupported in corner 
databases\n",
+                 current_file, current_line_number, corner_unsupported);
+       }
       }
       else {
        strncpy(helper_fn_names[patno], entry, 79);
        break;
       }
     }
-      
+
     {
       char *p;
       for (p = class; *p; p++) {
@@ -1104,15 +1116,15 @@ finish_pattern(char *line)
   case '+' :
     if (where & (NORTH_EDGE|EAST_EDGE|SOUTH_EDGE|WEST_EDGE))
       fprintf(stderr,
-             "%s(%d) : Warning : symmetry inconsistent with edge constraints 
(pattern %s)\n", 
+             "%s(%d) : Warning : symmetry inconsistent with edge constraints 
(pattern %s)\n",
              current_file, current_line_number, pattern_names[patno]);
     pattern[patno].trfno = 2;
     break;
 
-  case 'X' : 
+  case 'X' :
     if (where & (NORTH_EDGE|EAST_EDGE|SOUTH_EDGE|WEST_EDGE))
       fprintf(stderr,
-             "%s(%d) : Warning : X symmetry inconsistent with edge constraints 
(pattern %s)\n", 
+             "%s(%d) : Warning : X symmetry inconsistent with edge constraints 
(pattern %s)\n",
              current_file, current_line_number, pattern_names[patno]);
     if (maxi != maxj)
       fprintf(stderr,
@@ -1124,15 +1136,15 @@ finish_pattern(char *line)
   case '-' :
     if (where & (NORTH_EDGE|SOUTH_EDGE))
       fprintf(stderr,
-             "%s(%d) : Warning : symmetry inconsistent with edge constraints 
(pattern %s)\n", 
+             "%s(%d) : Warning : symmetry inconsistent with edge constraints 
(pattern %s)\n",
              current_file, current_line_number, pattern_names[patno]);
     pattern[patno].trfno = 4;
     break;
-    
+
   case '|' :
     if (where & (EAST_EDGE|WEST_EDGE))
       fprintf(stderr,
-             "%s(%d) : Warning : symmetry inconsistent with edge constraints 
(pattern %s)\n", 
+             "%s(%d) : Warning : symmetry inconsistent with edge constraints 
(pattern %s)\n",
              current_file, current_line_number, pattern_names[patno]);
     pattern[patno].trfno = 4;
     break;
@@ -1144,7 +1156,7 @@ finish_pattern(char *line)
     */
     if (maxi != maxj)
       fprintf(stderr,
-             "%s(%d) : Warning : \\ or / symmetry requires a square pattern 
(pattern %s)\n", 
+             "%s(%d) : Warning : \\ or / symmetry requires a square pattern 
(pattern %s)\n",
              current_file, current_line_number, pattern_names[patno]);
 
     pattern[patno].trfno = 4;
@@ -1153,23 +1165,22 @@ finish_pattern(char *line)
   case 'O' :
     if (where & (NORTH_EDGE|EAST_EDGE|SOUTH_EDGE|WEST_EDGE))
       fprintf(stderr,
-             "%s(%d) : Warning : symmetry inconsistent with edge constraints 
(pattern %s)\n", 
+             "%s(%d) : Warning : symmetry inconsistent with edge constraints 
(pattern %s)\n",
              current_file, current_line_number, pattern_names[patno]);
     pattern[patno].trfno = 5;  /* Ugly special convention. */
     break;
 
   default:
     fprintf(stderr,
-           "%s(%d) : Warning : symmetry character '%c' not implemented - using 
'8' (pattern %s)\n", 
+           "%s(%d) : Warning : symmetry character '%c' not implemented - using 
'8' (pattern %s)\n",
            current_file, current_line_number, symmetry, pattern_names[patno]);
     /* FALLTHROUGH */
   case '8' :
     pattern[patno].trfno = 8;
     break;
   }
-
 }
-      
+
 
 static void
 read_constraint_line(char *line)
@@ -2523,13 +2534,14 @@ write_patterns(FILE *outfile)
     }
 
     if (database_type == DB_CORNER) {
-      fprintf(outfile, "  {%d,0x%x,\"%s\",%f,%d,", second_corner_offset[j],
-             p->class, pattern_names[j], p->value, p->autohelper_flag);
+      fprintf(outfile, "  {%d,%d,0x%x,\"%s\",%f,%d,",
+             second_corner_offset[j], (p->trfno == 4),
+             p->class, pattern_names[j], p->shape,
+             p->autohelper_flag);
       if (p->autohelper)
-       fprintf(outfile, "autohelper%s%d", prefix, j);
+       fprintf(outfile, "autohelper%s%d}", prefix, j);
       else
-       fprintf(outfile, "NULL");
-      fprintf(outfile, ",%f}", p->constraint_cost);
+       fprintf(outfile, "NULL}");
 
       if (j != patno - 1)
        fprintf(outfile, ",\n");
@@ -2545,7 +2557,7 @@ write_patterns(FILE *outfile)
      * the pattern, relative to the pattern origin. These just transform same
      * as the elements.
      */
-    
+
     fprintf(outfile, "  {%s%d,%d,%d, \"%s\",%d,%d,%d,%d,%d,%d,0x%x,%d",
            prefix, j,
            p->patlen,
Index: patterns/patterns.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/patterns.h,v
retrieving revision 1.49
diff -u -p -r1.49 patterns.h
--- patterns/patterns.h 12 Jan 2003 15:26:54 -0000      1.49
+++ patterns/patterns.h 23 Jan 2003 21:44:24 -0000
@@ -322,7 +322,7 @@ void init_tree_oracle(void);
 
 /* pattern arrays themselves */
 extern struct pattern_db pat_db;
-extern struct pattern_db joseki_db;
+extern struct corner_db  joseki_db;
 extern struct pattern_db aa_attackpat_db;
 extern struct pattern_db owl_attackpat_db;
 extern struct pattern_db owl_vital_apat_db;
@@ -400,17 +400,18 @@ struct corner_variation {
 
 struct corner_pattern {
   int second_corner_offset;
+  int symmetric;
 
   unsigned int class;
   const char *name;
 
-  float value;
+  float shape;
 
   int autohelper_flag;
   autohelper_fn_ptr autohelper;
-  float constraint_cost;
 };
 
+/* Build time version of corner_variation structure. */
 struct corner_variation_b {
   int move_offset;
   char xor_att;





reply via email to

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