Minimax Alogrithm for TicTacToe [python]

时间:2017-04-08 12:41:30

标签: python algorithm tic-tac-toe minimax minmax

我正在尝试在我的tic tac toe游戏中实现minimax算法。我观看了几个视频,用minimax算法分析了多个程序,我想我现在知道它是如何工作的。我的程序正在运行,但似乎算法不知道他在做什么。它输出板上的垫,但它不阻止我或试图赢。喜欢它是随机的。如果有人可以查看我的minimax算法并告诉我的错误,那就太好了!告诉我我的解释有什么不对,并且不仅仅是投票,这也很好。

from copy import deepcopy


class Board:
    def __init__(self, board=None):
        self.winning_combos = (
            [0, 1, 2], [3, 4, 5], [6, 7, 8],
            [0, 3, 6], [1, 4, 7], [2, 5, 8],
            [0, 4, 8], [2, 4, 6])

        if board is not None:
            self.board = board
        else:
            self.board = [None for i in range(9)]

    def check_combos(self):
        """ checks every combo if its used """
        for symbol in ['X', 'O']:
            for win_comb in self.winning_combos:
                sum = 0
                for field in win_comb:
                    if self.board[field] == symbol:
                        sum += 1

                if sum == 3:
                    return symbol

        return None

    def complete(self):
        """ check if the game is complete, caused by win or draw """
        cc = self.check_combos()
        if cc is not None:
            return cc

        if len(self.empty_pads()) <= 0:
            return "DRAW"

        return False

    def show(self):
        """ print board """
        print(str(self.board[0:3]) + "\n" +
              str(self.board[3:6]) + "\n" +
              str(self.board[6:9]))

    def empty_pads(self):
        """ returns list with indexes of every unused/empty field/pad """
        list = []
        for pad in range(len(self.board)):
            if self.board[pad] is None:
                list.append(pad)

        return list

    def set(self, position, player):
        """ sets the players symbol on the given position """
        self.board[position] = player

    def copy(self):
        return deepcopy(self)


def get_enemy_player(player):
    if player == 'X':
        return 'O'
    return 'X'


def get_player_value(player):
    """ X = max, O = min """
    if player == 'X':
        return 1
    else:
        return -1


def get_player_by_value(value):

    if value == -1:
        return "O"
    elif value == 1:
        return "X"
    else:
        return "NONE"


def max_v(node):
    if node.depth == 0 or node.board.complete():
        return get_player_value(node.board.complete())

    bestVal = -100
    for child in node.children:
        v = minimax(child)
        if v >= bestVal:
            bestVal = v
            node.bestmove = child.move

    return bestVal


def min_v(node):
    if node.depth == 0 or node.board.complete():
        return get_player_value(node.board.complete())

    bestVal = 100
    for child in node.children:
        v = minimax(child)
        if v <= bestVal:
            bestVal = v
            node.bestmove = child.move

    return bestVal


def minimax(node):
    if node.depth == 0 or node.board.complete():
        return get_player_value(node.board.complete())

    if get_player_value(node.player) == 1:
        return max_v(node)
    elif get_player_value(node.player) == -1:
        return min_v(node)


class Node:
    def __init__(self, depth, player, board, pad):
        self.depth = depth
        self.player = player
        self.board = board
        self.move = pad
        self.board.set(pad, self.player)
        self.bestmove = int

        self.children = []
        self.CreateChildren()

    def CreateChildren(self):
        if self.depth > 0 and not self.board.complete():
            for index in self.board.empty_pads():
                board = self.board.copy()
                self.children.append(Node(self.depth - 1, get_enemy_player(self.player), board, index))

if __name__ == "__main__":
    board = Board()
    board.show()

    while not board.complete():
        player = 'X'
        player_move = int(input('Move: ')) - 1
        if player_move not in board.empty_pads():
            continue
        board.set(player_move, player)
        board.show()

        if board.complete():
            break
        player = get_enemy_player(player)
        node = Node(9, player, board.copy(), player_move)
        minmax = minimax(node)
        print(node.bestmove+1)
        for child in node.children:
            print("move: " + str(child.move + 1) + " --> " + get_player_by_value(minmax) + " win")

        board.set(node.bestmove, player)
        board.show()

    print(board.complete())
PS:我知道为什么“移动:”输出总是一样的,但那不是重点。

1 个答案:

答案 0 :(得分:0)

我在你的程序中看到了多个问题。

至于你的实际问题:你的程序就好像计算机没有区分它的损失和平局。我的代码中没有任何地方可以找到为绘图分配值0,而看起来你为胜利分配1而损失分配-1。你的代码应该更喜欢平局而不是损失,但它看不出任何区别。这就是为什么它看起来像是随机的&#34;。我在这里的分析可能没有,但以下问题解释了为什么我很难说出来。

应改进您的风格,以提高可读性和易维护性并避免错误。你的代码对我来说太难理解了,部分是因为......

  • 除了了解代码尝试执行的操作之外,您对其他任何人的评论都太少了。在几个月内你将无法记住,所以在代码中写下来。

  • 您有太多空行,违反PEP8并且更难在屏幕上看到更多代码。

  • 你没有认真对待你的输出,如你所说&34; ou [t] put总是一样,但那不是重点。&#34;包括你在内的任何人都很难在没有良好输出的情况下告诉代码中发生了什么。对此进行处理,并添加一些临时打印或记录语句,告诉您更多有关内部情况的信息。

  • 您的一些例程会返回不同类型的值。 complete()函数有时返回字符串"DRAW",有时返回布尔False,有时返回self.check_combos()的值,无论是什么类型。您的例程max_v()min_v()有时会返回get_player_value()的字符串值,有时会返回变量bestVal中的整数。