Minimax解决方案不起作用

时间:2018-08-20 14:01:47

标签: python

所以我很长一段时间以来一直在研究这个问题。但是我只是想不通。

我有一个像这样的球员课:

class perfectplayer():
    def __init__(self, player, game):
        self.player = player
        self.game = game

    def possible_moves(self, board):
        '''Finds all possible moves of given board'''
        possible_moves = []
        for x in range(len(board)):
            for y in range(len(board[x])):
                if board[x][y] is None:
                    possible_moves.append((x, y))
        return possible_moves

    def score(self, game, depth):
        '''Gives score to given board based on depth and who wins'''
        if game.win()[0]:
            if game.win()[1] is self.player:
                return 10 - depth
            else:
                return depth - 10
        return 0

    def minimax(self, game, depth):
        '''Constructs minimax tree and selects best move based on that tree'''
        if game.game_over():
            return self.score(game, depth)
        depth += 1
        scores = []
        moves = []

        # Recursively creates tree of possible decisions 
        for move in self.possible_moves(game.board):
            possible_game = game
            possible_game.move(move)
            scores.append(self.minimax(possible_game, depth))
            moves.append(move)

        # max the score if it is player's turn
        if game.current_player is self.player:
            max_score_idx = scores.index(max(scores))
            self.choice = moves[max_score_idx]
            return scores[max_score_idx]
        # min the score if it is not player's turn
        else:
            min_score_idx = scores.index(min(scores))
            self.choice = moves[min_score_idx]
            return scores[min_score_idx]

    def best_move(self, game):
        '''returns best move in give game state'''
        self.minimax(game, 0)
        return self.choice

哪个游戏类具有正确运行所需的所有功能。如果游戏结束,谁赢得了比赛以及谁将要前进,它可以返回。正如我测试过的那样,所有这些都有效。想法基本上是,best_move函数返回AI播放器的下一个选择。但是当我运行我的小游戏时:

game1 = game()
player1 = perfectplayer("x", game1)

while not game1.game_over():
    # finds best choice
    choice = player1.best_move(game1)
    # puts down a mark
    game1.move(choice)
    # renders game
    game1.render()
    move_x = int(input("please input row: "))
    move_y = int(input("please input column: "))
    game1.move((move_x, move_y))
    if game1.win()[0]:
        print(game1.win()[1], "has won!")

我得到以下输出:

>> o|o|x|
   o|x|o|
   x|o|x|
>> please input row: 1
>> please input column: 1
>> x has won!

因此,它正确地知道x赢了并且正确地要求我输入,但是为什么我的游戏板在1圈后就被填满了?这在我的代码中哪里发生?选择变量是正确的,因为它始终是两个坐标的元组。

伪代码来自以下网站:https://www.neverstopbuilding.com/blog/minimax

这是游戏类的代码:

class game():
    def __init__(self, board=None, starting_player="x"):
        if board is None:
            self.board = [[None, None, None],
                          [None, None, None],
                          [None, None, None]]
        else:
            self.board = board
        self.current_player = starting_player

    def render(self):
        for row in self.board:
            for item in row:
                if item is None:
                    print(".", end="|")
                else:
                    print(item, end="|")
            print()

    def move(self, move):
        move_x = move[0]
        move_y = move[1]
        self.board[move_x][move_y] = self.current_player
        self.switch()

    def legalmove(self, move):
        move_x = move[0]
        move_y = move[1]
        if self.board[move_x][move_y] is None:
            return True
        return False

    def switch(self):
        if self.current_player == "x":
            self.current_player = "o"
        else:
            self.current_player = "x"

    def win(self):
        board = self.board
        for x in range(len(board)):
            for y in range(len(board[x])):
                if board[0][y] == board[1][y] == board[2][y] is not None:
                    return True, board[0][y]
                if board[x][0] == board[x][1] == board[x][2] is not None:
                    return True, board[x][0]
                if x == y and board[0][0] == board[1][1] == board[2][2] is not None:
                    return True, board[0][0]
                if x + y == 2 and board[0][2] == board[1][1] == board[2][0] is not None:
                    return True, board[0][2]
        return False, None

    def game_over(self):
        for x in range(len(self.board)):
            for y in range(len(self.board[x])):
                if self.board[x][y] is None:
                    return False
        return True

1 个答案:

答案 0 :(得分:3)

我认为问题在于这一行:

possible_game = game

不是不是创建游戏状态的副本,而只是创建它的另一个引用。因此,您的搜索会修改实际的面板。要解决此问题,您可以:

  • 在探索结果状态后,执行“撤消”操作以撤消移动。
  • 或为游戏状态实施复制操作。