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)
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
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
def reverseTransformMove(self, move: int, r: int, f: int) -> int: """ Unflip and then unrotate the move position. :param move: :param r: :param f: :return: """ board = NEWBOARD # board[move] = 'M' updatedBoard = setMove(board, move, 'M') restoredBoard = self.restore(updatedBoard, r, f) nOrig = restoredBoard.index('M') return nOrig
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)
def makeAndEvaluateMove(self, board: str, move: int, mark: str, count: int) -> Tuple[int, int, int]: """ Make the move and evaluate the board. :param board: :param move: :param mark: :param count: A longer game is better. :return: 'X' is maximizer; 'O' is minimizer """ boardCopy = setMove(board, move, mark) winner = theWinner(boardCopy) (val, nextCount) = ( (1, count) if winner == XMARK else (-1, count) if winner == OMARK else # winner == None. Is the game a tie because board is full? (0, count) if emptyCellsCount(boardCopy) == 0 else # The game is not over. Minimax is is called as the argument to this lambda function. # Minimax returns (val, move, count). Select and return val and count. # move is the next player's best move, which we don't return. (lambda mmResult: (mmResult[0], mmResult[2]))(self.minimax(boardCopy, count))) return (val, move, nextCount)
def getQMove(self, board: str, move: int) -> int: (_, r, f) = self.getQBoardWithRF(board) tempBoard = setMove(NEWBOARD, move, 'M') qTempBoard = self.transform(tempBoard, r, f) qMove = qTempBoard.index('M') return qMove