// 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::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; } } }
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]); } }
// Transposition Table save void AlphaBeta::TTsave( GameState & state, const AlphaBetaScore & value, const AlphaBetaScore & alpha, const AlphaBetaScore & beta, const size_t & depth, const IDType & firstPlayer, const AlphaBetaMove & bestFirstMove, const AlphaBetaMove & bestSecondMove) { // IF THE DEPTH OF THE ENTRY IS BIGGER THAN CURRENT DEPTH, DO NOTHING TTEntry * entry = _TT->lookupScan(state.calculateHash(0), state.calculateHash(1)); bool valid = entry && entry->isValid(); size_t edepth = entry ? entry->getDepth() : 0; _results.ttSaveAttempts++; if (valid && (edepth > depth)) { return; } int type(TTEntry::NONE); if (value <= alpha) type = TTEntry::UPPER; else if (value >= beta) type = TTEntry::LOWER; else type = TTEntry::ACCURATE; // SAVE A NEW ENTRY IN THE TRANSPOSITION TABLE _TT->save(state.calculateHash(0), state.calculateHash(1), value, depth, type, firstPlayer, bestFirstMove, bestSecondMove); }