gnugo-devel
[Top][All Lists]
Advanced

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

[gnugo-devel] hash_1_28.4: revision of hash_1_28.3


From: Arend Bayer
Subject: [gnugo-devel] hash_1_28.4: revision of hash_1_28.3
Date: Sat, 23 Mar 2002 23:30:28 +0100 (CET)


 - hashing dependent on compiler switches, default 64 bit and no full position
 - default cache size set to 8
 
So here is the revision of the hashing patches. Its tested rather extensively
(but not with full regressions).

The two compiler switches are NUM_HASHVALUES and FULL_POSITION_IN_HASH.
NUM_HASHVALUES can be set indirectly by specifying MIN_HASHBITS, which
is preferable to get more consistent behaviour between 32/64 bit machines.
(Just to check: Am I right asuming that "sizeof(long) == sizeof(unsigned long)"
on all systems?)

I first considered setting the minimum number of hash bits to 96. But I did
not get a single mistake/assertion failure when running "make second_batch"
with 32 bit hashing. So this suggests that we would get far less than one
mistake per game with 32 bit hashing (note that a hash collision does not
at all imply a wrong read result lookup yet: the routine, the string in
question and stackp have to agree as well). So with 64 bits, we should get
less than one mistake per 10^10 games (if we trust the random generator).

However, if we use 96 bits instead of 64, that costs only 5% of memory (I
have not measured the performance loss).

With 96 bits, I measured a 4.5% speed improvement for nngs.tst compared
to the old hashing. This was almost the same with 8MB instead of 16 MB
cache size (in fact, 8MB was minimally faster), so I suggest to reduce
the default to 8.
Dan, if you want to play safe and stick with the old hashing, change
HASHING_SCHEME to 1 in hash.h and ignore the cache size part.

To reduce the drawback of the probabilistic approach, I can promise to
make sure we have the random seed in crash reports before 3.2. This should
be useful in any case.

Arend


Index: configure
===================================================================
RCS file: /cvsroot/gnugo/gnugo/configure,v
retrieving revision 1.43
diff -u -r1.43 configure
--- configure   4 Mar 2002 06:49:07 -0000       1.43
+++ configure   23 Mar 2002 22:08:16 -0000
@@ -677,7 +677,7 @@
   --enable-grid-opt           enable the grid optimsation within the pattern 
matcher (default)
   --enable-grid-opt=distrust  enable the grid optimsation in non-trusting mode
   --disable-grid-opt          disable the grid optimisation
-  --enable-cache-size=n     reserve n Mb RAM for caching (16 default)
+  --enable-cache-size=n     reserve n Mb RAM for caching (8 default)
   --enable-level=n          n = default level (8 standard, up to 10 supported)
   --enable-semeai-variations=n          n = semeai variations (250 standard)
   --disable-dfa             use old non-dfa pattern matcher
@@ -1358,7 +1358,7 @@
 
 fi;
 
-default_cache_size=16
+default_cache_size=8
 default_level=10
 default_semeai_variations=250
 
Index: configure.in
===================================================================
RCS file: /cvsroot/gnugo/gnugo/configure.in,v
retrieving revision 1.41
diff -u -r1.41 configure.in
--- configure.in        1 Mar 2002 14:54:31 -0000       1.41
+++ configure.in        23 Mar 2002 22:08:18 -0000
@@ -43,7 +43,7 @@
   --enable-grid-opt=distrust  enable the grid optimsation in non-trusting mode
   --disable-grid-opt          disable the grid optimisation])
 
-default_cache_size=16
+default_cache_size=8
 default_level=10
 default_semeai_variations=250
 
