Esempio n. 1
0
    def solve_by_bfs(self, head: TreeNode):
        """
        Search the state space using BFS search.
        :param head: Tree head node.
        """

        # visited list to store visited position on the world map.
        visited_pos = list()
        visited_pos.append(head.brick.pos)

        # queue to hold nodes encountered at each level of the tree.
        node_queue = list()
        node_queue.append(head)

        steps = 0
        while len(node_queue) > 0:
            node = node_queue.pop(0)
            self.debug("{:10s}: {:21s} - {}".format("removed", "frontier node",
                                                    str(node)))

            # show the BFS tree.
            print("Step: {}, Depth: {}, - {}".format(steps,
                                                     self.get_node_depth(node),
                                                     str(node)))
            self.show(node.brick)

            steps += 1
            if self.is_target_state(node.brick.pos):
                print("\nBFS SEARCH COMPLETED !")
                print("Optimal path is as below -> \n")
                self.show_optimal_path(node)
                return

            for next_pos, direction in self.next_valid_move(node, visited_pos):
                # create a new brick with next_pos, initialize a new node with brick position
                new_brick = Brick(next_pos)
                new_node = TreeNode(new_brick)

                # set the 4 direction attributes
                setattr(node, direction.name.lower(), new_node)

                # and parent node of the new node.
                new_node.parent = node
                new_node.dir_from_parent = direction

                node_queue.append(new_node)
                visited_pos.append(next_pos)
                self.debug("{:10s}: {:21s} - {}".format(
                    "added", "new node", str(new_node)))

        return
Esempio n. 2
0
    def solve_by_dfs(self, node: TreeNode, visited_pos: List = None):
        """
        Search the state space using DFS algorithm.
        :param node: Tree node.
        :param visited_pos: List containing visited positions.
        """

        if visited_pos is None:
            visited_pos = list()
            visited_pos.append(node.brick.pos)

        print("Step: {}, Depth: {} - {}".format(self.dfs_steps,
                                                self.get_node_depth(node),
                                                str(node)))
        self.show(node.brick)
        self.dfs_steps += 1

        if self.is_target_state(node.brick.pos):
            # with dfs, we are in deep recursion, 'return' won't exit the entire stack.
            exit(0)

        for next_pos, direction in self.next_valid_move(node, visited_pos):

            # create a new brick with next_pos, initialize a new node with brick position
            # and recursively make the state tree.
            new_brick = Brick(next_pos)
            new_node = TreeNode(new_brick)

            # set the 4 direction attributes
            setattr(node, direction.name.lower(), new_node)

            # and parent node of the new node.
            new_node.parent = node
            new_node.dir_from_parent = direction
            visited_pos.append(next_pos)

            self.debug("{:10s}: {:21s} - {}".format("to visit", "new node",
                                                    str(new_node)))
            self.solve_by_dfs(new_node, visited_pos)
        return
Esempio n. 3
0
    def solve_by_greedy_best_first(self, head: TreeNode, target_pos: Pos):
        """
        Solve the Bloxorz problem using A* algorithm.
        :param head: head node.
        :param target_pos: target position for heuristic estimates.
        """

        # compute the heuristic cost from all valid positions to the target positions
        heuristic_costs = self.compute_heuristic_costs(target_pos)
        head.f_cost = self.min_h_cost(heuristic_costs, head)
        self.set_cost_visited(head.brick.pos, 0)

        expanded_nodes = list()

        steps = 0
        node = head

        print("Step: {}, Depth: {}, Cost: {} - {}".format(
            steps, self.get_node_depth(head),
            self.get_cost_visited(head.brick.pos), str(head)))
        self.show(head.brick)

        while True:
            for next_pos, direction in self.next_valid_move(node, []):

                # new node and estimated cost.
                new_node = TreeNode(Brick(next_pos))
                h_cost = self.min_h_cost(heuristic_costs, new_node)

                new_node.f_cost = h_cost
                # set current node's child pointer.
                setattr(node, direction.name.lower(),
                        new_node)  # node.{left|right|up|down} -> new_node

                # link new_node to the current node.
                new_node.parent = node
                new_node.dir_from_parent = direction
                heappush(expanded_nodes, new_node)
                self.debug("{:10s}: {:21s} - {} [f_cost: {:.2f}] ".format(
                    "added", "new", str(new_node), new_node.f_cost))

            node = heappop(expanded_nodes)
            self.debug("{:10s}: {:21s} - {}".format("removed", "frontier node",
                                                    str(node)))

            # update cost of this node
            self.set_cost_visited(
                node.brick.pos,
                self.get_cost_visited(node.parent.brick.pos) + 1)

            steps += 1
            print("Step: {}, Depth: {}, Cost: {} - {} [f_cost: {:.2f}]".format(
                steps, self.get_node_depth(node),
                self.get_cost_visited(node.brick.pos), str(node), node.f_cost))
            self.show(node.brick)

            # if goal state is dequeued, mark the search as completed.
            if node.brick.pos == target_pos:
                break

        print("\nGreedy Best First SEARCH COMPLETED !")
        return
