gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] optics: minor bugfix and minor improvements


From: Paul Pogonyshev
Subject: [gnugo-devel] optics: minor bugfix and minor improvements
Date: Fri, 29 Nov 2002 01:12:13 +0200

here is a nasty bug (optics.c):

/* This macro is not fully generalized. It works because it is used only where
 * c, d match the first vital attack/defend point of the the half eye or none
 * at all.
 */
#define hadj(heye, apos, bpos) \
     (heye[apos].type == HALF_EYE \
>>>   && (heye[apos].attack_point[0] == (bpos) \
>>>       || (heye[apos].defense_point[0] == (bpos))))

this can eventually match a wrong half eye (if i.e. two neighboring half eyes 
have a common attack point). i had very hard time trying to figure out why 
the number of calls to most functions changed between patched and non-patched 
version. finally, when i had tried almost everything else (and found a typo 
in the patch ;) i discovered the thing shown above. i did check that it was 
really the cause: placed the very same logic in my patch and it started 
giving exactly the same results as non-patched version (in terms of function 
calls). who said gprof couldn't be used as a debugger ;) ?

actually, the bugfix hasn't caused any regression changes, but it has some 
influence on the engine (some variations must go another way since number of 
calls to functions has changed).


- eye_vertex and eye_graph structures reorganized
- mkeyes.c rewritten to conform the changes in eyes.h
- adjacent() and buggy hadj() macros in optics.c retired
- recognize_eye(), first_map() and next_map() simplified and sped up
- new static reset_map() in optics.c

all the stuff above brings the following:

* one bug tracked down in optics.c, the code looks somewhat cleaner to me now

* around 60k decrease in executable size

* slight performance improvement (i just couldn't stop ^^ and made changes to 
  first_map() and next_map() though they take _very_ little of total runtime):

        BEFORE
  ...
  0.49    588.64     3.28   185678     0.02     0.03  recognize_eye
  ...
  0.08    655.90     0.57  8115520     0.00     0.00  next_map
  ...
  0.03    664.34     0.17  2495304     0.00     0.00  first_map
  ...
-----------------------------------------------
                3.28    2.89  185678/185678      read_eye [146]
[149]    0.9    3.28    2.89  185678         recognize_eye [149]
                0.00    2.10   34338/667409      safe_move [64]
                0.57    0.00 8115520/8115520     next_map [272]
                0.17    0.00 2495304/2495304     first_map [336]
                0.04    0.00  581137/1560651     is_halfeye [378]
                0.01    0.00  151729/332905      eye_move_urgency [478]
  ...

        AFTER
  ...
  0.38    600.17     2.52   185760     0.01     0.03  recognize_eye
  ...
  0.07    652.44     0.48  8136365     0.00     0.00  next_map
  ...
  0.01    663.61     0.06  2342556     0.00     0.00  first_map
  ...
  0.00    665.18     0.03   732837     0.00     0.00  reset_map
  ...
-----------------------------------------------
                2.52    2.67  185760/185760      read_eye [149]
[152]    0.8    2.52    2.67  185760         recognize_eye [152]
                0.00    2.06   34362/667663      safe_move [64]
                0.48    0.00 8136365/8136365     next_map [283]
                0.06    0.00 2342556/2342556     first_map [411]
                0.03    0.00  732837/732837      reset_map [477]
                0.02    0.00  581604/1562113     is_halfeye [412]
                0.02    0.00  151763/333022      eye_move_urgency [446]

Paul


Index: patterns/eyes.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/eyes.h,v
retrieving revision 1.7
diff -u -p -r1.7 eyes.h
--- patterns/eyes.h     16 Sep 2002 07:27:49 -0000      1.7
+++ patterns/eyes.h     28 Nov 2002 22:06:21 -0000
@@ -21,25 +21,27 @@
 
 #include "liberty.h"
 