Index: engine/board.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/board.c,v
retrieving revision 1.42
diff -u -r1.42 board.c
--- engine/board.c      22 Mar 2002 08:18:32 -0000      1.42
+++ engine/board.c      23 Mar 2002 22:08:32 -0000
@@ -496,25 +496,25 @@
     if (str == NO_MOVE) {
       if (!komaster_is_empty(komaster, kom_pos))
        gg_snprintf(buf, 100, "%s (variation %d, hash %lx, komaster %s:%s)", 
-                   message, count_variations, hashdata.hashval,
+                   message, count_variations, hashdata.hashval[0],
                    komaster_to_string(komaster, kom_pos),
                    location_to_string(kom_pos));
       else
        gg_snprintf(buf, 100, "%s (variation %d, hash %lx)", 
-                   message, count_variations, hashdata.hashval);
+                   message, count_variations, hashdata.hashval[0]);
     }
     else {
       if (!komaster_is_empty(komaster, kom_pos))
        gg_snprintf(buf, 100, 
                    "%s at %s (variation %d, hash %lx, komaster %s:%s)", 
                    message, location_to_string(str), count_variations,
-                   hashdata.hashval, 
+                   hashdata.hashval[0], 
                     komaster_to_string(komaster, kom_pos),
                    location_to_string(kom_pos));
       else
        gg_snprintf(buf, 100, "%s at %s (variation %d, hash %lx)", 
                    message, location_to_string(str), count_variations,
-                   hashdata.hashval);
+                   hashdata.hashval[0]);
     }
     sgftreeAddPlayLast(sgf_dumptree, NULL, color, I(pos), J(pos));
     sgftreeAddComment(sgf_dumptree, NULL, buf);
@@ -597,12 +597,12 @@
       message = "UNKNOWN";
     if (!komaster_is_empty(komaster, kom_pos))
       gg_snprintf(buf, 100, "tryko: %s (variation %d, %lx, komaster %s:%s)", 
-                 message, count_variations, hashdata.hashval,
+                 message, count_variations, hashdata.hashval[0],
                  komaster_to_string(komaster, kom_pos), 
                   location_to_string(kom_pos));
     else
       gg_snprintf(buf, 100, "tryko: %s (variation %d, %lx)", 
-                 message, count_variations, hashdata.hashval);
+                 message, count_variations, hashdata.hashval[0]);
     if (0) {
       /* tm - I don't find these pass moves helpful in the tree. */
       sgftreeAddPlayLast(sgf_dumptree, NULL, color, -1, -1);
@@ -715,8 +715,9 @@
   PUSH_VALUE(board_ko_pos);
   memcpy(&hashdata_stack[stackp], &hashdata, sizeof(hashdata));
 
-  board_ko_pos = 0;
-  hashdata_remove_ko(&hashdata);
+  if (board_ko_pos != NO_MOVE)
+    hashdata_invert_ko(&hashdata, board_ko_pos);
+  board_ko_pos = NO_MOVE;
   
   PUSH_VALUE(black_captured);
   PUSH_VALUE(white_captured);
@@ -817,7 +818,7 @@
   if (count_variations)
     gprintf("%o (variation %d)", count_variations-1);
 #else
-  gprintf("%o (%d)", hashdata.hashval);
+  gprintf("%o (%d)", hashdata.hashval[0]);
 #endif
 
   gprintf("%o\n");
@@ -884,11 +885,16 @@
 
   /* Check the hash table to see if it corresponds to the cumulative one. */
   hashdata_recalc(&oldkey, board, board_ko_pos);
+#if FULL_POSITION_IN_HASH
   gg_assert(hashdata_diff_dump(&oldkey, &hashdata) == 0);
+#else
+  gg_assert(hashdata_compare(&oldkey, &hashdata) == 0);
+#endif
 #endif
 
+  if (board_ko_pos != NO_MOVE)
+    hashdata_invert_ko(&hashdata, board_ko_pos);
   board_ko_pos = NO_MOVE;
-  hashdata_remove_ko(&hashdata);
 
   /* If the move is a pass, we can skip some steps. */
   if (pos != PASS_MOVE) {
@@ -901,7 +907,11 @@
 #if CHECK_HASHING
     /* Check the hash table to see if it equals the previous one. */
     hashdata_recalc(&oldkey, board, board_ko_pos);
+#if FULL_POSITION_IN_HASH
     gg_assert(hashdata_diff_dump(&oldkey, &hashdata) == 0);
+#else
+    gg_assert(hashdata_compare(&oldkey, &hashdata) == 0);
+#endif
 #endif
   }
   new_position();
@@ -3759,8 +3769,11 @@
   if (string[s].liberties == 1
       && string[s].size == 1
       && captured_stones == 1) {
+    /* In case of a double ko: clear old ko position first. */
+    if (board_ko_pos != NO_MOVE)
+      hashdata_invert_ko(&hashdata, board_ko_pos);
     board_ko_pos = string[s].libs[0];
-    hashdata_set_ko(&hashdata, board_ko_pos);
+    hashdata_invert_ko(&hashdata, board_ko_pos);
   }
 }
 
