00001 //---------------------------------------------------------------------------- 00002 /** @file SgHash.h 00003 Hash codes and Zobrist tables. 00004 00005 See A.L. Zobrist "A New Hashing Method with Application for Game Playing", 00006 Techn. Rep. #88, Univ. of Wisconsin, Madison, WI 53706, April 1970. 00007 (Reprinted in ICCA Journal, Spring 1990?.) 00008 */ 00009 //---------------------------------------------------------------------------- 00010 00011 #ifndef SG_HASH_H 00012 #define SG_HASH_H 00013 00014 #include <algorithm> 00015 #include <bitset> 00016 #include <iomanip> 00017 #include <iostream> 00018 #include <sstream> 00019 #include "SgArray.h" 00020 #include "SgException.h" 00021 #include "SgRandom.h" 00022 00023 //---------------------------------------------------------------------------- 00024 00025 /** N-bit hash codes */ 00026 template<int N> 00027 class SgHash 00028 { 00029 public: 00030 /** Costruct hash code initialized with zero. */ 00031 SgHash() {} 00032 00033 /** Construct hash code from integer index */ 00034 SgHash(unsigned int key); 00035 00036 ~SgHash() {} 00037 00038 /** Reinitialize the hash code. 00039 Caution: after Clear() hash code matches code of empty board. 00040 */ 00041 void Clear(); 00042 00043 /** Set to random value. */ 00044 void Invalidate(); 00045 00046 bool operator<(const SgHash& code) const; 00047 00048 bool operator==(const SgHash& code) const; 00049 00050 bool operator!=(const SgHash& code) const; 00051 00052 bool IsZero() const; 00053 00054 /** Combine this hash code with the given hash code. */ 00055 void Xor(const SgHash& code); 00056 00057 /** Use this hash code to hash into a table with 'max' elements. */ 00058 unsigned int Hash(int max) const; 00059 00060 /** First integer (deprecated). 00061 @deprecated Don't use this function; it exposes implementation 00062 details. 00063 */ 00064 unsigned int Code1() const; 00065 00066 /** Second integer (deprecated). 00067 @deprecated Don't use this function; it exposes implementation 00068 details. 00069 */ 00070 unsigned int Code2() const; 00071 00072 /** Return a random hash code. 00073 @return A random hash code, which is not zero. 00074 */ 00075 static SgHash Random(); 00076 00077 /** Roll bits n places to the left */ 00078 void RollLeft(int n); 00079 00080 /** Roll bits n places to the right */ 00081 void RollRight(int n); 00082 00083 /** Convert hash code to string */ 00084 std::string ToString() const; 00085 00086 /** Convert string to hash code */ 00087 void FromString(const std::string& str); 00088 00089 static int Size(); 00090 00091 private: 00092 /** Thomas Wang's 32 bit mix function */ 00093 unsigned int Mix32(int key) const; 00094 00095 unsigned int GetWord() const; 00096 00097 std::bitset<N> m_code; 00098 }; 00099 00100 /** For backwards compatibility */ 00101 typedef SgHash<64> SgHashCode; 00102 00103 template<int N> 00104 SgHash<N>::SgHash(unsigned int key) 00105 : m_code(Mix32(key)) 00106 { 00107 // Use Thomas Wang's 32 bit mix function, cyclically 00108 for (int i = 1; i < (N / 32); ++i) 00109 { 00110 unsigned int mix = Mix32(GetWord()); 00111 m_code <<= 32; 00112 m_code |= mix; 00113 } 00114 } 00115 00116 template<int N> 00117 bool SgHash<N>::operator<(const SgHash& code) const 00118 { 00119 // std::bitset does not define operator<, so we have to do it (less 00120 // efficiently) ourselves 00121 for (int i = N - 1; i >= 0; --i) 00122 { 00123 bool c1 = m_code[i]; 00124 bool c2 = code.m_code[i]; 00125 if (! c1 && c2) 00126 return true; 00127 if (c1 && ! c2) 00128 return false; 00129 } 00130 return false; 00131 } 00132 00133 template<int N> 00134 bool SgHash<N>::operator==(const SgHash& code) const 00135 { 00136 return code.m_code == m_code; 00137 } 00138 00139 template<int N> 00140 bool SgHash<N>::operator!=(const SgHash& code) const 00141 { 00142 return code.m_code != m_code; 00143 } 00144 00145 template<int N> 00146 void SgHash<N>::Clear() 00147 { 00148 m_code.reset(); 00149 } 00150 00151 template<int N> 00152 unsigned int SgHash<N>::Code1() const 00153 { 00154 return GetWord(); 00155 } 00156 00157 template<int N> 00158 unsigned int SgHash<N>::Code2() const 00159 { 00160 return (m_code >> 32).to_ulong(); 00161 } 00162 00163 template<int N> 00164 void SgHash<N>::FromString(const std::string& str) 00165 { 00166 Clear(); 00167 for (std::string::const_iterator i_str = str.begin(); 00168 i_str != str.end(); ++i_str) 00169 { 00170 m_code <<= 4; 00171 char c = *i_str; 00172 if (c >= '0' && c <= '9') 00173 m_code |= std::bitset<N>(c - '0'); 00174 else if (c >= 'A' && c <= 'F') 00175 m_code |= std::bitset<N>(10 + c - 'A'); 00176 else if (c >= 'a' && c <= 'f') 00177 m_code |= std::bitset<N>(10 + c - 'a'); 00178 else throw SgException("Bad hex in hash string"); 00179 } 00180 } 00181 00182 template<int N> 00183 unsigned int SgHash<N>::GetWord() const 00184 { 00185 static const std::bitset<N> mask(0xffffffffUL); 00186 return (m_code & mask).to_ulong(); 00187 } 00188 00189 template<int N> 00190 unsigned int SgHash<N>::Hash(int max) const 00191 { 00192 return GetWord() % max; 00193 } 00194 00195 template<int N> 00196 void SgHash<N>::Invalidate() 00197 { 00198 *this = Random(); 00199 } 00200 00201 template<int N> 00202 bool SgHash<N>::IsZero() const 00203 { 00204 return m_code.none(); 00205 } 00206 00207 template<int N> 00208 unsigned int SgHash<N>::Mix32(int key) const 00209 { 00210 key += ~(key << 15); 00211 key ^= (key >> 10); 00212 key += (key << 3); 00213 key ^= (key >> 6); 00214 key += ~(key << 11); 00215 key ^= (key >> 16); 00216 return key; 00217 } 00218 00219 template<int N> 00220 SgHash<N> SgHash<N>::Random() 00221 { 00222 SgHash hashcode; 00223 hashcode.m_code = SgRandom::Global().Int(); 00224 for (int i = 1; i < (N / 32); ++i) 00225 { 00226 hashcode.m_code <<= 32; 00227 hashcode.m_code |= SgRandom::Global().Int(); 00228 } 00229 00230 return hashcode; 00231 } 00232 00233 template<int N> 00234 void SgHash<N>::RollLeft(int n) 00235 { 00236 m_code = (m_code << n) ^ (m_code >> (N - n)); 00237 } 00238 00239 template<int N> 00240 void SgHash<N>::RollRight(int n) 00241 { 00242 m_code = (m_code >> n) ^ (m_code << (N - n)); 00243 } 00244 00245 template<int N> 00246 int SgHash<N>::Size() 00247 { 00248 return N; 00249 } 00250 00251 template<int N> 00252 std::string SgHash<N>::ToString() const 00253 { 00254 std::ostringstream buffer; 00255 buffer.fill('0'); 00256 std::bitset<N> mask(0xff); 00257 for (int i = N / 8; i >= 0; --i) 00258 { 00259 std::bitset<N> b = ((m_code >> (i * 8)) & mask); 00260 buffer << std::hex << std::setw(2) << b.to_ulong(); 00261 } 00262 return buffer.str(); 00263 } 00264 00265 template<int N> 00266 void SgHash<N>::Xor(const SgHash& code) 00267 { 00268 m_code ^= code.m_code; 00269 } 00270 00271 template<int N> 00272 std::ostream& operator<<(std::ostream& out, const SgHash<N>& hash) 00273 { 00274 out << hash.ToString(); 00275 return out; 00276 } 00277 00278 template<int N> 00279 std::ostream& operator>>(std::istream& in, const SgHash<N>& hash) 00280 { 00281 std::string str; 00282 in >> str; 00283 hash.FromString(str); 00284 return in; 00285 } 00286 00287 //---------------------------------------------------------------------------- 00288 00289 /** Provides random hash codes for Zobrist hashing. */ 00290 template<int N> 00291 class SgHashZobrist 00292 { 00293 public: 00294 /** Hash index. 00295 The hash index ranges from [0..MAX_HASH_INDEX-1]. For board games with 00296 black and white pieces, MAX_HASH_INDEX needs to be bigger than twice 00297 the number of points on the board. It's up to the client to map points 00298 to this range. 00299 2 * SG_MAXPOINT, plus capture hash 00300 */ 00301 static const int MAX_HASH_INDEX = 1500; 00302 00303 SgHashZobrist(); 00304 00305 const SgHash<N>& Get(int index) const { return m_hash[index]; } 00306 00307 /** Global table for this size of hash code. */ 00308 static const SgHashZobrist& GetTable(); 00309 00310 private: 00311 static SgHashZobrist m_globalTable; 00312 00313 SgArray<SgHash<N>,MAX_HASH_INDEX> m_hash; 00314 }; 00315 00316 /** For backwards compatibility */ 00317 typedef SgHashZobrist<64> SgHashZobristTable; 00318 00319 template<int N> 00320 SgHashZobrist<N> SgHashZobrist<N>::m_globalTable; 00321 00322 template<int N> 00323 SgHashZobrist<N>::SgHashZobrist() 00324 { 00325 for (int i = 0; i < MAX_HASH_INDEX; ++i) 00326 m_hash[i] = SgHash<N>::Random(); 00327 } 00328 00329 template<int N> 00330 const SgHashZobrist<N>& SgHashZobrist<N>::GetTable() 00331 { 00332 return m_globalTable; 00333 } 00334 00335 //---------------------------------------------------------------------------- 00336 00337 namespace SgHashUtil 00338 { 00339 /** Xor hash code with code from the global Zobrist table. 00340 @deprecated Use your own zobrist table to avoid bugs due to 00341 overlapping usage of indices 00342 */ 00343 template<int N> 00344 inline SgHash<N> GetZobrist(int index) 00345 { 00346 return SgHashZobrist<N>::GetTable().Get(index); 00347 } 00348 00349 /** Xor hash code with code from the global Zobrist table. 00350 @deprecated Use your own zobrist table to avoid bugs due to 00351 overlapping usage of indices 00352 */ 00353 template<int N> 00354 inline void XorZobrist(SgHash<N>& hash, int index) 00355 { 00356 hash.Xor(GetZobrist<N>(index)); 00357 } 00358 00359 /** Xor hash code with integer index (no max value) */ 00360 template<int N> 00361 inline void XorInteger(SgHash<N>& hash, int index) 00362 { 00363 hash.Xor(SgHash<N>(index)); 00364 } 00365 } 00366 00367 //---------------------------------------------------------------------------- 00368 00369 #endif // SG_HASH_H