def recurse(root):
     """Build tree recursion
     :param root: current root
     :return: tuple with leaves"""
     if root.data.check_results() != Board.CONTINUE:
         return root.data.check_results()
     board_left = copy.deepcopy(root.data)
     board_right = copy.deepcopy(root.data)
     board_left.random_move()
     board_right.random_move()
     root.left = LinkedBinaryTree(board_left)
     root.right = LinkedBinaryTree(board_right)
     return recurse(root.left), recurse(root.right)
Exemplo n.º 2
0
    def create_tree(self):
        """(Board) -> BTNode

        Creates a tree to find the best move for the
        computer.
        """
        tree = LinkedBinaryTree(BTNode(self.board_positions))
        head_board = BTNode(self)

        def recurse(node, tree, move):
            possible_moves = node.data.free_cells()
            if len(possible_moves) == 1:
                last_board = copy.deepcopy(node)
                if move == "X":
                    next_move = "0"
                else:
                    next_move = "X"
                last_board.data.add(possible_moves[0][0], possible_moves[0][1],
                                    next_move)
                tree.insert_left(last_board)
            else:
                new_first_move = random.choice(possible_moves)
                possible_moves.remove(new_first_move)
                new_second_move = random.choice(possible_moves)

                first_board = copy.deepcopy(node)
                second_board = copy.deepcopy(node)
                if move == "X":
                    next_move = "0"
                else:
                    next_move = "X"

                first_board.data.add(new_first_move[0], new_first_move[1],
                                     next_move)
                second_board.data.add(new_second_move[0], new_second_move[1],
                                      next_move)

                tree.insert_left(first_board)
                tree.insert_right(second_board)

                recurse(first_board, tree.get_left_child(), next_move)
                recurse(second_board, tree.get_right_child(), next_move)

        recurse(head_board, tree, Board.PLAYER_INPUT)
        left_points = self.win_combination_count(tree.get_left_child())
        right_points = self.win_combination_count(tree.get_right_child())
        if left_points > right_points:
            return tree.left_child.key
        return tree.right_child.key
Exemplo n.º 3
0
    def __init__(self, root):
        '''
        Initializes variables including root of a future generated tree

        :param root: Board
        '''
        self.root = root
        self.tree = LinkedBinaryTree(root)
    def take_turn(self):
        """
        Compute next turn to win the game
        """
        self.solutions_tree = LinkedBinaryTree(Node(self))
        indexes = self.get_free_places()
        result = []

        for ind in indexes:
            result.append(self.build_solutions_tree(self, ind, True))

        best_choice = indexes[result.index(max(result))]
        self.place(best_choice, self.automated_player)
Exemplo n.º 5
0
    def take_turn(self):
        """
        Compute next turn to win the game
        """
        self.solutions_tree = LinkedBinaryTree(Node(self))
        index_1, index_2 = random.sample(self.get_free_places(), 2)

        res_1 = self.build_solutions_tree(self, index_1, self.second_player,
                                          "left")
        res_2 = self.build_solutions_tree(self, index_2, self.second_player,
                                          "right")

        if res_1 >= res_2:
            self.place(index_1, self.second_player)
        else:
            self.place(index_2, self.second_player)
Exemplo n.º 6
0
 def compute_score(self):
     has_winner = self.has_winner()
     if has_winner:
         winner_scores = {Board.NOUGHT_WINNER: 1, Board.CROSS_WINNER: -1, Board.DRAW: 0}
         return winner_scores[has_winner]
     board_tree = LinkedBinaryTree(Node(self))
     left_board = copy.deepcopy(self)
     right_board = copy.deepcopy(self)
     moved_left = left_board.make_random_move()
     moved_right = right_board.make_random_move()
     board_tree.insert_left(Node(moved_left))
     board_tree.insert_right(Node(moved_right))
     return left_board.compute_score() + right_board.compute_score()