Index: engine/cache.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/cache.c,v
retrieving revision 1.11
diff -u -r1.11 cache.c
--- engine/cache.c      4 Mar 2002 06:49:08 -0000       1.11
+++ engine/cache.c      23 Mar 2002 22:08:35 -0000
@@ -93,7 +93,9 @@
 
   /* Data about the node itself. */
   fprintf(outfile, "Hash value: %lx\n", (unsigned long) node->key.hashval);
+#if FULL_POSITION_IN_HASH
   hashposition_dump(&(node->key.hashpos), outfile);
+#endif
 
   for (result = node->results; result != NULL; result = result->next) {
     read_result_dump(result, outfile);
@@ -367,7 +369,7 @@
    */
   for (k = 0; k < table->num_nodes; k++) {
     node = &(table->all_nodes[k]);
-    bucket = node->key.hashval % table->hashtablesize;
+    bucket = node->key.hashval[0] % table->hashtablesize;
     previous = NULL;
     current = table->hashtable[bucket];
 
@@ -469,7 +471,7 @@
   node->results = NULL;
 
   /* ...and enter it into the table. */
-  bucket = hd->hashval % table->hashtablesize;
+  bucket = hd->hashval[0] % table->hashtablesize;
   node->next = table->hashtable[bucket];
   table->hashtable[bucket] = node;
 
@@ -493,13 +495,24 @@
 {
   Hashnode *node;
   int bucket;
+  int i;
 
-  bucket = hd->hashval % table->hashtablesize;
+  bucket = hd->hashval[0] % table->hashtablesize;
   for (node = table->hashtable[bucket]; node != NULL; node = node->next) {
-    if (node->key.hashval != hd->hashval)
+    if (node->key.hashval[0] != hd->hashval[0])
       continue;
-    if (hashposition_compare(&hd->hashpos, &node->key.hashpos) == 0)
+    for (i = 1; i < NUM_HASHVALUES; i++)
+      if (node->key.hashval[i] != hd->hashval[i]) {
+       stats.hash_collisions++;
+       break;
+      }
+    if (i >= NUM_HASHVALUES)
+#if FULL_POSITION_IN_HASH
+      if (hashposition_compare(&hd->hashpos, &node->key.hashpos) == 0)
+       break;
+#else
       break;
+#endif
   }
   return node;
 }
@@ -589,6 +602,8 @@
                 / (1.5 * sizeof(Hashnode *)
                    + sizeof(Hashnode)
                    + 1.4 * sizeof(Read_result)));
+  if (0)
+    gprintf("Allocated memory for %d hash nodes. \n", (int) nodes);
   /* If we get a zero size hash table, disable hashing completely. */
   if (nodes < 1.0)
     hashflags = HASH_NOTHING;
@@ -691,7 +706,11 @@
 
   /* Check the hash table to see if we have had this position before. */
   hashdata_recalc(&key, board, board_ko_pos);
+#if FULL_POSITION_IN_HASH
   gg_assert(hashdata_diff_dump(&key, &hashdata) == 0);
+#else
+  gg_assert(hashdata_compare(&key, &hashdata) == 0);
+#endif
 
   /* Find this position in the table.  If it wasn't found, enter it. */
   hashnode = hashtable_search(movehash, &hashdata);
Index: engine/hash.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/hash.c,v
retrieving revision 1.11
diff -u -r1.11 hash.c
--- engine/hash.c       22 Mar 2002 08:18:32 -0000      1.11
+++ engine/hash.c       23 Mar 2002 22:08:37 -0000
@@ -40,15 +40,15 @@
 static int is_initialized = 0;
 
 
-
 /* Random values for the hash function.  For stones and ko position. */
-static Hashvalue white_hash[BOARDMAX]; 
-static Hashvalue black_hash[BOARDMAX]; 
-static Hashvalue ko_hash[BOARDMAX];
-
+static Hashvalue white_hash[BOARDMAX][NUM_HASHVALUES]; 
+static Hashvalue black_hash[BOARDMAX][NUM_HASHVALUES]; 
+static Hashvalue ko_hash[BOARDMAX][NUM_HASHVALUES];
 
+#if FULL_POSITION_IN_HASH
 static Compacttype white_patterns[4 * sizeof(Compacttype)];
 static Compacttype black_patterns[4 * sizeof(Compacttype)];
+#endif
 
 
 /* Get a random Hashvalue, where all bits are used. */
@@ -73,8 +73,11 @@
 hash_init(void)
 {
   int pos;
-  int x;
+  int i;
   struct gg_rand_state state;
+#if FULL_POSITION_IN_HASH
+  int x;
+#endif
 
   if (is_initialized)
     return;
@@ -90,15 +93,17 @@
   gg_srand(1);
 #endif
   
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++)
-    if (ON_BOARD(pos)) {
-      black_hash[pos] = hash_rand();
-      white_hash[pos] = hash_rand();
-      ko_hash[pos]    = hash_rand();
-    }
-  
+  for (i = 0; i < NUM_HASHVALUES; i++)
+    for (pos = BOARDMIN; pos < BOARDMAX; pos++)
+      if (ON_BOARD(pos)) {
+       black_hash[pos][i] = hash_rand();
+       white_hash[pos][i] = hash_rand();
+       ko_hash[pos][i]    = hash_rand();
+      }
+
   gg_set_rand_state(&state);
   
+#if FULL_POSITION_IN_HASH
   {
     Compacttype mask;
 
@@ -107,6 +112,7 @@
       black_patterns[x] = mask << 1;
     }
   }
