def check_neighbors(self, start, end, grid, open_list): node = open_list.pop(0) node.closed = True if node == end: return backtrace(end) neighbors = self.find_neighbors(grid, node) for neighbor in neighbors: if neighbor.closed or neighbor.opened: continue open_list.append(neighbor) neighbor.opened = True neighbor.parent = node
def check_neighbors(self, start, end, grid, open_list, open_value=True, backtrace_by=None, width=0, height=0): """ find next path segment based on given node (or return path if we found the end) """ # pop node with minimum 'f' value node = heapq.nsmallest(1, open_list)[0] open_list.remove(node) node.closed = True width = grid.width height = grid.height # if reached the end position, construct the path and return it # (ignored for bi-directional a*, there we look for a neighbor that is # part of the oncoming path) if not backtrace_by and node == end: return backtrace(end) # get neighbors of the current node neighbors = self.find_neighbors(grid, node) for neighbor in neighbors: if neighbor.closed: # already visited last minimum f value continue if backtrace_by and neighbor.opened == backtrace_by: # found the oncoming path if backtrace_by == BY_END: return bi_backtrace(node, neighbor) else: return bi_backtrace(neighbor, node) # check if the neighbor has not been inspected yet, or # can be reached with smaller cost from the current node self.process_node(neighbor, node, end, open_list, open_value, width, height) # the end has not been reached (yet) keep the find_path loop running return None
def check_neighbors(self, start, end, grid, open_list, open_value=True, backtrace_by=None): """ find next path segment based on given node (or return path if we found the end) """ # pop node with minimum 'f' value node = heapq.nsmallest(1, open_list)[0] open_list.remove(node) node.closed = True # if reached the end position, construct the path and return it # (ignored for bi-directional a*, there we look for a neighbor that is # part of the oncoming path) if not backtrace_by and node == end: return backtrace(end) # get neighbors of the current node neighbors = self.find_neighbors(grid, node) for neighbor in neighbors: if neighbor.closed: # already visited last minimum f value continue if backtrace_by and neighbor.opened == backtrace_by: # found the oncoming path if backtrace_by == BY_END: return bi_backtrace(node, neighbor) else: return bi_backtrace(neighbor, node) # check if the neighbor has not been inspected yet, or # can be reached with smaller cost from the current node self.process_node(neighbor, node, end, open_list, open_value) # the end has not been reached (yet) keep the find_path loop running return None
def find_path(self, start, end, grid, max_runs=MAX_RUNS): """ find a path from start to end node on grid using the A* algorithm :param start: start node :param end: end node :param grid: grid that stores all possible steps/tiles as 2D-list :param max_runs: max. amount of tries until we abort the search (optional, only if we enter huge grids and have time constrains) <=0 means there are no constrains and the code might run on any large map. :return: """ open_list = [] start.g = 0 start.f = 0 # push the start node into the open list heapq.heappush(open_list, start) runs = 0 # while the open list is not empty while len(open_list) > 0: runs += 1 if 0 < max_runs <= runs: logging.error('A* run into barrier of {} iterations without ' 'finding the destination'.format(max_runs)) break # pop node with minimum 'f' value node = heapq.nsmallest(1, open_list)[0] open_list.remove(node) node.closed = True # if reached the end position, construct the path and return it if node == end: return backtrace(end), runs # get neighbors of the current node neighbors = grid.neighbors(node, self.diagonal_movement) for neighbor in neighbors: if neighbor.closed: # already visited last minimum f value continue x = neighbor.x y = neighbor.y # get the distance between current node and the neighbor ng = node.g if x - node.x == 0 or y - node.y == 0: # direct neighbor - distance is 1 ng += 1 else: # not a direct neighbor - diagonal movement ng += SQRT2 # check if the neighbor has not been inspected yet, or # can be reached with smaller cost from the current node if not neighbor.opened or ng < neighbor.g: neighbor.g = ng neighbor.h = neighbor.h or self.weight * \ self.heuristic(abs(x - end.x), abs(y - end.y)) # f is the estimated total cost from start to goal neighbor.f = neighbor.g + neighbor.h neighbor.parent = node if not neighbor.opened: heapq.heappush(open_list, neighbor) neighbor.opened = True else: # the neighbor can be reached with smaller cost. # Since its f value has been updated, we have to # update its position in the open list open_list.remove(neighbor) heapq.heappush(open_list, neighbor) # failed to find path return [], runs