Exemplo n.º 7
0
    def gen_tree(self):
        """
        Finds a better move on the board.
        :return: move to do.
        """
        tree = LinkedBinaryTree(self.positions)

        def recursion(board, tree):
            """Recursive function"""
            possible_moves = board.possible()
            if len(possible_moves) < 2:
                new_board = copy.deepcopy(board)
                if board.last_move == 5:
                    board.last_move = 7
                    new_board.positions[possible_moves[0][0]][
                        possible_moves[0][1]] = 7
                if board.last_move == 7:
                    board.last_move = 5
                    new_board.positions[possible_moves[0][0]][
                        possible_moves[0][1]] = 5
                tree.insert_left(new_board)
            else:
                move = board.last_move
                new_move1 = random.choice(possible_moves)
                possible_moves.remove(new_move1)
                new_move2 = random.choice(possible_moves)
                board1 = copy.deepcopy(board)
                board2 = copy.deepcopy(board)
                next_move = 5 if move == 7 else 7
                board.last_move = copy.deepcopy(next_move)
                board1.positions[new_move1[0]][new_move1[1]] = next_move
                board2.positions[new_move2[0]][new_move2[1]] = next_move
                tree.insert_left(board1)
                tree.insert_right(board2)
                recursion(board1, tree.get_left_child())
                recursion(board2, tree.get_right_child())

        recursion(self, tree)

        left_tree_points = self.win_combinations(tree.left_child.leaves_list())
        right_tree_points = self.win_combinations(
            tree.right_child.leaves_list())
        return tree.left_child.key if left_tree_points > right_tree_points \
            else tree.right_child.key
    def computer_move(self):
        """Make computer move: 
        generates binary tree and determines the best move"""
        board = copy.deepcopy(self)
        tree = LinkedBinaryTree(board)
        
        def recurse(root):
            """Build tree recursion
            :param root: current root
            :return: tuple with leaves"""
            if root.data.check_results() != Board.CONTINUE:
                return root.data.check_results()
            board_left = copy.deepcopy(root.data)
            board_right = copy.deepcopy(root.data)
            board_left.random_move()
            board_right.random_move()
            root.left = LinkedBinaryTree(board_left)
            root.right = LinkedBinaryTree(board_right)
            return recurse(root.left), recurse(root.right)

        leaves = recurse(tree)
        ######################
        left_results, right_results = [], []

        def search_from_tuple(leaves, results):
            """Take leaves from tuples"""
            if not isinstance(leaves, tuple):
                results.append(leaves)
            else:
                for leaf in leaves:
                    search_from_tuple(leaf, results)
        
        search_from_tuple(leaves[0], left_results)
        search_from_tuple(leaves[1], right_results)
        ######################
        self.last_move = -self.last_move
        left_count = left_results.count(self.last_move)
        right_count = right_results.count(self.last_move)
        if left_count < right_count:
            return copy.deepcopy(tree.right.data)
        else:
            return copy.deepcopy(tree.left.data)
Exemplo n.º 9
0
    def build_tree(self, board):
        """
        build_tree
        """
        tree = LinkedBinaryTree(board)

        def recurse(board, tree):
            """
            Recursive function for building a tree.
            """
            possible = board.possibilities()
            if len(possible) == 1:
                position = possible[0]
                left_board = deepcopy(board)
                right_board = deepcopy(board)
                if board.last_move == "x":
                    left_board.board[position[0]][position[1]] = "0"
                    right_board.board[position[0]][position[1]] = "0"
                if board.last_move == "0":
                    left_board.board[position[0]][position[1]] = "x"
                    right_board.board[position[0]][position[1]] = "x"
                tree.insert_left(left_board)
                tree.insert_right(right_board)
                return
            else:
                left_position = possible[0]
                right_position = possible[1]
                left_board = deepcopy(board)
                right_board = deepcopy(board)
                if board.last_move == "x":
                    new_move = "0"
                else:
                    new_move = "x"
                left_board.board[left_position[0]][left_position[1]] = new_move
                right_board.board[right_position[0]][
                    right_position[1]] = new_move
                left_board.last_move = new_move
                right_board.last_move = new_move
                tree.insert_left(left_board)
                tree.insert_right(right_board)
                recurse(left_board, tree.get_left_child())
                recurse(right_board, tree.get_right_child())

        recurse(board, tree)
        left_points = self.get_points(tree.get_left_child())
        right_points = self.get_points(tree.get_right_child())
        if left_points > right_points:
            return tree.get_left_child().key
        return tree.get_right_child().key