+#endif
 
   is_initialized = 1;
 }
@@ -120,6 +126,7 @@
  * which are used e.g. by the comparison functions used in qsort().
  */
 
+#if FULL_POSITION_IN_HASH
 int
 hashposition_compare(Hashposition *pos1, Hashposition *pos2)
 {
@@ -160,12 +167,13 @@
   else
     gfprintf(outfile, "  Ko position: %1m", pos->ko_pos);
 }
+#endif                 /* FULL_POSITION_IN_HASH */
 
 
 /* ---------------------------------------------------------------- */
 
 
-/* Calculate the compactboard and the hashvalue in one function.
+/* Calculate the compactboard and the hashvalues in one function.
  * They are always used together and it saves us a loop and a function 
  * call.
  */
@@ -173,50 +181,50 @@
 void 
 hashdata_recalc(Hash_data *target, Intersection *p, int ko_pos)
 {
-  /* USE_SHIFTING is a (CPU dependent?) optimization.
-   * The theory behind it is that shifting is relatively cheap.
-   * Referencing a precomputed array uses the bus, and might consume 
-   * a cacheslot. 
-   *
-   * FIXME: Do some more measuring.
-   *   Here is the result so far:
-   *   Platform                Speedup (comparing SHIFT to TABLE)
-   *   ------------------------------------------------
-   *   Intel PII       2-3% of total run-time
-   *   SPARC           ???
-   */
-
-#define USE_SHIFTING 1
-#if USE_SHIFTING
+#if FULL_POSITION_IN_HASH
   unsigned int index;
-  int pos;
   Compacttype bits;
+#endif
+  int pos;
+  int i;
 
-  target->hashval = 0;
+  for (i = 0; i < NUM_HASHVALUES; i++)
+    target->hashval[i] = 0;
+#if FULL_POSITION_IN_HASH
   bits = 1;
   index = 0;
   target->hashpos.board[index] = 0;
+#endif
   for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
     if (!ON_BOARD(pos))
       continue;
     switch (p[pos]) {
       default:
       case EMPTY: 
+#if FULL_POSITION_IN_HASH
        bits <<= 2;
+#endif
        break;
       case WHITE:
-       target->hashval ^= white_hash[pos];
+        for (i = 0; i < NUM_HASHVALUES; i++)
+         target->hashval[i] ^= white_hash[pos][i];
+#if FULL_POSITION_IN_HASH
        target->hashpos.board[index] |= bits;
        bits <<= 2;
+#endif
        break;
       case BLACK:
-       target->hashval ^= black_hash[pos];
+        for (i = 0; i < NUM_HASHVALUES; i++)
+         target->hashval[i] ^= black_hash[pos][i];
+#if FULL_POSITION_IN_HASH
        bits <<= 1;
        target->hashpos.board[index] |= bits;
        bits <<= 1;
+#endif
        break;
     }
 
+#if FULL_POSITION_IN_HASH
     if (!bits) {
       /* This means the bit fell off the left side. */
       bits = 1;
@@ -224,85 +232,43 @@
       if (index < COMPACT_BOARD_SIZE)
        target->hashpos.board[index] = 0;
     }
+#endif
   }
 
   /* This cleans up garbage bits at the (unused) end of the array.
    * It probably should not really be necessary.
    */
