bool AlphaBetaSearch::getNextMoveVec(IDType playerToMove, MoveArray & moves, const size_t & moveNumber, const TTLookupValue & TTval, const size_t & depth, std::vector<Action> & moveVec) const { if (_params.maxChildren() && (moveNumber >= _params.maxChildren())) { return false; } // if this move is beyond the first, check to see if we are only using a single move if (moveNumber == 1) { // if we are player modeling, we should have only generated the first move if (_params.playerModel(playerToMove) != PlayerModels::None) { // so return false return false; } // if there is a transposition table entry for this state if (TTval.found()) { // if there was a valid move found with higher depth, just do that one const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove); if ((TTval.entry()->getDepth() >= depth) && abMove.isValid()) { // so return false return false; } } } const Array<std::vector<Action>, Constants::Max_Ordered_Moves> & orderedMoves(_orderedMoves[depth]); moveVec.clear(); // if this move should be from the ordered list, return it from the list if (moveNumber < orderedMoves.size()) { moveVec.assign(orderedMoves[moveNumber].begin(), orderedMoves[moveNumber].end()); return true; } // otherwise return the next move vector starting from the beginning else { if (moves.hasMoreMoves()) { moves.getNextMoveVec(moveVec); return true; } else { return false; } } }
const MoveTuple AlphaBeta::getNumMoveTuples(MoveArray & moves, const TTLookupValue & TTval, const IDType & playerToMove, const size_t & depth) const { // if we are doing opponent modeling, there is just one move to do if (_params.usePlayerModel(playerToMove)) { return 1; } // if there is a transposition table entry for this state if (TTval.found()) { // if there was a valid move found with higher depth, just do that one const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove); if ((TTval.entry()->getDepth() >= depth) && abMove.isValid() && (abMove.moveTuple() < moves.numMoveTuples())) { return 1; } } // otherwise, it's the number of possible moves + number of ordered moves return moves.numMoveTuples(); }
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); } } }