1

I am trying to create a class that generates a decision tree for a board from the Game Tic-Tac-Toe. I am using the comment from the user "ssoler" on the post Tic-Tac-Toe: How to populate decision tree? as the basis for the class however I don't think the class is working. For one I cannot see all the outputs as idle abbreviates them by using "...". Also my use of classes and recursion in the past is poor. I am aiming to apply the Minimax algorithm and alpha-beta pruning to the tree outputted by the class.

win_comb=((0,1,2),(3,4,5),(6,7,8),(6,3,0),(7,4,1),(8,5,2),(6,4,2),(8,4,0))
Board = [1, 2, 3, 4, 5, 6, 7, 8, 9]
whose_move = 1
child_nodes = []

class Node():
    def __init__(self,Board,win_comb,whose_move, child_nodes):
        self.c_g_s = Board
        self.node = None
        self.new_node = None
        self.child_nodes = child_nodes
        self.win_comb = win_comb
        self.w_m = whose_move

    def create_tree(self):
        for index,each in enumerate(self.c_g_s):
            if each == index + 1:
                self.new_node = self.c_g_s
                if self.w_m == 1:
                    self.new_node[index] = "X"
                    self.w_m = 0
                else:
                    self.new_node[index] = "O"
                    self.w_m = 1
                self.new_node = tuple(self.new_node)
                if self.available_moves():
                    self.new_node = self.c_g_s
                    self.child_nodes.append(self.create_tree())
                else:
                    child_nodes.append(self.new_node)
        if self.child_nodes:
            return [self.node,self.child_nodes]
        return

    def available_moves(self):
        for index, each in enumerate(self.c_g_s):
            if index + 1 == each:
                return False
        return True

n = Node(Board,win_comb,whose_move,child_nodes)


print(n.create_tree())
Community
  • 1
  • 1
Faisal148991
  • 47
  • 2
  • 12
  • 1
    The `'...'` output is likely the result of trying to print a recursive data structure. (I suspect `self.c_g_s` or `self.child_nodes`, although I haven't really looked at it.) Since printing a structure that contains itself would take forever, Python's standard types use `'...'` as a placeholder to indicate "more of the same here". The [`reprlib.recursive_repr`](https://docs.python.org/3/library/reprlib.html#reprlib.recursive_repr) decorator allows you to mark your own `__repr__` functions as potentially-recursive, to avoid this problem in your own container types. – Kevin J. Chase Feb 17 '16 at 16:24

1 Answers1

0

I'm guessing this simplification of your program generates what you want, all possible boards as a tree. It's poised for you to now use your winning combinations list to significantly prune the branches as it's generated:

winning_combinations = ((0,1,2), (3,4,5), (6,7,8), (6,3,0), (7,4,1), (8,5,2), (6,4,2), (8,4,0))
board = [1, 2, 3, 4, 5, 6, 7, 8, 9]
whose_move = 1

class Node():
    def __init__(self, board, whose_move):
        self.board = board
        self.whose_move = whose_move

    def create_tree(self, board=None, whose_move=None):

        if board is None:
            board = self.board
        if whose_move is None:
            whose_move = self.whose_move

        child_nodes = []

        for index, square in enumerate(board):
            if square == index + 1:  # if square not taken
                new_board = list(board)  # make a shallow copy

                if whose_move == 1:
                    new_board[index] = "X"
                    whose_move = 0
                else:
                    new_board[index] = "O"
                    whose_move = 1

                if self.available_moves(new_board):
                    child_nodes.append(self.create_tree(new_board, whose_move))
                else:
                    child_nodes.append(new_board)
        return child_nodes

    def available_moves(self, board):
        for index, square in enumerate(board):
            if square == index + 1:  # if square not taken
                return True
        return False

node = Node(board, whose_move)

print(node.create_tree())

The key is not to store in your object things that you want to temporary mutate to see what might happen (e.g. the board and whose turn it is) -- make those local variables. Also, your available_moves() method had True and False reversed.

cdlane
  • 40,441
  • 5
  • 32
  • 81
  • Thank you for the solution, could you help me a tad more as I am currently adding a module that figures out whether a user has won or not however whilst I am trying to access the winning combinations I get the error "AttributeError: 'list' object has no attribute with 'check_if_won' [the module that checks who has won or if it is a draw] " – Faisal148991 Feb 15 '16 at 21:55
  • 1
    @Faisal148991, I suggest you close off this question and post a new one with the method with which you're having problems, examples of the data it's processing and what you desire to be returned. You can include a link back to this question for additional background on your problem. – cdlane Feb 16 '16 at 19:36