+#if FULL_POSITION_IN_HASH
   while (++index < COMPACT_BOARD_SIZE)
     target->hashpos.board[index] = 0;
-
-#else /* USE_SHIFTING */
-
-  int index;
-  int subindex;
-  int pos;
-  Compacttype bits;
-
-  target->hashval = 0;
-  index = 0;
-  subindex = 0;
-  bits = 0;
-  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
-    if (!ON_BOARD(pos))
-      continue;
-    switch (p[pos]) {
-    default:
-    case EMPTY: 
-      break;
-    case WHITE:
-      target->hashval ^= white_hash[pos];
-      bits |= white_patterns[subindex];
-      break;
-    case BLACK:
-      target->hashval ^= black_hash[pos];
-      bits |= black_patterns[subindex];
-      break;
-    }
-
-    if (++subindex == POINTSPERCOMPACT) {
-      target->hashpos.board[index++] = bits;
-      bits = 0;
-      subindex = 0;
-    }
-  }
-  
-  if (subindex != 0)
-    target->hashpos.board[index] = bits;
-#endif /* USE_SHIFTING */
+#endif
 
   if (ko_pos != 0)
-    target->hashval ^= ko_hash[ko_pos];
+    for (i = 0; i < NUM_HASHVALUES; i++)
+      target->hashval[i] ^= ko_hash[ko_pos][i];
 
+#if FULL_POSITION_IN_HASH
   target->hashpos.ko_pos = ko_pos;
+#endif
 }
 
 
 /*
- * Set ko in the hash value and hash position.
+ * Set or remove ko in the hash value and hash position.
  */
 
 void
-hashdata_set_ko(Hash_data *hd, int pos)
+hashdata_invert_ko(Hash_data *hd, int pos)
 {
-  hd->hashval ^= ko_hash[pos];
+  int i;
+  for (i = 0; i < NUM_HASHVALUES; i++)
+    hd->hashval[i] ^= ko_hash[pos][i];
+#if FULL_POSITION_IN_HASH
   hd->hashpos.ko_pos = pos;
+#endif
 }
 
 
-/*
- * Remove any ko from the hash value and hash position.
- */
-
-void
-hashdata_remove_ko(Hash_data *hd)
-{
-  if (hd->hashpos.ko_pos != 0) {
-    hd->hashval ^= ko_hash[hd->hashpos.ko_pos];
-    hd->hashpos.ko_pos = 0;
-  }
-}
-
 
 /*
  * Set or remove a stone of COLOR at pos in a Hash_data.
@@ -311,18 +277,27 @@
 void
 hashdata_invert_stone(Hash_data *hd, int pos, int color)
 {
+#if FULL_POSITION_IN_HASH
   int i = I(pos);
   int j = J(pos);
   int index = (i * board_size + j) / POINTSPERCOMPACT;
   int subindex = (i * board_size + j) % POINTSPERCOMPACT;
+#endif
+  int k;
 
   if (color == BLACK) {
-    hd->hashval ^= black_hash[pos];
+    for (k = 0; k < NUM_HASHVALUES; k++)
+      hd->hashval[k] ^= black_hash[pos][k];
+#if FULL_POSITION_IN_HASH
     hd->hashpos.board[index] ^= black_patterns[subindex];
+#endif
   }
   else if (color == WHITE) {
-    hd->hashval ^= white_hash[pos];
+    for (k = 0; k < NUM_HASHVALUES; k++)
+      hd->hashval[k] ^= white_hash[pos][k];
+#if FULL_POSITION_IN_HASH
     hd->hashpos.board[index] ^= white_patterns[subindex];
+#endif
   }
 }
 
@@ -333,6 +308,7 @@
  * return is the same as for hashposition_compare()
  */
 
+#if FULL_POSITION_IN_HASH
 int
 hashdata_diff_dump(Hash_data *hd1, Hash_data *hd2)
 {
@@ -392,16 +368,25 @@
 
   return retval;
 }
