Beispiel #1
0
 def minimax(self, board: str, count: int = 0) -> (int, int, int):
     """
     Does a minimax search.
     :param board:
     :param count: The length of the game. A longer count is better.
     :return: (val, move, count): the best minimax val for current player with longest count.
              The move to achieve that.
     """
     mark = whoseMove(board)
     # possMoves are [(val, move, count)] (val in [1, 0, -1]) for move in self.validMoves(board)]
     # These are the possible moves considering a full minimax analysis.
     # The recursive call to minimax is made in self.makeAndEvaluateMove(board, move, mark, count+1)
     possMoves = [
         self.makeAndEvaluateMove(board, move, mark, count + 1)
         for move in validMoves(board)
     ]
     minOrMax = max if mark == XMARK else min
     (bestVal, _, _) = minOrMax(possMoves, key=lambda possMove: possMove[0])
     bestMoves = [(val, move, count) for (val, move, count) in possMoves
                  if val == bestVal]
     (_, _, longestBestMoveCount) = max(bestMoves,
                                        key=lambda possMove: possMove[2])
     # Get all moves with best val and with longest count
     longestBestMoves = [(val, move, count)
                         for (val, move, count) in bestMoves
                         if count == longestBestMoveCount]
     return choice(longestBestMoves)
Beispiel #2
0
    def minimax(self, board: str):
        """
        Does a minimax search.
        :param board:
        :return: (move, (val, game_length)): the move to achieve the best val with 
                                             the longest game for current player.
        """
        """ Your Code Here """

        # ----------------------------BEGIN CODE----------------------------
        # disclaimer: I did only minimax (as said on the homework description https://drive.google.com/file/d/1JXBi_5JB8fwTWX34j0ZwN5YwjoIexh-Z/view)
        # my minimax does NOT try to prolong the game. It always goes for the best move!

        # initializing default values
        moveToMake = validMoves(board)[0]
        bestValue = -100

        # this will find the best move to go to, since value only returns the best score
        # util's setMove creates a copy, so we can use that as the successor
        for validmove in validMoves(board):
            currentValue = self.value(
                setMove(board, validmove, whoseMove(board)), 0)
            if currentValue > bestValue:
                bestValue = currentValue
                moveToMake = validmove

        # currently the val and game_length tuple is arbitrary because i have not implemented depth!
        return (moveToMake)
Beispiel #3
0
 def minvalue(self, board: str, score):
     # set v to positive infinity
     v = 9999
     # min of value(successor)
     for validmove in validMoves(board):
         v = min(
             v,
             self.value(setMove(board, validmove, whoseMove(board)), score))
     return v
Beispiel #4
0
 def maxvalue(self, board: str, score):
     # set v to negative infinity
     v = -9999
     # max of value(successor)
     for validmove in validMoves(board):
         v = max(
             v,
             self.value(setMove(board, validmove, whoseMove(board)), score))
     return v
Beispiel #5
0
    def value(self, board: str, score):
        # terminal state is when there is a winner or a tie
        # ----------terminal states-------------
        # maximizer gets 100 for winning
        if theWinner(board) == XMARK:
            score += 100
            return score
        elif theWinner(board) == OMARK:
            score -= 100
            return score
        # check for a tie
        if len(validMoves(board)) == 0:
            return score

        # ------terminal states end, begin recursion-------

        # if next agent is the maximizer, get the maxvalue
        if whoseMove(board) == XMARK:
            return self.maxvalue(board, score)
        # if next agent is minimizer, return min value
        if whoseMove(board) == OMARK:
            return self.minvalue(board, score)
    def step(self, board: str, move: int) -> (Optional[PlayerDict], str):
        """
        Make the move and return (winnerDict, updatedBoard).
        If no winner, winnerDict will be None.
        :param board:
        :param move:
        :return: (winnerDict, updatedBoard)
        """
        currentPlayerDict: PlayerDict = self.XDict if whoseMove(
            board) is XMARK else self.ODict
        otherPlayerDict: PlayerDict = self.otherDict(currentPlayerDict)

        # The following are all game-ending cases.
        if not isAvailable(board, move):
            # Illegal move. currentPlayerDict loses.
            # Illegal moves should be blocked and should not occur.
            currentPlayerDict['cachedReward'] = -100
            otherPlayerDict['cachedReward'] = 100
            print(f'\n\nInvalid move by {currentPlayerDict["mark"]}: {move}.',
                  end='')
            return (otherPlayerDict, board)

        updatedBoard = setMove(board, move, currentPlayerDict['mark'])
        if theWinner(updatedBoard):
            # The current player just won the game with its current move.
            currentPlayerDict['cachedReward'] = 100
            otherPlayerDict['cachedReward'] = -100
            return (currentPlayerDict, updatedBoard)

        if emptyCellsCount(updatedBoard) == 0:
            # The game is over. It's a tie.
            currentPlayerDict['cachedReward'] = 0
            otherPlayerDict['cachedReward'] = 0
            return (None, updatedBoard)

        # The game is not over.
        # Get a reward for extending the game.
        currentPlayerDict['cachedReward'] = 1
        return (None, updatedBoard)