- /* 
-     Texel - A UCI chess engine. 
-     Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.com 
-   
-     This program is free software: you can redistribute it and/or modify 
-     it under the terms of the GNU General Public License as published by 
-     the Free Software Foundation, either version 3 of the License, or 
-     (at your option) any later version. 
-   
-     This program is distributed in the hope that it will be useful, 
-     but WITHOUT ANY WARRANTY; without even the implied warranty of 
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
-     GNU General Public License for more details. 
-   
-     You should have received a copy of the GNU General Public License 
-     along with this program.  If not, see <http://www.gnu.org/licenses/>. 
- */ 
-   
- /* 
-  * transpositionTable.hpp 
-  * 
-  *  Created on: Feb 25, 2012 
-  *      Author: petero 
-  */ 
-   
- #ifndef TRANSPOSITIONTABLE_HPP_ 
- #define TRANSPOSITIONTABLE_HPP_ 
-   
- #include "util/util.hpp" 
- #include "move.hpp" 
- #include "constants.hpp" 
- #include "util/alignedAlloc.hpp" 
-   
- #include <vector> 
-   
- class Position; 
-   
- /** 
-  * Implements the main transposition table using Cuckoo hashing. 
-  */ 
- class TranspositionTable { 
- public: 
-     /** In-memory representation of TT entry. Uses std::atomic for thread safety, 
-      * but accessed using memory_order_relaxed for maximum performance. */ 
-     struct TTEntryStorage { 
-         std::atomic<U64> key; 
-         std::atomic<U64> data; 
-         TTEntryStorage(); 
-         TTEntryStorage(const TTEntryStorage& a); 
-     }; 
-     static_assert(sizeof(TTEntryStorage) == 16, "TTEntryStorage size wrong"); 
-   
-     /** A local copy of a transposition table entry. */ 
-     class TTEntry { 
-     public: 
-         /** Set type to T_EMPTY. */ 
-         void clear(); 
-   
-         /** Store in transposition table, encoded for thread safety. */ 
-         void store(TTEntryStorage& ent); 
-   
-         /** Load from transposition table, decode the thread safety encoding. */ 
-         void load(const TTEntryStorage& ent); 
-   
-         /** Return true if this object is more valuable than the other, false otherwise. */ 
-         bool betterThan(const TTEntry& other, int currGen) const; 
-   
-         U64 getKey() const; 
-         void setKey(U64 k); 
-   
-         void getMove(Move& m) const; 
-   
-         void setMove(const Move& m); 
-   
-         /** Get the score from the hash entry and convert from "mate in x" to "mate at ply". */ 
-         int getScore(int ply) const; 
-   
-         /** Convert score from "mate at ply" to "mate in x" and store in hash entry. */ 
-         void setScore(int score, int ply); 
-   
-         /** Return true if entry is good enough to cut off this branch in the search tree. */ 
-         bool isCutOff(int alpha, int beta, int ply, int depth) const; 
-   
-         int getDepth() const; 
-         void setDepth(int d); 
-         int getGeneration() const; 
-         void setGeneration(int g); 
-         int getType() const; 
-         void setType(int t); 
-         int getEvalScore() const; 
-         void setEvalScore(int s); 
-   
-     private: 
-         U64 key;        //  0 64 key         Zobrist hash key 
-         U64 data;       //  0 16 move        from + (to<<6) + (promote<<12) 
-                         // 16 16 score       Score from search 
-                         // 32 10 depth       Search depth 
-                         // 42  4 generation  Increase when OTB position changes 
-                         // 46  2 type        exact score, lower bound, upper bound 
-                         // 48 16 evalScore   Score from static evaluation 
-   
-         void setBits(int first, int size, unsigned int value); 
-         unsigned int getBits(int first, int size) const; 
-     }; 
-   
-     /** Constructor. Creates an empty transposition table with numEntries slots. */ 
-     TranspositionTable(int log2Size); 
-   
-     void reSize(int log2Size); 
-   
-     /** Insert an entry in the hash table. */ 
-     void insert(U64 key, const Move& sm, int type, int ply, int depth, int evalScore); 
-   
-     /** Retrieve an entry from the hash table corresponding to position with zobrist key "key". */ 
-     void probe(U64 key, TTEntry& result); 
-   
-     /** Prefetch cache line. */ 
-     void prefetch(U64 key); 
-   
-     /** 
-      * Increase hash table generation. This means that subsequent inserts will be considered 
-      * more valuable than the entries currently present in the hash table. 
-      */ 
-     void nextGeneration(); 
-   
-     /** Clear the transposition table. */ 
-     void clear(); 
-   
-     /** Extract a list of PV moves, starting from "rootPos" and first move "mFirst". */ 
-     void extractPVMoves(const Position& rootPos, const Move& mFirst, std::vector<Move>& pv); 
-   
-     /** Extract the PV starting from posIn, using hash entries, both exact scores and bounds. */ 
-     std::string extractPV(const Position& posIn); 
-   
-     /** Print hash table statistics. */ 
-     void printStats() const; 
-   
- private: 
-     /** Get position in hash table given zobrist key. */ 
-     size_t getIndex(U64 key) const; 
-   
-     /** Get part of zobrist key to store in hash table. */ 
-     static U64 getStoredKey(U64 key); 
-   
-   
-     vector_aligned<TTEntryStorage> table; 
-     U8 generation; 
- }; 
-   
-   
- inline 
- TranspositionTable::TTEntryStorage::TTEntryStorage() { 
-     key.store(0, std::memory_order_relaxed); 
-     data.store(0, std::memory_order_relaxed); 
- } 
-   
- inline 
- TranspositionTable::TTEntryStorage::TTEntryStorage(const TTEntryStorage& a) { 
-     key.store(a.key.load(std::memory_order_relaxed), std::memory_order_relaxed); 
-     data.store(a.data.load(std::memory_order_relaxed), std::memory_order_relaxed); 
- } 
-   
-   
- inline void 
- TranspositionTable::TTEntry::clear() { 
-     key = 0; 
-     data = 0; 
-     static_assert(TType::T_EMPTY == 0, "type not set to T_EMPTY"); 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::store(TTEntryStorage& ent) { 
-     ent.key.store(key ^ data, std::memory_order_relaxed); 
-     ent.data.store(data, std::memory_order_relaxed); 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::load(const TTEntryStorage& ent) { 
-     key = ent.key.load(std::memory_order_relaxed); 
-     data = ent.data.load(std::memory_order_relaxed); 
-     key ^= data; 
- } 
-   
- inline bool 
- TranspositionTable::TTEntry::betterThan(const TTEntry& other, int currGen) const { 
-     if ((getGeneration() == currGen) != (other.getGeneration() == currGen)) 
-         return getGeneration() == currGen;   // Old entries are less valuable 
-     if ((getType() == TType::T_EXACT) != (other.getType() == TType::T_EXACT)) 
-         return getType() == TType::T_EXACT;         // Exact score more valuable than lower/upper bound 
-     if (getDepth() != other.getDepth()) 
-         return getDepth() > other.getDepth();     // Larger depth is more valuable 
-     return false;   // Otherwise, pretty much equally valuable 
- } 
-   
- inline U64 
- TranspositionTable::TTEntry::getKey() const { 
-     return key; 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::setKey(U64 k) { 
-     key = k; 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::getMove(Move& m) const { 
-     int move = getBits(0, 16); 
-     m.setMove(move & 63, (move >> 6) & 63, (move >> 12) & 15, m.score()); 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::setMove(const Move& m) { 
-     int move = (short)(m.from() + (m.to() << 6) + (m.promoteTo() << 12)); 
-     setBits(0, 16, move); 
- } 
-   
- inline int 
- TranspositionTable::TTEntry::getScore(int ply) const { 
-     int sc = (S16)getBits(16, 16); 
-     if (SearchConst::isWinScore(sc)) 
-         sc -= ply; 
-     else if (SearchConst::isLoseScore(sc)) 
-         sc += ply; 
-     return sc; 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::setScore(int score, int ply) { 
-     if (SearchConst::isWinScore(score)) 
-         score += ply; 
-     else if (SearchConst::isLoseScore(score)) 
-         score -= ply; 
-     setBits(16, 16, score); 
- } 
-   
- inline bool 
- TranspositionTable::TTEntry::isCutOff(int alpha, int beta, int ply, int depth) const { 
-     using namespace SearchConst; 
-     const int score = getScore(ply); 
-     const int plyToMate = MATE0 - std::abs(getScore(0)); 
-     const int eDepth = getDepth(); 
-     const int eType = getType(); 
-     if ((eDepth >= depth) || (eDepth >= plyToMate*plyScale)) { 
-         if ( (eType == TType::T_EXACT) || 
-             ((eType == TType::T_GE) && (score >= beta)) || 
-             ((eType == TType::T_LE) && (score <= alpha))) 
-             return true; 
-     } 
-     return false; 
- } 
-   
- inline int 
- TranspositionTable::TTEntry::getDepth() const { 
-     return getBits(32, 10); 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::setDepth(int d) { 
-     setBits(32, 10, d); 
- } 
-   
- inline int 
- TranspositionTable::TTEntry::getGeneration() const { 
-     return getBits(42, 4); 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::setGeneration(int g) { 
-     setBits(42, 4, g); 
- } 
-   
- inline int 
- TranspositionTable::TTEntry::getType() const { 
-     return getBits(46, 2); 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::setType(int t) { 
-     setBits(46, 2, t); 
- } 
-   
- inline int 
- TranspositionTable::TTEntry::getEvalScore() const { 
-     return (S16)getBits(48, 16); 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::setEvalScore(int s) { 
-     setBits(48, 16, s); 
- } 
-   
- inline void 
- TranspositionTable::TTEntry::setBits(int first, int size, unsigned int value) { 
-     U64 mask = ((1ULL << size) - 1) << first; 
-     data = (data & ~mask) | (((U64)value << first) & mask); 
- } 
-   
- inline unsigned int 
- TranspositionTable::TTEntry::getBits(int first, int size) const { 
-     U64 sizeMask = ((1ULL << size) - 1); 
-     return (unsigned int)((data >> first) & sizeMask); 
- } 
-   
-   
- inline size_t 
- TranspositionTable::getIndex(U64 key) const { 
-     return (size_t)(key & (table.size() - 1)); 
- } 
-   
- inline U64 
- TranspositionTable::getStoredKey(U64 key) { 
-     return key; 
- } 
-   
- inline TranspositionTable::TranspositionTable(int log2Size) { 
-     reSize(log2Size); 
- } 
-   
- inline void 
- TranspositionTable::probe(U64 key, TTEntry& result) { 
-     size_t idx0 = getIndex(key); 
-     U64 key2 = getStoredKey(key); 
-     TTEntry ent; 
-     ent.load(table[idx0]); 
-     if (ent.getKey() == key2) { 
-         if (ent.getGeneration() != generation) { 
-             ent.setGeneration(generation); 
-             ent.store(table[idx0]); 
-         } 
-         result = ent; 
-         return; 
-     } 
-     size_t idx1 = idx0 ^ 1; 
-     ent.load(table[idx1]); 
-     if (ent.getKey() == key2) { 
-         if (ent.getGeneration() != generation) { 
-             ent.setGeneration(generation); 
-             ent.store(table[idx1]); 
-         } 
-         result = ent; 
-         return; 
-     } 
-     result.setType(TType::T_EMPTY); 
- } 
-   
- inline void 
- TranspositionTable::prefetch(U64 key) { 
- #ifdef HAS_PREFETCH 
-     size_t idx0 = getIndex(key); 
-     __builtin_prefetch(&table[idx0]); 
- #endif 
- } 
-   
- inline void 
- TranspositionTable::nextGeneration() { 
-     generation = (generation + 1) & 15; 
- } 
-   
- inline void 
- TranspositionTable::clear() { 
-     TTEntry ent; 
-     ent.clear(); 
-     for (size_t i = 0; i < table.size(); i++) 
-         ent.store(table[i]); 
- } 
-   
- #endif /* TRANSPOSITIONTABLE_HPP_ */ 
-