Exemplo n.º 10
0
    def computer_move(self):
        """
        () ->
        Computer moving in the game
        """
        tree = LinkedBinaryTree(self)
        self.create_tree(tree)
        left_points = self._calculate_points(tree.get_left_child())
        right_points = self._calculate_points(tree.get_right_child())

        if left_points < right_points:
            next_board = tree.get_right_child().key
        else:
            next_board = tree.get_left_child().key
        self.board = next_board.board
Exemplo n.º 11
0
    def build_tree(self):
        tree = LinkedBinaryTree(self.board)

        def recurse(board, tree, prev_move):
            empties = Board.get_empties(board)
            if len(empties) == 1:
                pos = empties[0]
                board1 = copy.deepcopy(board)
                board1[pos[0]][pos[1]] = Board.COMPUTER_SIGN
                board2 = copy.deepcopy(board)
                board2[pos[0]][pos[1]] = Board.COMPUTER_SIGN
                tree.insert_left(board1)
                tree.insert_right(board2)
                return
            else:
                pos1 = random.choice(empties)
                empties.remove(pos1)
                pos2 = random.choice(empties)
                board1 = copy.deepcopy(board)
                board2 = copy.deepcopy(board)
                if prev_move == Board.COMPUTER_SIGN:
                    curr_move = Board.HUMAN_SIGN
                else:
                    curr_move = Board.COMPUTER_SIGN
                board1[pos1[0]][pos1[1]] = curr_move
                board2[pos2[0]][pos2[1]] = curr_move
                tree.insert_left(board1)
                tree.insert_right(board2)
                recurse(board1, tree.get_left(), curr_move)
                recurse(board2, tree.get_right(), curr_move)

        recurse(self.board, tree, Board.HUMAN_SIGN)

        points_left = Board.get_points(tree.left)
        points_right = Board.get_points(tree.right)
        if points_left > points_right:
            return tree.left.key
        else:
            return tree.right.key
Exemplo n.º 12
0
    def position_choose(self):
        """
        Choost the position
        :return: position
        """
        tree = LinkedBinaryTree(self.game)
        current_symbol = self.symbol_type
        random_position = self.random_positions(self.game)
        if len(random_position) == 1:
            return random_position[0]
        game_left = Game()
        game_right = Game()
        game_left.set_symbol(random_position[0][0], random_position[0][1],
                             current_symbol)
        if game_left.game_over():
            return self._gameOver_check(current_symbol)

        game_right.set_symbol(random_position[0][0], random_position[0][1],
                              current_symbol)
        if game_right.game_over():
            return self._gameOver_check(current_symbol)

        current_symbol = self._change_symbol(current_symbol)

        def recurse(game, current_symbol):

            if game.draw():
                return 0

            # Create two new Games
            new_game1 = self._new_game(game)
            new_game2 = self._new_game(game)

            # Find two random possible positions
            random_positions = self.random_positions(game)

            new_game1.set_symbol(random_positions[0][0],
                                 random_positions[0][1], current_symbol)
            if new_game1.game_over():
                return self._gameOver_check(current_symbol)
            tree.insert_right(new_game1)

            if len(random_positions) == 1:
                current_symbol = self._change_symbol(current_symbol)
                return recurse(new_game1, current_symbol)

            new_game2.set_symbol(random_positions[1][0],
                                 random_positions[1][1], current_symbol)
            if new_game2.game_over():
                return self._gameOver_check(current_symbol)

            current_symbol = self._change_symbol(current_symbol)
            tree.insert_left(new_game2)

            return recurse(new_game1, current_symbol) + recurse(
                new_game2, current_symbol)

        if recurse(game_left, current_symbol) > recurse(
                game_right, current_symbol):
            return random_position[0]
        return random_position[1]