+
+#define CAN_BE_EMPTY           1
+#define CAN_CONTAIN_STONE      2
+#define EYE_DEFENSE_POINT      4
+#define EYE_ATTACK_POINT       8
+
 /*
- * The vertices of each eye is defined by an array of struct eye_vertex.
+ * The vertices of each eye are defined by an array of struct eye_vertex.
  */
 
 struct eye_vertex {
-  int i;                          /* coordinates of the vertex             */
-  int j; 
-  char type;                      /* . x or X                              */
-
-  int neighbors;                  /* number of neighbors                   */
-  int n1;                         /* first neighbor (position in array)    */
-  int n2;                         /* second neighbor                       */
-  int n3;                         /* third neighbor                        */
-  int n4;                         /* fourth neighbor                       */
-  int edge;                       /* 0=center, 1=edge, 2=corner            */
+  char marginal;                 /* 1 if marginal vertex, 0 otherwise    */
+  char edge;                     /* 0 = center, 1 = edge, 2 = corner      */
   /* A corner vertex may only be matched at the corner.
    * An edge vertex may be matched at the corner or on the edge.
    * A center vertex may be matched anywhere.
    */
+  char flags;                    /* see the #defines above                */
+
+  char neighbors;                /* number of neighbors                   */
+  int n[4];                      /* position in array of vertex neighors */
 };
 
 