+#endif
 
 
 int
 hashdata_compare(Hash_data *hd1, Hash_data *hd2)
 {
-  int rc;
+  int rc = 0;
+  int i;
 
-  rc = (hd1->hashval == hd2->hashval) ? 0 : 2;
+  for (i = 0; i < NUM_HASHVALUES; i++)
+    if (hd1->hashval[i] != hd2->hashval[i]) 
+      rc = 2;
+  if ( rc == 2 && i > 0)
+    stats.hash_collisions++;
+
+#if FULL_POSITION_IN_HASH
   if (rc == 0)
     rc = hashposition_compare(&hd1->hashpos, &hd2->hashpos);
+#endif
 
   return rc;
 }
Index: engine/hash.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/hash.h,v
retrieving revision 1.6
diff -u -r1.6 hash.h
--- engine/hash.h       4 Mar 2002 06:49:08 -0000       1.6
+++ engine/hash.h       23 Mar 2002 22:08:38 -0000
@@ -20,6 +20,7 @@
 \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 #include <stdio.h>
+#include <gnugo.h>
 
 /*
  * This file, together with engine/hash.c implements hashing of go positions
@@ -55,12 +56,42 @@
 /* for testing: Enables a lot of checks. */
 #define CHECK_HASHING 0
 
+/* Set this to 1 for old hashing, 2 for new hashing, 3 for experiments. */
+#define HASHING_SCHEME 2
+
+/* Old hashing. */
+#if (HASHING_SCHEME==1)                
+#define NUM_HASHVALUES                 1
+#define FULL_POSITION_IN_HASH  1
+#endif
+
+/* Proposed new hashing. */
+#if (HASHING_SCHEME==2)
+
+/* How many bits should be used at least for hashing? Set this to 32 for
+ * some memory save and speedup, at the cost of occasional irreproducable
+ * mistakes (and possibly assertion failures). 
+ * With 64 bits, there should be less than one such mistake in 10^9 games.
+ * Set this to 96 if this is not safe enough for you.
+ */
+#define MIN_HASHBITS           64              
+
+#define NUM_HASHVALUES                 (MIN_HASHBITS / ( 8 * SIZEOF_LONG))
+#define FULL_POSITION_IN_HASH  0       /* Set this to 1 for debugging. */
+#endif
+
+/* Use this for self-defined values. */
+#if (HASHING_SCHEME==3)
+#define NUM_HASHVALUES                 ?
+#define FULL_POSITION_IN_HASH  ?
+#endif
+
 
 /*
  * We define a special compact representation of the board for the 
- * positions.  In this representation each location is represented
- * by 2 bits with 0 meaning EMPTY, 1 meaning WHITE and 2 meaning 
- * BLACK as defined in gnugo.h.
+ * positions, used if FULL_POSITION_IN_HASH is set. In this representation
+ * each location is represented by 2 bits with 0 meaning EMPTY, 1 meaning
+ * WHITE and 2 meaning BLACK as defined in gnugo.h.
  * COMPACT_BOARD_SIZE is the size of such a compact representation
  * for the maximum board size allowed.
  *
@@ -84,11 +115,12 @@
 #define POINTSPERCOMPACT    ((int) sizeof(Compacttype) * 4)
 #define COMPACT_BOARD_SIZE  ((MAX_BOARD) * (MAX_BOARD) / POINTSPERCOMPACT + 1)
 
-
+#if FULL_POSITION_IN_HASH
 typedef struct hashposition_t {
   Compacttype  board[COMPACT_BOARD_SIZE];
   int          ko_pos;
 } Hashposition;
+#endif
 
 
 /*
@@ -97,19 +129,22 @@
  */
 
 typedef struct {
-  Hashvalue     hashval;
+  Hashvalue     hashval[NUM_HASHVALUES];
+#if FULL_POSITION_IN_HASH
   Hashposition  hashpos;
+#endif
 } Hash_data;
 
 
 void hash_init(void);
+#if FULL_POSITION_IN_HASH
 int hashposition_compare(Hashposition *pos1, Hashposition *pos2);
 void hashposition_dump(Hashposition *pos, FILE *outfile);
+#endif
 
 void hashdata_recalc(Hash_data *hd, Intersection *board, int ko_pos);
 int hashdata_compare(Hash_data *hd1, Hash_data *hd2);
-void hashdata_set_ko(Hash_data *hd, int pos);
-void hashdata_remove_ko(Hash_data *hd);
+void hashdata_invert_ko(Hash_data *hd, int pos);
 void hashdata_invert_stone(Hash_data *hd, int pos, int color);
 void hashdata_set_tomove(Hash_data *hd, int to_move);
 




reply via email to

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