Exemplo n.º 13
0
        def helper(field, pos=-1):
            tree = BTree()
            res = self.check_field(field)
            if res == WIN1:
                tree.add_root(tuple([field, 1, 1, pos]))
                return tree
            if res == WIN2:
                tree.add_root(tuple([field, -1, 1, pos]))
                return tree
            if res == TIE:
                tree.add_root(tuple([field, 0, 1, pos]))
                return tree

            tree.add_root(field)
            root = tree.root()

            left = helper(*self.random_step(field))
            right = helper(*self.random_step(field))

            points = left.root().element()[1] + right.root().element()[1]
            count = left.root().element()[2] + right.root().element()[2]
            tree.replace(root, tuple([field, points, count, pos]))

            tree.attach(root, left, right)
            return tree
Exemplo n.º 14
0
 def __init__(self, board, last_turn=None):
     """Create new Board"""
     self.board = board  # string
     self.opponent = self.board[last_turn] if last_turn is not None else 'O'
     self.player = 'O' if self.opponent == 'X' else 'X'
     self.tree = Tree()
Exemplo n.º 15
0
class Board:
    """Class for Board representation"""
    def __init__(self, board, last_turn=None):
        """Create new Board"""
        self.board = board  # string
        self.opponent = self.board[last_turn] if last_turn is not None else 'O'
        self.player = 'O' if self.opponent == 'X' else 'X'
        self.tree = Tree()

    def check_win(self, board=None):
        """Checks if there is a winning combination on board"""
        if board is None:
            board = self.board
        if not self.player:
            return False
        for x in range(0, 3):
            row = {board[x * 3:][0], board[x * 3:][1], board[x * 3:][2]}
            column = {board[x], board[x + 3], board[x + 6]}
            if len(column) == 1:
                return board[x]
            if len(row) == 1:
                return board[x * 3:][0]

        diag1 = {board[0], board[4], board[8]}  # diagonals
        diag2 = {board[2], board[4], board[6]}
        if len(diag1) == 1 or len(diag2) == 1:
            return board[4]
        if board.count(self.player) + board.count(self.opponent) == 9:
            return None  # Draw
        return False

    def make_tree(self):
        """Construct a decision tree"""
        def add(position, curr_player, leaves=[]):
            board = position.element()
            winner = self.check_win(board)
            if winner:
                self.tree.mark(position, 'win' + winner)
                leaves.append(position)
                return
            poss_moves = [int(i) - 1 for i in board if i != 'O' and i != 'X']
            if not poss_moves:
                self.tree.mark(position, 'draw')
                leaves.append(position)
                return

            moves = 2 if len(poss_moves) > 1 else 1
            for i in range(moves):
                move = random.choice(poss_moves)
                poss_moves.remove(move)
                p = self.tree.add(board[:move] + curr_player +
                                  board[move + 1:],
                                  p=position)
                add(p, 'X' if curr_player == 'O' else 'O', leaves)
            return leaves

        root = self.tree.add(self.board)
        leaves = add(root, self.player)
        return leaves

    def choose_move(self):
        """Choose the best move for computer"""
        leaves = self.make_tree()
        root = self.tree.root()
        right, left = self.tree.right(root), self.tree.left(root)
        parents = {x.element(): 0 for x in [left, right] if x is not None}
        for leaf in leaves:
            parent = self.tree.find_parent(leaf).element()
            if leaf.mark() == 'win' + self.player:
                if parent == leaf.element():
                    for i in range(9):
                        if leaf.element()[i] != parent[i]:
                            return i
                parents[parent] += 1
            elif leaf.mark() == 'win' + self.opponent:
                parents[parent] -= 1

        mean = sum(parents.values()) / len(parents)  # check if all chances are
        if not all(parents[z] == mean for z in parents.keys()):  # not equal
            next_board = max(parents, key=lambda x: parents[x])
        else:
            next_board = random.choice(list(parents.keys()))
        for i in range(9):
            if self.board[i] != next_board[i]:
                return i

    def draw(self):
        """Print the game board"""
        print('\n   1 2 3')
        for i in range(3):
            print(' ' + str(i + 1), end=' ')
            for j in range(3):
                cell = self.board[i * 3:][j]
                print(cell if cell == 'O' or cell == 'X' else ' ', end=' ')
            print()