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