Esempio n. 4
0
    def solve_by_astar(self, head: TreeNode, target_pos: Pos):
        """
        Solve the Bloxorz problem using A* algorithm.
        :param head: head node.
        :param target_pos: target position for heuristic estimates.
        """

        # compute the heuristic cost from all valid positions to the target positions
        heuristic_costs = self.compute_heuristic_costs(target_pos)
        head.f_cost = self.min_h_cost(heuristic_costs, head)
        self.set_cost_visited(head.brick.pos, 0)

        expanded_nodes = list()

        steps = 0
        node = head

        print("Step: {}, Depth: {}, Cost: {} - {}".format(
            steps, self.get_node_depth(head),
            self.get_cost_visited(head.brick.pos), str(head)))
        self.show(head.brick)

        while True:
            for next_pos, direction in self.next_valid_move(node, []):

                g_cost = self.get_cost_visited(node.brick.pos) + 1

                # if the node is not visited, add to expanded queue.
                # if the node is visited, but has lower actual cost than previously recorded, add to expanded queue.
                if next_pos not in self.cost_visited or g_cost < self.get_cost_visited(
                        next_pos):
                    # new node and estimated cost.
                    new_node = TreeNode(Brick(next_pos))
                    h_cost = self.min_h_cost(heuristic_costs, new_node)

                    new_node.f_cost = g_cost + h_cost
                    # set current node's child pointer.
                    setattr(node, direction.name.lower(),
                            new_node)  # node.{left|right|up|down} -> new_node

                    # link new_node to the current node.
                    new_node.parent = node
                    new_node.dir_from_parent = direction
                    heappush(expanded_nodes, new_node)
                    self.debug(
                        "{:10s}: {:21s} - {} [f_cost: {:.2f} = {} + {:.2f}] ".
                        format("added", "new | visited & cheap", str(new_node),
                               new_node.f_cost, g_cost, h_cost))
                else:
                    self.debug(
                        "{:10s}: {:21s} - [hash(Parent): {}, Parent->{}] [Cost now: {}, earlier: {}]"
                        .format("rejected", "visited & costly", hash(node),
                                direction.name.lower(), g_cost,
                                self.get_cost_visited(next_pos)))

            node = heappop(expanded_nodes)
            self.debug("{:10s}: {:21s} - {}".format("removed", "frontier node",
                                                    str(node)))

            # update cost of this node
            self.set_cost_visited(
                node.brick.pos,
                self.get_cost_visited(node.parent.brick.pos) + 1)

            steps += 1
            print("Step: {}, Depth: {}, Cost: {} - {} [f_cost: {:.2f}]".format(
                steps, self.get_node_depth(node),
                self.get_cost_visited(node.brick.pos), str(node), node.f_cost))
            self.show(node.brick)

            # if goal state is dequeued, mark the search as completed.
            if node.brick.pos == target_pos:
                break

        print("\nA* SEARCH COMPLETED !")
        print("Optimal path is as below -> \n")
        self.show_optimal_path(node)
        return