/* * Compute the next move given the opponent's last move. Your AI is * expected to keep track of the board on its own. If this is the first move, * or if the opponent passed on the last move, then opponentsMove will be NULL. * * msLeft represents the time your AI has left for the total game, in * milliseconds. doMove() must take no longer than msLeft, or your AI will * be disqualified! An msLeft value of -1 indicates no time limit. * * The move returned must be legal; if there are no valid moves for your side, * return NULL. */ Move *Player::doMove(Move *opponentsMove, int msLeft) { // add opponent's move to our board gameboard->doMove(opponentsMove, them); // print opponent move if (opponentsMove == NULL) { cerr << "PASS"<< endl; } else { cerr << "Opponent: " << opponentsMove->x << " " << opponentsMove->y << endl; } // implement Minimax if (testingMinimax) { // make a vector of our moves at current depth vector<Move*> Movector = MakeMovector(*gameboard, us); // check edge case if (Movector.empty()) { return NULL; } // if moves exist else { int BestScore = -70; // want lowest value of score Move * BestMove = NULL; for (unsigned int i = 0; i < Movector.size(); i++) { Board * gameboardcopy = gameboard->copy(); gameboardcopy->doMove(Movector[i], us); // should make sure to call even number depth int score = Minimax(gameboardcopy, them, 4, 1, -70, 70); if (score > BestScore) { BestMove = Movector[i]; BestScore = score; } } // perform our move on our own board gameboard->doMove(BestMove, us); cerr << "Grace: " << BestMove->x << " " << BestMove->y << endl; return BestMove; } } // naive solution (working AI plays random valid moves) else { if (gameboard->hasMoves(us)) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { Move move(i, j); if (gameboard->checkMove(&move, us)) { // perform our move on our own board Move * iMove = new Move(i, j); gameboard->doMove(iMove, us); // return move to actual game return iMove; } } } } } // shouldn't actually hit this case... // std::cerr << "Grace: idk" << std::endl; return NULL; }
/** * Get the compuer's input using the Minimax algorithm * * @param sf::Event event the event that the computer should handle, here it is * useless since the computer doesn;t use the mouse/keyboard to make a move * @param Board b the current board of the game * * @return std::pair<unsigned int, unsigned int> a position (row, col) * on the board where the computer's move should be made */ std::pair<unsigned int, unsigned int> AiPlayer::GetInput(sf::Event, Board b){ return Minimax(b); }
int Player::Minimax(Board * board, Side side, int depth, int CurrentDepth, int alpha, int beta) { if (CurrentDepth == depth) { return FindBoardScore(*board, side); } // else vector<Move*> Movector = MakeMovector(*board, side); if (Movector.empty()) { return FindBoardScore(*board, side); } // else // instead of switching checking for min / max every layer, // each recursive call looks 2 plays ahead and just returns the max if (CurrentDepth % 2 == 0) // parity 0, our side's move, maximize score { int BestScore = -70; for (unsigned int i = 0; i < Movector.size(); i++) { // create an board one move into future Board * boardcopy = board->copy(); boardcopy->doMove(Movector[i], side); Side nextside = (side == BLACK) ? WHITE : BLACK; // recursive call int score = Minimax(boardcopy, nextside, depth, CurrentDepth + 1, alpha, beta); // update if appropriate if (score > BestScore) BestScore = score; if (BestScore > alpha) alpha = BestScore; if (beta <= alpha) // abs(beta) <= alpha break; } return BestScore; } else // parity 1, opponent's move, minimize score { int WorstScore = 70; for (unsigned int i = 0; i < Movector.size(); i++) { // create an board one move into future Board * boardcopy = board->copy(); boardcopy->doMove(Movector[i], side); Side nextside = (side == BLACK) ? WHITE : BLACK; // recursive call int score = Minimax(boardcopy, nextside, depth, CurrentDepth + 1, alpha, beta); // update if appropriate if (score < WorstScore) { WorstScore = score; } if (WorstScore < beta) beta = WorstScore; if (beta <= alpha) // abs(beta) >= alpha break; } return WorstScore; } }