bool Table::shouldFinishGame(PieceColor pieceColor) { if(isGameFinished(pieceColor) || getAllPossibleMoves(m_array, getOppositeColor(pieceColor)).empty()) { return true; } return false; }
void AIRandomPlayer::requestMove(PieceColor moveType) { assert(m_array); auto gameLogic = m_gameLogic.lock(); std::vector<int> scores; auto lockedGameLogic = m_gameLogic.lock(); std::vector<PieceMove> moves = lockedGameLogic->getAllPossibleMoves(*m_array, moveType); auto move = moves.at(rand() % moves.size()); std::vector<Position> subMoves{move.subMoves().begin()+1, move.subMoves().end()}; lockedGameLogic->movePiece(move.source(), subMoves, moveType); }
void AIMediocrePlayer::requestMove(PieceColor moveType) { assert(m_array); auto gameLogic = m_gameLogic.lock(); std::vector<int> scores; auto lockedGameLogic = m_gameLogic.lock(); std::vector<PieceMove> moves = lockedGameLogic->getAllPossibleMoves(*m_array, moveType); std::vector<std::future<int>> futures; for(const auto& move: moves) { Array copyOfArray = *m_array; copyOfArray.move(move.source().m_row, move.source().m_col, move.destination().m_row, move.destination().m_col); for(const auto& pos: move.capturedPieces()) { copyOfArray.erase(pos.m_row, pos.m_col); } int newScore = move.numberOfCapturedPieces(); auto score = std::async(std::launch::async, &minMaxWithAlphaBetaPruning, lockedGameLogic, copyOfArray, m_maxDepth, newScore, getOppositeColor(moveType), moveType, gMinusInfinity, gPlusInfinity); futures.push_back(std::move(score)); } for(auto& future: futures) { auto result = future.get(); scores.push_back(result); } auto it = std::max_element(scores.begin(), scores.end()); PieceMove move = moves.at(std::distance(scores.begin(), it)); std::vector<Position> subMoves{move.subMoves().begin()+1, move.subMoves().end()}; lockedGameLogic->movePiece(move.source(), subMoves, moveType); }
std::pair<int, int> algorithm(const Board& board, int depth, bool whiteOnTurn) { Move currentBestMove = { 0, 0, 0 }; // Container for best value and the move to get there int a = MIN; // Alpha int b = MAX; // Beta currentBestMove.value = (whiteOnTurn) ? a : b; // 1. Get number of threads that system can manage unsigned int num_of_threads = THREADS; std::srand((int)std::time(0)); // 2. Get all possible moves and divide them as tasks to threads std::vector<Move> possibleMoves = getAllPossibleMoves(board, whiteOnTurn); // In other cases can proceed to dividing tasks for threads taskVectors.clear(); // Must be cleared so it's empty on start taskVectors = divideForThreads(possibleMoves, (int)num_of_threads); // 3. Create threadpool and run tasks with threads std::vector<std::thread> threads; // Lambda auto lambda = [depth, whiteOnTurn](Board board, int i, int la, int lb) { // This is what the thread does to its tasks // This also works as 1st level of algorithm (because of alphaBeta structure) std::srand((int)std::time(0)); // Use current time as a seed for random // Copy taskVektor so it can be used threadMutex.lock(); std::vector<Move> tasks = taskVectors[i]; threadMutex.unlock(); Move bestThreadMove = { 0, 0, 0}; bestThreadMove.value = (whiteOnTurn) ? la : lb; for (auto move : tasks) { move.value = (whiteOnTurn) ? la : lb; // For white turn=>MIN black=>MAX Board new_board = board; new_board.movePiece(move.origin, move.destination); new_board.updateState(move.destination, 1); int temp = alphaBeta(new_board, depth - 1, la, lb, !whiteOnTurn); // Recursive part depth needs to decrease now depth at its maximum if (whiteOnTurn) { if ((bestThreadMove.value < temp) || (bestThreadMove.value == temp && (rand() % 8 == 1))) { bestThreadMove = move; bestThreadMove.value = temp; } la = std::max(la, bestThreadMove.value); } else { if ((bestThreadMove.value > temp) || (bestThreadMove.value == temp && (rand() % 8 == 1))) { bestThreadMove = move; bestThreadMove.value = temp; } lb = std::min(lb, bestThreadMove.value); } if (lb <= la) { break; // Cut off bad branch } // Randomly pick if as good as current } threadMutex.lock(); // Must be logged so that threads wont do this same time { taskVectors[i].clear(); taskVectors[i].push_back(bestThreadMove); } threadMutex.unlock(); }; // Create threads and push them in vector for (unsigned int i = 0; i < taskVectors.size(); i++) { // Some magic with lambda functions threads.push_back(std::thread(lambda, board, i, a, b)); //std::cout << "Started thread number " << i + 1 << std::endl; } //int i = 1; //This is for the cout below // 4. Wait threads to finish for (auto thread = threads.begin(); thread != threads.end(); thread++) { //std::cout << "Waiting for thread number " << i << " to finish." << std::endl; thread->join(); //std::cout << "Thread number " << i++ << " finished." << std::endl; } // 5. Choose best value for (auto list : taskVectors) { for (auto move : list) { // White turn if (move.value > currentBestMove.value && whiteOnTurn) { currentBestMove = move; // Replace with better one } // Black turn else if (move.value < currentBestMove.value && !whiteOnTurn) { // To have some random factor if same values currentBestMove = move; } else if (move.value == currentBestMove.value && (rand() % 8 == 1)) { currentBestMove = move; } } } if (currentBestMove.origin == 0 && currentBestMove.destination == 0) { std::cout << "Illegal move [0,0]" << std::endl; } //std::cout << "Returning with move [" << currentBestMove.origin << "," << currentBestMove.destination << "]" << ", its value is " << currentBestMove.value << std::endl; return std::make_pair(currentBestMove.origin ,currentBestMove.destination); }
void AIBestPlayer::requestMove(PieceColor moveType) { assert(m_array); auto gameLogic = m_gameLogic.lock(); std::vector<int> scores; auto lockedGameLogic = m_gameLogic.lock(); std::vector<PieceMove> moves = lockedGameLogic->getAllPossibleMoves(*m_array, moveType); std::experimental::optional<std::pair<std::vector<Position>, int>> foundMove = bestMoves::findMove(*m_array, moveType); if(!foundMove || (foundMove && foundMove->second < m_maxDepth)) { std::cout << "computation of best move" << std::endl; std::vector<std::future<int>> futures; for(const auto& move: moves) { Array copyOfArray = *m_array; copyOfArray.move(move.source().m_row, move.source().m_col, move.destination().m_row, move.destination().m_col); for(const auto& pos: move.capturedPieces()) { copyOfArray.erase(pos.m_row, pos.m_col); } int newScore = move.numberOfCapturedPieces(); auto score = std::async(std::launch::async, &minMaxWithAlphaBetaPruning, lockedGameLogic, copyOfArray, m_maxDepth, newScore, getOppositeColor(moveType), moveType, gMinusInfinity, gPlusInfinity); futures.push_back(std::move(score)); } for(auto& future: futures) { auto result = future.get(); scores.push_back(result); } auto it = std::max_element(scores.begin(), scores.end()); PieceMove move = moves.at(std::distance(scores.begin(), it)); std::vector<Position> subMoves{move.subMoves().begin()+1, move.subMoves().end()}; lockedGameLogic->movePiece(move.source(), subMoves, moveType); } else { std::vector<Position>& positions = foundMove->first; for(const auto& move: moves) { if(positions == move.subMoves()) { std::cout << "used saved best move" << std::endl; std::vector<Position> subMoves{move.subMoves().begin()+1, move.subMoves().end()}; lockedGameLogic->movePiece(move.source(), subMoves, moveType); } } } }