Esempio n. 1
0
 def _makeAMove(self, board: str) -> int:
     # The first few moves are hard-wired into HardWiredPlayer.
     move = (
         super()._makeAMove(board) if emptyCellsCount(board) >= 7 else
         # minimax returns (val, move, count). Extract move.
         self.minimax(board)[1])
     return move
Esempio n. 2
0
    def _makeAMove(self, prev_move, board: str) -> int:
        move = (
            super()._makeAMove(prev_move, board)
            if emptyCellsCount(board) >= 7 else
            # minimax returns (val, move, count). Extract move.
            self.minimax(board))

        return move
Esempio n. 3
0
    def _makeAMove(self, board: str) -> int:
        """
        If this player can win, it will.
        If not, it blocks if the other player can win.
        Otherwise it makes a random valid move.
        :param board:
        :return: selected move
        """

        (myWins, otherWins, _, _) = self.winsBlocksForks(board)
        move = choice(
            [self.findEmptyCell(board, myWin)
             for myWin in myWins] if myWins else
            [self.findEmptyCell(board, otherWin)
             for otherWin in otherWins] if otherWins else list(
                 self.otherMove(board, emptyCellsCount(board))))
        return move
Esempio n. 4
0
    def gameLoop(self, isATestGame: bool = True) -> (PlayerDict, str):
        board = NEWBOARD

        # X always makes the first move.
        currentPlayerDict: PlayerDict = self.XDict
        winnerDict: Optional[PlayerDict] = None
        done = False
        while not done:
            player: Player = currentPlayerDict['player']
            reward: int = currentPlayerDict['cachedReward']
            move: int = player.makeAMove(reward, board, isATestGame)
            (winnerDict, board) = self.step(board, move)
            done = winnerDict is not None or emptyCellsCount(board) == 0
            currentPlayerDict = self.otherDict(currentPlayerDict)

        # Tell the players the final reward for the game.
        currentPlayerDict['player'].finalReward(
            currentPlayerDict['cachedReward'])
        otherPlayerDict = self.otherDict(currentPlayerDict)
        otherPlayerDict['player'].finalReward(otherPlayerDict['cachedReward'])
        return (winnerDict, board)
Esempio n. 5
0
    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)
Esempio n. 6
0
 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)
Esempio n. 7
0
 def _makeAMove(self, board: str) -> int:
     (myWins, otherWins, myForks, otherForks) = self.winsBlocksForks(board)
     availCorners = [pos for pos in CORNERS if isAvailable(board, pos)]
     availCenter = [pos for pos in [CENTER] if isAvailable(board, pos)]
     availSides = [pos for pos in SIDES if isAvailable(board, pos)]
     myOppositeCorners = [
         pos for pos in CORNERS if isAvailable(board, pos)
         and board[oppositeCorner(pos)] == self.myMark
     ]
     move = choice(
         [self.findEmptyCell(board, myWin)
          for myWin in myWins] if myWins else
         [self.findEmptyCell(board, otherWin) for otherWin in otherWins]
         if otherWins else myForks if myForks else
         # If emptyCellsCount(board) == 6, I'm playing 'O'. If a diagonal is XOX, don't take corner.
         availSides if board[CENTER] ==
         self.myMark and emptyCellsCount(board) == 6 else otherForks
         if otherForks else availCorners if availCorners and self.myMark ==
         'X' and len(availCorners) %
         2 == 0 else availCenter if availCenter else myOppositeCorners
         if board[CENTER] == self.opMark and myOppositeCorners else
         availCorners if availCorners else validMoves(board))
     return move
Esempio n. 8
0
 def printQTable(self) -> NoReturn:
     print(f'\n\nQTable contains {len(self.qTable)} entries.')
     for (qBoard, qValuesDicts) in sorted(self.qTable.items(), key=lambda bv: 9 - emptyCellsCount(bv[0])):
         self.printQValuesForPattern(qBoard, qValuesDicts)