This is the doxygen documentation for gtkboard.
.00001 /* This file is a part of gtkboard, a board games system. 00002 Copyright (C) 2003, Arvind Narayanan <arvindn@users.sourceforge.net> 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA 00017 00018 */ 00019 #include <stdio.h> 00020 #include <unistd.h> 00021 #include <stdlib.h> 00022 #include <assert.h> 00023 #include <glib.h> 00024 00025 #include "move.h" 00026 00048 #ifndef uint 00049 #define uint unsigned 00050 #endif 00051 00052 #ifndef byte 00053 #define byte gint8 00054 #endif 00055 00056 // FIXME: write a function called debug or something instead of doing it this way 00057 extern int opt_verbose; 00058 00059 /* TODO: use a secondary hash fn of 16 bits to use as increment in case 00060 of collision. Also use it for 16 of the 48 bits of the check field */ 00061 00062 /* TODO: hash the state also. games like chess will need it */ 00063 00064 typedef struct 00065 { 00066 guint32 check; /* should this be 32 or 64 ? */ 00067 /* hmm.. maybe 48: that would fit nicely into 3 words */ 00068 float eval; 00069 int num_moves:16; 00070 int depth:8; 00071 int free:1; 00072 int stale:1; 00073 byte *best_move; 00074 } hash_t; 00075 00076 static int hash_table_size = 1 << 16; 00077 static int hash_table_max = 3 * 1 << 14; 00078 static int num_hash_coeffts = 1024; 00079 static uint *hash_coeffts = NULL; 00080 static hash_t *hash_table = NULL; 00081 static int hash_filled = 0; 00082 static int hash_eval_hits = 0, hash_eval_misses = 0; 00083 static int hash_move_hits = 0, hash_move_misses = 0; 00084 00085 static void hash_init () 00086 /* malloc the stuff */ 00087 // FIXME: Do we need to free this? 00088 { 00089 int i; 00090 if (hash_coeffts) return; 00091 hash_coeffts = (uint *) malloc (num_hash_coeffts * sizeof (uint)); 00092 assert (hash_coeffts); 00093 for (i=0; i<num_hash_coeffts; i++) 00094 hash_coeffts[i] = (random() << 1u) + 1; 00095 hash_table = (hash_t *) malloc (hash_table_size * sizeof (hash_t)); 00096 assert (hash_table); 00097 for (i=0; i<hash_table_size; i++) 00098 hash_table[i].free = 1; 00099 } 00100 00101 static uint get_hash (byte *pos, int poslen) 00102 { 00103 int i; 00104 uint hash = 0; 00105 if (!hash_coeffts) 00106 hash_init (); 00107 for (i = 0; i < poslen; i++) 00108 hash += (pos[i] * hash_coeffts[i%num_hash_coeffts]); 00109 return hash; 00110 } 00111 00112 static uint get_check (byte *pos, int poslen) 00113 /* just another hash function */ 00114 { 00115 int i; 00116 uint check = 0; 00117 if (!hash_coeffts) 00118 hash_init (); 00119 for (i=0; i < poslen; i++) 00120 check += (pos[i] * hash_coeffts 00121 [num_hash_coeffts-1-(i%num_hash_coeffts)]); 00122 return check; 00123 } 00124 00125 // FIXME: hash should work with state as well 00126 void hash_insert (byte *pos, int poslen, int num_moves, int depth, float eval, 00127 byte *move) 00128 { 00129 uint start = get_hash (pos, poslen) % hash_table_size; 00130 uint check = get_check (pos, poslen); 00131 int idx, cnt = 0; 00132 for (idx=start; cnt <= 10; idx = (idx+1) % hash_table_size, cnt++) 00133 { 00134 if (hash_table[idx].free) 00135 { 00136 if (hash_filled >= hash_table_max) 00137 continue; 00138 hash_filled++; 00139 break; 00140 } 00141 if (hash_table[idx].stale) 00142 break; 00143 /* even if the same position is already there it should be 00144 overwritten with the new depth */ 00145 if (hash_table[idx].check == check) 00146 break; 00147 if (hash_filled >= hash_table_max && depth > hash_table[idx].depth) 00148 break; 00149 } 00150 if (hash_table[idx].free == 0 && hash_table[idx].best_move) 00151 free (hash_table[idx].best_move); 00152 hash_table[idx].free = 0; 00153 hash_table[idx].check = check; 00154 hash_table[idx].num_moves = num_moves; 00155 hash_table[idx].eval = eval; 00156 hash_table[idx].depth = depth; 00157 hash_table[idx].stale = 0; 00158 hash_table[idx].best_move = (move ? movdup (move) : NULL); 00159 } 00160 00161 int hash_get_eval (byte *pos, int poslen, int num_moves, int depth, float *evalp) 00162 /* get the eval of a pos if it is there in the hash table 00163 retval = was it found 00164 eval = answer*/ 00165 { 00166 uint idx = get_hash (pos, poslen) % hash_table_size; 00167 uint check = get_check (pos, poslen); 00168 for (; hash_table[idx].free == 0; idx = (idx+1) % hash_table_size) 00169 { 00170 if (hash_table[idx].check == check) /* found it */ 00171 { 00172 /* don't compare 2 evals at different depths*/ 00173 if (hash_table[idx].depth == depth 00174 && hash_table[idx].num_moves == num_moves) 00175 { 00176 if (evalp) 00177 *evalp = hash_table[idx].eval; 00178 hash_table[idx].stale = 0; 00179 hash_eval_hits++; 00180 return 1; 00181 } 00182 break; 00183 } 00184 } 00185 /* found a free slot before encountering this pos */ 00186 hash_eval_misses++; 00187 return 0; 00188 } 00189 00190 byte * hash_get_move (byte *pos, int poslen, int num_moves) 00191 { 00192 uint idx = get_hash (pos, poslen) % hash_table_size; 00193 uint check = get_check (pos, poslen); 00194 for (; hash_table[idx].free == 0; idx = (idx+1) % hash_table_size) 00195 { 00196 if (hash_table[idx].check == check) /* found it */ 00197 { 00198 if (hash_table[idx].num_moves == num_moves) 00199 { 00200 hash_table[idx].stale = 0; 00201 hash_move_hits++; 00202 return hash_table[idx].best_move; 00203 } 00204 break; 00205 } 00206 } 00207 /* found a free slot before encountering this pos */ 00208 hash_move_misses++; 00209 return NULL; 00210 } 00211 00212 void hash_clear () 00213 { 00214 int i; 00215 for (i=0; i<hash_table_size; i++) 00216 { 00217 if (hash_table[i].free == 0 && hash_table[i].best_move) 00218 free (hash_table[i].best_move); 00219 hash_table[i].free = 1; 00220 } 00221 hash_filled = 0; 00222 } 00223 00224 void hash_print_stats () 00225 { 00226 int i, stale=0; 00227 if (opt_verbose) printf ("hashtable: size=%d \tfilled=%d \teval_hits=%d \teval_misses=%d \tmove_hits=%d \tmove_misses=%d \t", 00228 hash_table_size, hash_filled, 00229 hash_eval_hits, hash_eval_misses, hash_move_hits, hash_move_misses); 00230 hash_eval_hits = hash_eval_misses = hash_move_hits = hash_move_misses = 0; 00231 for (i=0; i<hash_table_size; i++) 00232 { 00233 if (!hash_table[i].free && hash_table[i].stale) 00234 stale++; 00235 hash_table[i].stale = 1; 00236 } 00237 if (opt_verbose) printf ("stale=%d\n", stale); 00238 }