TicTacToe 不适用 Win-Conditions &&在 minimax 上的错误动作。

问题描述 投票:0回答:1

我正在努力学习python,并一直试图编程一个简单的tictactoe游戏。以下是代码。

import random


class TicTacToe03:

    def __init__(self):
        # first, the board
        self.board = self.board = [" ", " ", " ", " ", " ", " ", " ", " ", " "]

        # then, the symbols the players will choose
        self.playerSymbol = ""
        self.aiSymbol = ""

        # the game is always ongoing, unless somebody won
        self.gameOngoing = True

        # you also need to tell the ai how different conditions are evaluated
        self.scoreBoard = {
            self.playerSymbol: -10,  # if the player wins, it is seen as smth bad from the ai
            self.aiSymbol: 10,
            "tie": 0
        }

    # every tictactoe game starts by drawing the board
    def drawBoard(self):
        print("""
          {} | {} | {}
         -----------
          {} | {} | {}
         -----------
          {} | {} | {}
        """.format(*self.board))

    # then, eveybody chooses what the like
    def chooseYourPlayer(self):
        self.playerSymbol = input("choose your player X/O ").upper()

        if self.playerSymbol == "X":
            self.aiSymbol = "O"
        else:
            self.aiSymbol = "X"

    # everybody has to behave and leave their turn when it's over
    def nextPlayer(self, player):
        if player == self.playerSymbol:
            return self.aiSymbol
        return self.playerSymbol

    # ppl also have to be able to make moves
    def move(self, player, index):
        self.board[index] = player

    # and find what moves they CAN make, so they don't override each-other
    def availableMoves(self):

        availableMoves = []

        for fieldIndex in range(len(self.board)):
            if self.board[fieldIndex] == " ":
                availableMoves.append(fieldIndex)  # yes, i append indexes, not empty fields
        return availableMoves

    def getMoves(self, player):

        playerMoves = []

        for fieldIndex in range(len(self.board)):
            if self.board[fieldIndex] == player:
                playerMoves.append(fieldIndex)
        return playerMoves

    # here is the algo to check who won, based on a set of winPos is subset of playerMoves
    def won(self):

        winningPositions = [{0, 1, 2}, {3, 4, 5}, {6, 7, 8},
                            {0, 4, 8}, {2, 4, 6}, {0, 3, 6},
                            {1, 4, 7}, {2, 5, 8}]

        for player in ("X", "O"):
            playerPositions = self.getMoves(player)
            for position in winningPositions:
                if position.issubset(playerPositions):
                    print(player + "wins")
                    self.gameOngoing = False
                    return player
        if self.board.count(" ") == 0:  # and this dude outside of the main loop
            print("Guess it's a draw")
            self.gameOngoing = False
            return "tie"

    def minimax(self, isMaximizing, player):

        if not self.gameOngoing:  # base in minimax: if this is an end-state, return it's evaluation
            return self.scoreBoard[self.won()]

        if isMaximizing:
            bestScore = float("-Infinity")  # the worst eval for max
            for move in self.availableMoves():
                self.move(player, move)
                score = self.minimax(False, self.nextPlayer(player))  # you should pick the max of what your opponent chooses
                self.move(" ", move)
                bestScore = max(bestScore, score)
            return bestScore
        else:
            bestScore = float("Infinity")
            for move in self.availableMoves():
                self.move(player, move)
                score = self.minimax(True, self.nextPlayer(player))
                self.move(" ", move)
                bestScore = min(bestScore, score)
            return bestScore

    def findOptimalMove(self, player):

        goldenMiddle = 0
        choices = []

        for move in self.availableMoves():
            self.move(player, move)
            score = self.minimax(True, player)
            self.move(" ", move)
            if score > goldenMiddle:
                choices = [move]  # this is a one-element list
                break
            elif score == goldenMiddle:
                choices.append(move)

        # here is the code block that mustn't be wrongly interpreted:
        # the idea is: you choose a random element, from a ONE-ELEMENT list!!!
        if len(choices) > 0:
            return random.choice(choices)
        else:
            return random.choice(self.availableMoves())

    def play(self):

        self.chooseYourPlayer()

        while self.gameOngoing:
            personMove = int(input("Choose a position (1-9) "))
            self.move(self.playerSymbol, personMove - 1)
            self.drawBoard()

            if not self.gameOngoing:
                break

            print("Computer choosing move...")
            aiMove = self.findOptimalMove(self.aiSymbol)
            self.move(self.aiSymbol, aiMove)
            self.drawBoard()

        print("Thanks for playing :)")


tictactoe = TicTacToe03()
tictactoe.play()

游戏 "工作 "了,因为它显示了用户的字段,然而它不会显示是否有人赢了。正如你所看到的,我尝试了简单的最小化算法,但也不能正常工作,因为人工智能只是选择下一个可用的字段,而不是逻辑上应该选择的字段。

至于我得到的错误:我只得到了一次,在板子满了之后,它是以下内容。IndexError: Cannot choose from an empty sequence (IndexError): Cannot choose from an empty sequence (on line 133).

我还发布了另一个版本,其中 "中奖 "问题不存在 ( TicTacToe和Minimax。 ),但由于没有人回答这个问题,我想再问一次会有帮助(如果我做错了什么,对不起)

一如既往,我对改进我的代码的建议和方法持开放态度 :)

python tic-tac-toe minimax
1个回答
0
投票

在我看来,唯一的问题是你忘记了调用 self.won()play() 方法。

def play(self):

    self.chooseYourPlayer()

    while self.gameOngoing:
        personMove = int(input("Choose a position (1-9) "))
        self.move(self.playerSymbol, personMove - 1)
        self.drawBoard()

        self.won()                     #<--- call self.won() here
        if not self.gameOngoing:
            break

        print("Computer choosing move...")
        aiMove = self.findOptimalMove(self.aiSymbol)
        self.move(self.aiSymbol, aiMove)
        self.drawBoard()

    print("Thanks for playing :)")

我想你曾试图做类似的事情在 minimax() 方法。但我不明白你说的是什么意思。

if not self.gameOngoing:
    return self.scoreBoard[self.won()]
© www.soinside.com 2019 - 2024. All rights reserved.