// 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); }
// 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); }
void AlphaBeta::generateOrderedMoves(GameState & state, MoveArray & moves, const TTLookupValue & TTval, const IDType & playerToMove, const size_t & depth) { // get the array where we will store the moves and clear it Array<MoveTuple, Search::Constants::Max_Ordered_Moves> & orderedMoves(_orderedMoves[depth]); orderedMoves.clear(); // if we are using opponent modeling, get the move and then return, we don't want to put any more moves in if (_params.usePlayerModel(playerToMove)) { MoveTuple playerModelMove = _params.getPlayer(playerToMove)->getMoveTuple(state, moves); orderedMoves.add(playerModelMove); return; } // if there is a transposition table entry for this state if (TTval.found()) { // get the abMove we stored for this player const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove); // here we get an incorrect move from the transposition table if (abMove.moveTuple() >= moves.numMoveTuples()) { HashType h0 = state.calculateHash(0); HashType h1 = state.calculateHash(1); MoveArray moves2; state.generateMoves(moves2, playerToMove); // figure out why //fprintf(stderr, "Something very wrong, this tuple (%d) doesn't exist, only (%d) moves\n", (int)abMove.moveTuple(), (int)moves.numMoveTuples()); } _results.ttFoundCheck++; // Two checks: // 1) Is the move 'valid' ie: was it actually set inside the TT // 2) Is it a valid tuple number for this move set? This guards against double // hash collision errors. Even if it is a collision, this is just a move // ordering, so no errors should occur. if (abMove.isValid() && (abMove.moveTuple() < moves.numMoveTuples())) { orderedMoves.add(abMove.moveTuple()); _results.ttMoveOrders++; return; } else { _results.ttFoundButNoMove++; } } // if we are using script modeling, insert the script moves we want if (_params.useScriptMoveFirst()) { for (size_t s(0); s<_allScripts.size(); s++) { MoveTuple scriptMove = _allScripts[s]->getMoveTuple(state, moves); orderedMoves.addUnique(scriptMove); } } }