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 #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


Sun Mar 13 2011 Doxygen 1.7.1