def solve_with_a_star(self): path = [] openList = MinHeap([]) entryFinder = {} initial_cost = self.heuristic[self.startingNode] openList.insert(initial_cost, [self.startingNode, []]) entryFinder[self.startingNode] = 0 closedList = [] memory_spend = 0 for i in range(1, MAX_ATTEMPTS): if openList.heap_size is 0: raise Exception("Not found a solution") else: if openList.heap_size > memory_spend: memory_spend = openList.heap_size p = openList.extract_min() cost_until_now = p[0] actual_city = p[1][0] if actual_city in entryFinder: entryFinder.pop(actual_city) if actual_city in self.objectives: finalPath = p[1][1] finalPath.append(actual_city) print(memory_spend) print(finalPath) print(cost_until_now) return adj_cities = self.graph[actual_city] closedList.append(actual_city) for adj_city in adj_cities: if adj_city not in closedList: gx = (cost_until_now - self.heuristic[actual_city] ) + adj_cities[adj_city]['distance'] cost = gx + self.heuristic[adj_city] if adj_city not in entryFinder: path = p[1][1] newPath = list(path) newPath.append(actual_city) openList.insert(cost, [adj_city, newPath]) entryFinder[adj_city] = cost else: if cost < entryFinder[adj_city]: path = p[1][1] newPath = list(path) newPath.append(actual_city) for i in range(1, openList.heap_size): if openList.heap[i][1][0] == adj_city: openList.heap[i][1][1] = newPath openList.decrease_priority(i, cost) entryFinder[adj_city] = cost break raise Exception("Max attempts reached")
def a_star(start_state, heuristic_func, successors_gen, goal_predicate, cost_func=lambda *_: 1): """ Generalized implementation of A* search. Input: start_state: Initial state heuristic_func: Function of the form (state) -> heuristic value successors_gen: Generator which yields all successors for a given state: state -> yield successor state goal_predicate: Predicate to test whether the given state is a goal state: state -> True or False (Optional) cost_func: Function which returns the cost of a state transition: from_state, to_state -> cost Defaults to a cost of one. Returns: A list of the form [(x0, y0), (x1, y1), ..., (xn, yn)] representing a path from start to end node. """ # Memoization table, maps from state to corresponding node memo = {} # Initialize containers closed = set() open_ = MinHeap(key_attr='f') # Initialize starting node start = initialize_start_node(start_state, heuristic_func) open_.insert(start) memo[start_state] = start # Loop as long as there are nodes to process while open_: u = open_.extract_min() closed.add(u) # Test to see if goal state is reached if goal_predicate(u.state): print("Goal found!") return [node.state[1:] for node in create_path_to(u)] # Process successor states of current node for v_state in successors_gen(u.state): # Check if state has been previously encountered, create new by default if v_state in memo: v = memo[v_state] else: v = initialize_successor_node(u, v_state, heuristic_func, cost_func) memo[v_state] = v # Add to parents' list of successors u.successors.append(v) # In case of encountering a new node (not opened or closed) if v not in open_ and v not in closed: attach_and_eval(v, u, heuristic_func, cost_func) open_.insert(v) # If path is an improvement to previously discovered node elif u.g + cost_func(u.state, v.state) < v.g: attach_and_eval(v, u, heuristic_func, cost_func) # If successor is an internal node if v in closed: propagate_path_improvements(v, heuristic_func, cost_func)