// Transposition Table look up + alpha/beta update TTLookupValue AlphaBeta::TTlookup(const GameState & state, AlphaBetaScore & alpha, AlphaBetaScore & beta, const size_t & depth) { TTEntry * entry = _TT->lookupScan(state.calculateHash(0), state.calculateHash(1)); if (entry && (entry->getDepth() == depth)) { // get the value and type of the entry AlphaBetaScore TTvalue = entry->getScore(); // set alpha and beta depending on the type of entry in the TT if (entry->getType() == TTEntry::LOWER) { if (TTvalue > alpha) { alpha = TTvalue; } } else if (entry->getType() == TTEntry::UPPER) { if (TTvalue < beta) { beta = TTvalue; } } else { printf("LOL\n"); alpha = TTvalue; beta = TTvalue; } if (alpha >= beta) { // this will be a cut _results.ttcuts++; return TTLookupValue(true, true, entry); } else { // found but no cut _results.ttFoundNoCut++; return TTLookupValue(true, false, entry); } } else if (entry) { _results.ttFoundLessDepth++; return TTLookupValue(true, false, entry); } return TTLookupValue(false, false, entry); }
void TranspositionTable::extractPVMoves(const Position& rootPos, const Move& mFirst, std::vector<Move>& pv) { Position pos(rootPos); Move m(mFirst); UndoInfo ui; std::vector<U64> hashHistory; while (true) { pv.push_back(m); pos.makeMove(m, ui); if (contains(hashHistory, pos.zobristHash())) break; hashHistory.push_back(pos.zobristHash()); TTEntry ent; ent.clear(); probe(pos.historyHash(), ent); if (ent.getType() == TType::T_EMPTY) break; ent.getMove(m); MoveList moves; MoveGen::pseudoLegalMoves(pos, moves); MoveGen::removeIllegal(pos, moves); bool contains = false; for (int mi = 0; mi < moves.size; mi++) if (moves[mi].equals(m)) { contains = true; break; } if (!contains) break; } }
/** Extract the PV starting from posIn, using hash entries, both exact scores and bounds. */ std::string TranspositionTable::extractPV(const Position& posIn) { std::string ret; Position pos(posIn); bool first = true; TTEntry ent; ent.clear(); probe(pos.historyHash(), ent); UndoInfo ui; std::vector<U64> hashHistory; bool repetition = false; while (ent.getType() != TType::T_EMPTY) { Move m; ent.getMove(m); MoveList moves; MoveGen::pseudoLegalMoves(pos, moves); MoveGen::removeIllegal(pos, moves); bool valid = false; for (int mi = 0; mi < moves.size; mi++) if (moves[mi].equals(m)) { valid = true; break; } if (!valid) break; if (repetition) break; if (!first) ret += ' '; if (ent.getType() == TType::T_LE) ret += '<'; else if (ent.getType() == TType::T_GE) ret += '>'; std::string moveStr = TextIO::moveToString(pos, m, false); ret += moveStr; pos.makeMove(m, ui); if (contains(hashHistory, pos.zobristHash())) repetition = true; hashHistory.push_back(pos.zobristHash()); probe(pos.historyHash(), ent); first = false; } return ret; }
void TranspositionTable::insert(U64 key, const Move& sm, int type, int ply, int depth, int evalScore) { if (depth < 0) depth = 0; size_t idx0 = getIndex(key); U64 key2 = getStoredKey(key); TTEntry ent0, ent1; ent0.load(table[idx0]); size_t idx = idx0; TTEntry* ent = &ent0; if (ent0.getKey() != key2) { size_t idx1 = idx0 ^ 1; ent1.load(table[idx1]); idx = idx1; ent = &ent1; if (ent1.getKey() != key2) if (ent1.betterThan(ent0, generation)) { idx = idx0; ent = &ent0; } } bool doStore = true; if ((ent->getKey() == key2) && (ent->getDepth() > depth) && (ent->getType() == type)) { if (type == TType::T_EXACT) doStore = false; else if ((type == TType::T_GE) && (sm.score() <= ent->getScore(ply))) doStore = false; else if ((type == TType::T_LE) && (sm.score() >= ent->getScore(ply))) doStore = false; } if (doStore) { if ((ent->getKey() != key2) || (sm.from() != sm.to())) ent->setMove(sm); ent->setKey(key2); ent->setScore(sm.score(), ply); ent->setDepth(depth); ent->setGeneration((S8)generation); ent->setType(type); ent->setEvalScore(evalScore); ent->store(table[idx]); } }
void TranspositionTable::printStats() const { int unused = 0; int thisGen = 0; std::vector<int> depHist; const int maxDepth = 20*8; depHist.resize(maxDepth); for (size_t i = 0; i < table.size(); i++) { TTEntry ent; ent.load(table[i]); if (ent.getType() == TType::T_EMPTY) { unused++; } else { if (ent.getGeneration() == generation) thisGen++; if (ent.getDepth() < maxDepth) depHist[ent.getDepth()]++; } } double w = 100.0 / table.size(); std::stringstream ss; ss.precision(2); ss << std::fixed << "hstat: size:" << table.size() << " unused:" << unused << " (" << (unused*w) << "%)" << " thisGen:" << thisGen << " (" << (thisGen*w) << "%)" << std::endl; cout << ss.str(); for (int i = 0; i < maxDepth; i++) { int c = depHist[i]; if (c > 0) { std::stringstream ss; ss.precision(2); ss << std::setw(4) << i << ' ' << std::setw(8) << c << " " << std::setw(6) << std::fixed << (c*w); std::cout << "hstat:" << ss.str() << std::endl; } } }