Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

SgHash.h

Go to the documentation of this file.
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


17 Jun 2010 Doxygen 1.4.7