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)
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
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)
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)
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()
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)
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
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
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
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]
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
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()
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()