@@ -50,7 +52,7 @@ struct eye_vertex {
 
 struct eye_graph {
   struct eye_vertex *vertex;
-  const char *patname;            /* Name of pattern                       */
+  int patnum;                    /* Number of pattern                      */
   int esize;                      /* number of vertices                    */
   int msize;                      /* number of marginal vertices           */
   int ends;                       /* number of vertices with one neighbor  */
Index: patterns/mkeyes.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/patterns/mkeyes.c,v
retrieving revision 1.10
diff -u -p -r1.10 mkeyes.c
--- patterns/mkeyes.c   16 Sep 2002 07:27:49 -0000      1.10
+++ patterns/mkeyes.c   28 Nov 2002 22:06:25 -0000
@@ -36,6 +36,8 @@
 #include <ctype.h>
 #include <assert.h>
 
+#include "eyes.h"
+
 
 #define DEBUG(x)  /* printf x */
 
@@ -49,10 +51,11 @@ main(void)
   int patno = 0;
   int p;
   char vertex[MAXDIMEN][MAXDIMEN];
-  int marginal[MAXDIMEN][MAXDIMEN];
-  int edge[MAXDIMEN][MAXDIMEN];
+  char marginal[MAXDIMEN][MAXDIMEN];
+  char edge[MAXDIMEN][MAXDIMEN];
+  char flags[MAXDIMEN][MAXDIMEN];
   int neighbors[MAXSIZE];
-  int i, k, l, h;
+  int k, l, h;
   int m = 0, n = 0;
   int vi[MAXSIZE];
   int vj[MAXSIZE];
@@ -70,13 +73,11 @@ main(void)
   int num_defenses = 0;
   int debug = 0;
   
-  printf("\
-/* This file is automatically generated by mkeyes. Do not\n\
- * edit it directly. Instead, edit the eye shape database.\n\
- */\n\n\
-\
-#include <stdio.h> /* for NULL */\n\
-#include \"eyes.h\"\n\n");
+  printf("/* This file is automatically generated by mkeyes. Do not\n");
+  printf(" * edit it directly. Instead, edit the eye shape database.\n");
+  printf(" */\n\n");
+  printf("#include <stdio.h> /* for NULL */\n");
+  printf("#include \"eyes.h\"\n\n");
 
   memset(ends, 0, sizeof(ends));
   memset(two_neighbors, 0, sizeof(two_neighbors));
@@ -84,18 +85,17 @@ main(void)
   memset(esize, 0, sizeof(esize));
 
   while (fgets(line, MAXLINE, stdin) && !fatal_errors) {
+    int last = strlen(line) - 1;
 
-    if (line[strlen(line)-1] != '\n') {
+    if (line[last] != '\n') {
       fprintf(stderr, "mkeyes: line truncated: %s\n", line);
       return 1;
     }
 
     /* remove trailing whitespace */
-    i = strlen(line)-2;        /* start removing backwards just before newline 
*/
-    while (i >= 0 && (line[i] == ' ' || line[i] == '\t' || line[i] == '\r')) 
{
-      line[i]   = '\n';
-      line[i+1] = '\0';
-      i--;
+    for (last--; last >= 0 && isspace(line[last]); last--) {
+      line[last]   = '\n';
+      line[last+1] = '\0';
     }
 
     /* New pattern. */
@@ -108,9 +108,12 @@ main(void)
       }
       if (debug)
        fprintf(stderr, "parsing pattern %d\n", eye_number[patno]);
+      
       memset(vertex, 0, sizeof(vertex));
       memset(marginal, 0, sizeof(marginal));
       memset(edge, 0, sizeof(edge));
+      memset(flags, 0, sizeof(flags));
+      
       m = 0;
       esize[patno] = 0;
       msize[patno] = 0;
@@ -158,16 +161,19 @@ main(void)
        {
          case '.':
            marginal[m][n] = 0;
+           flags[m][n] = CAN_BE_EMPTY;
            break;
            
          case '!':
            msize[patno]++;
            marginal[m][n] = 1;
+           flags[m][n] = CAN_BE_EMPTY;
            break;
            
          case '@':
            msize[patno]++;
            marginal[m][n] = 1;
+           flags[m][n] = CAN_BE_EMPTY | EYE_DEFENSE_POINT | EYE_ATTACK_POINT;
            num_attacks++;
            num_defenses++;
            break;
@@ -175,42 +181,50 @@ main(void)
          case '$':
            msize[patno]++;
            marginal[m][n] = 1;
+           flags[m][n] = CAN_CONTAIN_STONE;
            break;
            
          case '(':
            msize[patno]++;
            marginal[m][n] = 1;
+           flags[m][n] = CAN_BE_EMPTY | EYE_ATTACK_POINT;
            num_attacks++;
            break;
            
          case ')':
            msize[patno]++;
            marginal[m][n] = 1;
+           flags[m][n] = CAN_BE_EMPTY | EYE_DEFENSE_POINT;
            num_defenses++;
            break;
            
          case 'x':
            marginal[m][n] = 0;
+           flags[m][n] = CAN_BE_EMPTY | CAN_CONTAIN_STONE;
            break;
            
          case '*':
            marginal[m][n] = 0;
+           flags[m][n] = CAN_BE_EMPTY | EYE_ATTACK_POINT | EYE_DEFENSE_POINT;
            num_attacks++;
            num_defenses++;
            break;
            
          case '<':
            marginal[m][n] = 0;
+           flags[m][n] = CAN_BE_EMPTY | EYE_ATTACK_POINT;
            num_attacks++;
            break;
 
          case '>':
            marginal[m][n] = 0;
+           flags[m][n] = CAN_BE_EMPTY | EYE_DEFENSE_POINT;
            num_defenses++;
            break;
            
          case 'X':
            marginal[m][n] = 0;
+           flags[m][n] = CAN_CONTAIN_STONE;
            break;
            
          default:
@@ -253,13 +267,15 @@ main(void)
       }
       
       printf("static struct eye_vertex eye%d[] = {\n", eye_number[patno]);
+      
       for (l = 0; l < esize[patno]; l++) {
-       
        int ni[4];
        int nj[4];
        int nb[4];
        int mx[MAXDIMEN][MAXDIMEN];
        int count = 0;
+       int i = vi[l];
+       int j = vj[l];
        
        memset(mx, -1, sizeof(mx));
        
@@ -271,36 +287,36 @@ main(void)
          nb[h] = -1;
        }
        
-       mx[vi[l]][vj[l]] = 0;
+       mx[i][j] = 0;
        
-       if (vi[l] > 0 && vertex[vi[l]-1][vj[l]]) {
-         ni[neighbors[l]] = vi[l]-1;
-         nj[neighbors[l]] = vj[l];
+       if (i > 0 && vertex[i-1][j]) {
+         ni[neighbors[l]] = i-1;
+         nj[neighbors[l]] = j;
          neighbors[l]++;
          count++;
-         mx[vi[l]-1][vj[l]] = l;
+         mx[i-1][j] = l;
        }
        
-       if (vi[l] < MAXDIMEN-1 && vertex[vi[l]+1][vj[l]]) {
-         ni[neighbors[l]] = vi[l]+1;
-         nj[neighbors[l]] = vj[l];
+       if (i < MAXDIMEN-1 && vertex[i+1][j]) {
+         ni[neighbors[l]] = i+1;
+         nj[neighbors[l]] = j;
          neighbors[l]++;
          count++;
-         mx[vi[l]+1][vj[l]] = l;
+         mx[i+1][j] = l;
        }
        
-       if (vj[l] > 0 && vertex[vi[l]][vj[l]-1]) {
-         ni[neighbors[l]] = vi[l];
-         nj[neighbors[l]] = vj[l]-1;
+       if (j > 0 && vertex[i][j-1]) {
+         ni[neighbors[l]] = i;
+         nj[neighbors[l]] = j-1;
          neighbors[l]++;
-         mx[vi[l]][vj[l]-1] = l;
+         mx[i][j-1] = l;
        }
        
-       if (vi[l] < MAXDIMEN-1 && vertex[vi[l]][vj[l]+1]) {
-         ni[neighbors[l]] = vi[l];
-         nj[neighbors[l]] = vj[l]+1;
+       if (j < MAXDIMEN-1 && vertex[i][j+1]) {
+         ni[neighbors[l]] = i;
+         nj[neighbors[l]] = j+1;
          neighbors[l]++;
-         mx[vi[l]][vj[l]+1] = l;
+         mx[i][j+1] = l;
        }
        
        
@@ -319,10 +335,9 @@ main(void)
        }
        
        
-       printf("   {%d, %d, \'%c\', %d, %d, %d, %d, %d, %d}",
-              vi[l], vj[l], vertex[vi[l]][vj[l]], 
-              neighbors[l], nb[0], nb[1], nb[2], nb[3],
-              edge[vi[l]][vj[l]]);
+       printf("  {%d, %d, %2d, %d, {%2d, %2d, %2d, %2d}}",
+              marginal[i][j], edge[i][j], flags[i][j],
+              neighbors[l], nb[0], nb[1], nb[2], nb[3]);
        
        if (l < esize[patno]-1)
          printf(",\n");
@@ -343,14 +358,14 @@ main(void)
   printf("\nstruct eye_graph graphs[] = {\n");
   for (l = 0; l < patno; l++) {
 
-    printf("   {eye%d, \"%d\", %d, %d, %d, %d, %d, {%d, %d, %d, %d}}",
+    printf("  {eye%d, %d, %d, %d, %d, %d, %d, {%d, %d, %d, %d}}",
           eye_number[l], eye_number[l], esize[l], msize[l], ends[l],
           two_neighbors[l], three_neighbors[l],
           value_a[l], value_b[l], value_c[l], value_d[l]);
     if (l < patno-1)
       printf(",\n");
     else
-      printf(",\n{NULL, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}}\n};\n");
+      printf(",\n  {NULL, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}}\n};\n");
   }
 
   if (fatal_errors) {
Index: engine/optics.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/optics.c,v
retrieving revision 1.60
diff -u -p -r1.60 optics.c
--- engine/optics.c     15 Nov 2002 15:12:45 -0000      1.60
+++ engine/optics.c     28 Nov 2002 22:06:54 -0000
@@ -29,28 +29,6 @@
 #include "gg_utils.h"
 
 
-/* This macro is not fully generalized. It works because it is used only 
where
- * c, d match the first vital attack/defend point of the the half eye or none
- * at all.
- */
-#define hadj(heye, apos, bpos) \
-     (heye[apos].type == HALF_EYE \
-      && (heye[apos].attack_point[0] == (bpos) \
-          || (heye[apos].defense_point[0] == (bpos))))
-
-/*
- * Two eye points are defined to be adjacent if they are either
- * next to each other or if one vertex is a half eye and the
- * other one is the point making it a real eye.
- */
-
-#define adjacent(heye, apos, bpos) (   (apos) == SOUTH(bpos) \
-                                   || (apos) == WEST(bpos) \
-                                   || (apos) == NORTH(bpos) \
-                                   || (apos) == EAST(bpos) \
-                                   || hadj(heye, apos, bpos) \
-                                   || hadj(heye, bpos, apos))
-
 #define MAXEYE 20
 
 
@@ -64,6 +42,7 @@ struct vital_points {
   int num_defenses;
 };
 
+
 static void
 compute_primary_domains(int color, int domain[BOARDMAX],
                        int lively[BOARDMAX],
@@ -84,12 +63,13 @@ static int recognize_eye(int pos, int *a
                         struct eyevalue *value,
                         struct eye_data eye[BOARDMAX],
                         struct half_eye_data heye[BOARDMAX],
-                        int color, struct vital_points *vp);
+                        struct vital_points *vp);
 static void guess_eye_space(int pos, int effective_eyesize, int margins,
                            struct eye_data eye[BOARDMAX],
                            struct eyevalue *value, char *pessimistic_min);
-static void first_map(int q, int map[MAXEYE]);
-static int next_map(int *q, int map[MAXEYE], int esize);
+static void reset_map(int size);
+static void first_map(int* map_value);
+static int next_map(int *q, int map[MAXEYE]);
 static void print_eye(struct eye_data eye[BOARDMAX],
                      struct half_eye_data heye[BOARDMAX], int pos);
 static float 
@@ -102,6 +82,10 @@ evaluate_diagonal_intersection(int m, in
 static int black_domain[BOARDMAX];
 static int white_domain[BOARDMAX];
 
+/* Used internally by mapping functions. */
+static int map_size;
+static char used_index[MAXEYE];
+
 
 /*
  * Clear a struct eye_data.
@@ -1045,7 +1029,7 @@ read_eye(int pos, int *attack_point, int
   struct vital_points *best_vp = &vp;
   
   eye_color = recognize_eye(pos, attack_point, defense_point, value,
-                            eye, heye, color, &vp);
+                            eye, heye, &vp);
   if (!eye_color)
     return 0;
 
@@ -1065,7 +1049,7 @@ read_eye(int pos, int *attack_point, int
 
     heye[ko_halfeye].type = 0;
     result = recognize_eye(pos, &apos, &dpos, &ko_value, eye,
-                          heye, color, &ko_vp);
+                          heye, &ko_vp);
     heye[ko_halfeye].type = HALF_EYE;
 
     if (result && max_eyes(value) < max_eyes(&ko_value)) {
@@ -1107,20 +1091,16 @@ recognize_eye(int pos, int *attack_point
              struct eyevalue *value,
              struct eye_data eye[BOARDMAX], 
              struct half_eye_data heye[BOARDMAX], 
-             int color, struct vital_points *vp)
+             struct vital_points *vp)
 {
   int m, n;
-  int k;
+  int eye_color;
   int eye_size = 0;
-  int vpos[MAXEYE], marginal[MAXEYE], neighbors[MAXEYE];
-  int edge[MAXEYE];
+  int num_marginals = 0;
+  int vpos[MAXEYE];
+  char marginal[MAXEYE], edge[MAXEYE], neighbors[MAXEYE];
   int graph;
-  int q;
   int map[MAXEYE];
-  int ok, contin;
-  int eye_color;
-  int kpos;
-  int num_marginals = 0;
 
   gg_assert(attack_point != NULL);
   gg_assert(defense_point != NULL);
@@ -1132,7 +1112,6 @@ recognize_eye(int pos, int *attack_point
   if (eye_color == WHITE_BORDER)
     eye_color = WHITE;
 
-
   if (eye[pos].esize-eye[pos].msize > 7)
     return 0;
 
@@ -1163,26 +1142,22 @@ recognize_eye(int pos, int *attack_point
        if (n == 0 || n == board_size-1)
          edge[eye_size]++;
        
-       eye_size++;
        if (is_halfeye(heye, pos2)) {
-
-         /* Use one of the diagonals as a marginal for mapping purposes.
-          * The whole set of diagonals is isomorphic to a marginal.
-          * Note that the half eye preceedes the diagonal in the list.
+         neighbors[eye_size]++;      /* Increase neighbors of half eye. */
+         eye_size++;
+         /* Use a virtual marginal vertex for mapping purposes. We set it
+          * to be at NO_MOVE so it won't be accidentially count as a
+          * neighbor for another vertex. Note that the half eye preceedes
+          * the virtual marginal vertex in the list.
           */
-         neighbors[eye_size-1]++;       /* increase neighbors of half eye */
-         if (eye_color == color)
-           kpos = heye[pos2].defense_point[0];
-         else
-           kpos = heye[pos2].attack_point[0];
-         ASSERT_ON_BOARD1(kpos);
-         vpos[eye_size] = kpos;
+         vpos[eye_size] = NO_MOVE;
          marginal[eye_size] = 1;
-         edge[eye_size] = 0;
          num_marginals++;
+         edge[eye_size] = 0;
          neighbors[eye_size] = 1;
-         eye_size++;
        }
+
+       eye_size++;
       }
     }
 
@@ -1192,86 +1167,70 @@ recognize_eye(int pos, int *attack_point
    */
 
   for (graph = 0; graphs[graph].vertex != NULL; graph++) {
+    int q;
+
     if (graphs[graph].esize != eye_size
        || graphs[graph].msize != num_marginals)
       continue;
 
-
+    reset_map(eye_size);
     q = 0;
-    first_map(q, map);
+    first_map(&map[0]);
 
-    contin = 1;
-    while (contin && q >= 0 && q < eye_size) {
-      ok = 1;
+    while (1) {
+      struct eye_vertex *gv = &graphs[graph].vertex[q];
+      int mv = map[q];
+      int ok = 1;
 
       if (0)
        TRACE("q=%d: %d %d %d %d %d %d\n", 
              q, map[0], map[1], map[2], map[3], map[4], map[5]);
 
-      if (neighbors[map[q]] != graphs[graph].vertex[q].neighbors)
+      if (neighbors[mv] != gv->neighbors
+         || marginal[mv] != gv->marginal
+         || edge[mv] < gv->edge)
        ok = 0;
 
-      if (ok && marginal[map[q]]
-         && graphs[graph].vertex[q].type != '!'
-         && graphs[graph].vertex[q].type != '@'
-         && graphs[graph].vertex[q].type != '$'
-         && graphs[graph].vertex[q].type != ')'
-         && graphs[graph].vertex[q].type != '(')
-       ok = 0;
-      
-      if (ok && !marginal[map[q]]
-         && (graphs[graph].vertex[q].type == '!'
-             || graphs[graph].vertex[q].type == '('
-             || graphs[graph].vertex[q].type == ')'
-             || graphs[graph].vertex[q].type == '@'
-             || graphs[graph].vertex[q].type == '$'))
-       ok = 0;
-      
-      if (ok && IS_STONE(board[vpos[map[q]]])
-         && graphs[graph].vertex[q].type != 'X'
-         && graphs[graph].vertex[q].type != 'x'
-         && graphs[graph].vertex[q].type != '$')
-       ok = 0;
-      
-      if (ok && board[vpos[map[q]]] == EMPTY
-         && (graphs[graph].vertex[q].type == 'X'
-             || graphs[graph].vertex[q].type == '$'))
-       ok = 0;
-
-      if (ok && edge[map[q]] < graphs[graph].vertex[q].edge)
-       ok = 0;
-      
-      if (ok && graphs[graph].vertex[q].n1 < q
-         && graphs[graph].vertex[q].n1 != -1)
-       {
-         if (!adjacent(heye, vpos[map[q]], 
-                       vpos[map[graphs[graph].vertex[q].n1]]))
-           ok = 0;
-       }
-      if (ok && graphs[graph].vertex[q].n2 < q
-         && graphs[graph].vertex[q].n2 != -1)
-       {
-         if (!adjacent(heye, vpos[map[q]], 
-                       vpos[map[graphs[graph].vertex[q].n2]]))
-           ok = 0;
-       }
-      if (ok && graphs[graph].vertex[q].n3 < q
-         && graphs[graph].vertex[q].n3 != -1)
-       {
-         if (!adjacent(heye, vpos[map[q]],
-                       vpos[map[graphs[graph].vertex[q].n3]]))
+      if (ok) {
+        if (IS_STONE(board[vpos[mv]])) {
+         if (!(gv->flags & CAN_CONTAIN_STONE))
            ok = 0;
        }
-      if (ok && graphs[graph].vertex[q].n4 < q
-         && graphs[graph].vertex[q].n4 != -1)
-       {
-         if (!adjacent(heye, vpos[map[q]],
-                       vpos[map[graphs[graph].vertex[q].n4]]))
-           ok = 0;
+       /* Virtual half eye marginals also fall here since they are off
+        * board.
+        */
+       else if (!(gv->flags & CAN_BE_EMPTY))
+         ok = 0;
+      }
+
+      if (ok) {
+       int k;
+
+       for (k = 0; k < gv->neighbors; k++) {
+         if (gv->n[k] < q) {
+           int mn = map[gv->n[k]];
+
+           /* Two eye vertices are neighbours if they are adjacent on the
+            * board or one of them is a half eye and the other is its
+            * virtual marginal vertex (and follows it in vpos[] array).
+            */
+           if (vpos[mv] != SOUTH(vpos[mn])
+               && vpos[mv] != WEST(vpos[mn])
+               && vpos[mv] != NORTH(vpos[mn])
+               && vpos[mv] != EAST(vpos[mn])
+               && (mv != mn - 1 || heye[vpos[mv]].type != HALF_EYE)
+               && (mn != mv - 1 || heye[vpos[mn]].type != HALF_EYE)) {
+             ok = 0;
+             break;
+           }
+         }
        }
+      }
 
       if (!ok) {
-       contin = next_map(&q, map, eye_size);
+       if (!next_map(&q, map))
+         break;
+
        if (0)
          gprintf("  q=%d, esize=%d: %d %d %d %d %d\n",
                  q, eye_size, 
@@ -1279,55 +1238,54 @@ recognize_eye(int pos, int *attack_point
       }
       else {
        q++;
-       first_map(q, map);
+       if (q == eye_size)
+         break;                        /* A match! */
+       
+       first_map(&map[q]);
       }
     }
 
-    /* We have found a match! Now sort out the vital moves. */
     if (q == eye_size) {
+      /* We have found a match! Now sort out the vital moves. */
       *value = graphs[graph].value;
       vp->num_attacks = 0;
       vp->num_defenses = 0;
       
       if (eye_move_urgency(value) > 0) {
        /* Collect all attack and defense points in the pattern. */
-       for (k = 0; k < graphs[graph].esize; k++) {
-         if (graphs[graph].vertex[k].type == '*'
-             || graphs[graph].vertex[k].type == '<')
-           vp->attacks[vp->num_attacks++] = vpos[map[k]];
-         else if (graphs[graph].vertex[k].type == '@'
-                  || graphs[graph].vertex[k].type == '(') {
-           /* check for marginal matching half eye diagonal
-            * If it is a half eye diagonal, the half eye preceeds
-            * the diagonal in the list of vertices
+       int k;
+
+       for (k = 0; k < eye_size; k++) {
+         struct eye_vertex *ev = &graphs[graph].vertex[k];
+
+         if (ev->flags & EYE_ATTACK_POINT) {
+           /* Check for a marginal vertex matching a half eye virtual
+            * marginal. This is the case if a half eye preceeds the
+            * current vertex in the list.
             */
-           if (map[k] > 0 && is_halfeye(heye, vpos[map[k]-1])) {
+           if (ev->marginal && map[k] > 0
+               && is_halfeye(heye, vpos[map[k] - 1])) {
              /* Add all diagonals as vital. */
              int ix;
-             struct half_eye_data *this_half_eye = &heye[vpos[map[k]-1]];
+             struct half_eye_data *he = &heye[vpos[map[k] - 1]];
              
-             for (ix = 0; ix < this_half_eye->num_attacks; ix++)
-               vp->attacks[vp->num_attacks++] =
-                 this_half_eye->attack_point[ix];
+             for (ix = 0; ix < he->num_attacks; ix++)
+               vp->attacks[vp->num_attacks++] = he->attack_point[ix];
            }
            else
              vp->attacks[vp->num_attacks++] = vpos[map[k]];
          }
          
-         if (graphs[graph].vertex[k].type == '*'
-             || graphs[graph].vertex[k].type == '>')
-           vp->defenses[vp->num_defenses++] = vpos[map[k]];
-         else if (graphs[graph].vertex[k].type == '@'
-                  || graphs[graph].vertex[k].type == ')') {
-           /* Check for marginal matching half eye diagonal. */
-           if (map[k] > 0 && is_halfeye(heye, vpos[map[k]-1])) {
+         if (ev->flags & EYE_DEFENSE_POINT) {
+           /* Check for a half eye virtual marginal vertex. */
+           if (ev->marginal && map[k] > 0
+               && is_halfeye(heye, vpos[map[k] - 1])) {
              /* Add all diagonals as vital. */
              int ix;
-             struct half_eye_data *this_half_eye = &heye[vpos[map[k]-1]];
-
-             for (ix = 0; ix < this_half_eye->num_defends; ix++)
-               vp->defenses[vp->num_defenses++] 
-                 = this_half_eye->defense_point[ix];
+             struct half_eye_data *he = &heye[vpos[map[k] - 1]];
+             
+             for (ix = 0; ix < he->num_defends; ix++)
+               vp->defenses[vp->num_defenses++] = he->defense_point[ix];
            }
            else
              vp->defenses[vp->num_defenses++] = vpos[map[k]];
@@ -1350,10 +1308,10 @@ recognize_eye(int pos, int *attack_point
        
        DEBUG(DEBUG_EYES, "  vital points: %1m (attack) %1m (defense)\n",
              *attack_point, *defense_point);
-       DEBUG(DEBUG_EYES, "  pattern matched:  %s\n", graphs[graph].patname);
+       DEBUG(DEBUG_EYES, "  pattern matched:  %d\n", graphs[graph].patnum);
        
       }
-      TRACE("eye space at %1m of type %s\n", pos, graphs[graph].patname);
+      TRACE("eye space at %1m of type %d\n", pos, graphs[graph].patnum);
       
       return eye_color;
     }
@@ -1366,69 +1324,60 @@ recognize_eye(int pos, int *attack_point
 /* a MAP is a map of the integers 0,1,2, ... ,q into 
  * 0,1, ... , esize-1 where q < esize. This determines a 
  * bijection of the first q+1 elements of the graph into the 
- * eyespace. The function first_map finds the smallest valid
- * value of element q, assuming the previous elements are ok.
+ * eyespace. The following three functions work with maps.
  */
 
+/* Reset internal data structure used by first_map() and
+ * next_map() functions.
+ */
 static void
-first_map(int q, int map[MAXEYE])
+reset_map(int size)
 {
-  int k;
-  int r;
-  
-  for (k = 0; k <= q; k++) {
-    for (r = 0; r < q; r++)
-      if (map[r] == k)
-       break;
-
-    if (r == q) {
-      map[q] = k;
-      break;
-    }
-  }
-}     
+  map_size = size;
+  memset(used_index, 0, size * sizeof(char));
+}
 
 
-/* a MAP is a map of the integers 0,1,2, ... ,q into 
- * 0,1, ... , esize-1 where q < esize. This determines a 
- * bijection of the first q+1 elements of the graph into the 
- * eyespace. The function next_map produces the next map when
- * these are ordered lexicographically. If no next map can
- * be found, q is decremented, then we try again. If q==0
- * and no next map can be found, the function returns false.
+/* The function first_map finds the smallest valid
+ * value of a map element.
  */
-
-static int
-next_map(int *q, int map[MAXEYE], int esize)
+static void
+first_map(int* map_value)
 {
-  int mapok = 0;
-  int r;
+  int k = 0;
 
-  if (0)
-    gprintf("  q=%d, esize=%d: %d %d %d %d %d\n",
-           *q, esize, map[0], map[1], map[2], map[3], map[4]);
+  while (used_index[k])
+    k++;
 
-  if (*q == 0 && map[*q] == esize - 1)
-    return 0;
+  used_index[k] = 1;
+  *map_value = k;
+}     
 
-  map[*q]++;
-  while (!mapok) {
-    mapok = 1;
-    for (r = 0; r < *q; r++) {
-      if (map[r] == map[*q]) {
-       map[*q]++;
-       mapok = 0;
+
+/* The function next_map produces the next map in lexicographical
+ * order. If no next map can be found, q is decremented, then we
+ * try again. If the entire map is lexicographically last, the
+ * function returns false.
+ */
+static int
+next_map(int *q, int map[MAXEYE])
+{
+  int k;
+
+  do {
+    used_index[map[*q]] = 0;
+    for (k = map[*q]; ++k < map_size;) {
+      if (!used_index[k]) {
+       used_index[k] = 1;
+       map[*q] = k;
+       return 1;
       }
     }
-  }
 
-  if (map[*q] >= esize) {
-    map[*q] = 0;
     (*q)--;
-    return next_map(q, map, esize);
-  }
-  else
-    return 1;
+  } while (*q >= 0);
+  
+  return 0;
 }     
 
 




reply via email to

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