def step(self, record = None): """Starts the computation of the shortest path. *Note* : This function works as a generator, a yield statement is appended at the bottom of each loop to make this function capable of being executed step by step. If you does not want the step feature, simply delete the yield statements. :Parameters: record : deque or list if a queue is specified, a record of each operation (OPEN, CLOSE, etc) will be pushed into the queue. """ # add the source node into the open list sx, sy = self.source self.nodes[sy][sx].g = 0 self.nodes[sy][sx].f = 0 self.open_list.append(_QNode(self.source, self.nodes)) self.nodes[sy][sx].status = OPENED # while the open list is not empty while self.open_list: # get the node with lowest F from the heap x, y = heappop(self.open_list).pos self.nodes[y][x].status = CLOSED if record != None: record.append(('CLOSE', (x, y))) # if the node is the target, reconstruct the path # and break the loop if (x, y) == self.target: self._retrace() break # inspect the horizontal and vertical adjacent nodes for i in xrange(len(XOFFSET)): # next x and y nx = x + XOFFSET[i] ny = y + YOFFSET[i] # if the next coordinate is walkable, inspect it. if is_walkable(nx, ny, self.n_row, self.n_col, self.graph): self._inspect_node((nx, ny), (x, y), False, record) # further investigate the diagonal nodes nx1 = x + DAXOFFSET[i] ny1 = y + DAYOFFSET[i] nx2 = x + DBXOFFSET[i] ny2 = y + DBYOFFSET[i] npos = ((nx1, ny1), (nx2, ny2)) for nx, ny in npos: if is_walkable(nx, ny, self.n_row, self.n_col, self.graph): self._inspect_node((nx, ny), (x, y), True, record)
def _expand_target(self, rec): """Searches from the target. Until it meets a node which has been visited by the other tree. """ # the procedure is identical with _expand_source. v, (x, y) = heappop(self.queue_target) node = self.nodes[y][x] diagonal_can = [] if rec is not None: rec.append(('CLOSE', (x, y))) for i in range(len(XOFFSET)): nx = x + XOFFSET[i] ny = y + YOFFSET[i] if is_walkable(nx, ny, self.size, self.graph): diagonal_can.append(i) if self.nodes[ny][nx].visited_by == CTARGET: continue nxt_node = self.nodes[ny][nx] if nxt_node.visited_by == CSOURCE: if rec: rec.append(('CLOSE', (nx, ny))) self._retrace((nx, ny), (x, y)) self.success = True return nxt_node.visited_by = CTARGET nxt_node.h = node.h + DIST nxt_node.parent = (x, y) heappush(self.queue_target, (nxt_node.h, (nx, ny))) if rec is not None: rec.append(('OPEN', (nx, ny))) rec.append(('VALUE', ('h', (nx, ny), nxt_node.h))) rec.append(('PARENT', ((nx, ny), (x, y)))) # further investigate the diagonal nodes for i in diagonal_can: nx1 = x + DAXOFFSET[i] ny1 = y + DAYOFFSET[i] nx2 = x + DBXOFFSET[i] ny2 = y + DBYOFFSET[i] npos = ((nx1, ny1), (nx2, ny2)) for nx, ny in npos: if is_walkable(nx, ny, self.size, self.graph) and \ self.nodes[ny][nx].visited_by != CTARGET: nxt_node = self.nodes[ny][nx] if nxt_node.visited_by == CSOURCE: if rec: rec.append(('CLOSE', (nx, ny))) self._retrace((nx, ny), (x, y)) self.success = True return nxt_node.visited_by = CTARGET nxt_node.h = node.h + DDIST nxt_node.parent = (x, y) heappush(self.queue_target, (nxt_node.h, (nx, ny))) if rec is not None: rec.append(('OPEN', (nx, ny))) rec.append(('VALUE', ('h', (nx, ny), nxt_node.h))) rec.append(('PARENT', ((nx, ny), (x, y))))
def step(self, record=None): """Starts the computation of the shortest path. *Note* : This function works as a generator, a yield statement is appended at the bottom of each loop to make this function capable of being executed step by step. If you does not want the step feature, simply delete the yield statements. :Parameters: record : deque or list if a queue is specified, a record of each operation (OPEN, CLOSE, etc) will be pushed into the queue. """ # add the source node into the open list sx, sy = self.source self.nodes[sy][sx].g = 0 self.nodes[sy][sx].f = 0 self.open_list.append(_QNode(self.source, self.nodes)) self.nodes[sy][sx].status = OPENED # while the open list is not empty while self.open_list: # get the node with lowest F from the heap x, y = heappop(self.open_list).pos self.nodes[y][x].status = CLOSED if record != None: record.append(('CLOSE', (x, y))) # if the node is the target, reconstruct the path # and break the loop if (x, y) == self.target: self._retrace() break # inspect the horizontal and vertical adjacent nodes for i in xrange(len(XOFFSET)): # next x and y nx = x + XOFFSET[i] ny = y + YOFFSET[i] # if the next coordinate is walkable, inspect it. if is_walkable(nx, ny, self.n_row, self.n_col, self.graph): self._inspect_node((nx, ny), (x, y), False, record) # further investigate the diagonal nodes nx1 = x + DAXOFFSET[i] ny1 = y + DAYOFFSET[i] nx2 = x + DBXOFFSET[i] ny2 = y + DBYOFFSET[i] npos = ((nx1, ny1), (nx2, ny2)) for nx, ny in npos: if is_walkable(nx, ny, self.n_row, self.n_col, self.graph): self._inspect_node((nx, ny), (x, y), True, record) yield
def _expand_target(self, rec): """Searches from the target. Until it meets a node which has been visited by the other tree. """ # the procedure is identical with _expand_source. v, (x, y) = heappop(self.queue_target) node = self.nodes[y][x] diagonal_can = [] if rec != None: rec.append(('CLOSE', (x, y))) for i in xrange(len(XOFFSET)): nx = x + XOFFSET[i] ny = y + YOFFSET[i] if is_walkable(nx, ny, self.n_row, self.n_col, self.graph): diagonal_can.append(i) if self.nodes[ny][nx].visited_by == CTARGET: continue nxt_node = self.nodes[ny][nx] if nxt_node.visited_by == CSOURCE: if rec: rec.append(('CLOSE', (nx, ny))) self._retrace((nx, ny), (x, y)) self.success = True return nxt_node.visited_by = CTARGET nxt_node.h = node.h + DIST nxt_node.parent = (x, y) heappush(self.queue_target, (nxt_node.h, (nx, ny))) if rec != None: rec.append(('OPEN', (nx, ny))) rec.append(('VALUE', ('h', (nx, ny), nxt_node.h))) rec.append(('PARENT', ((nx, ny), (x, y)))) # further investigate the diagonal nodes for i in diagonal_can: nx1 = x + DAXOFFSET[i] ny1 = y + DAYOFFSET[i] nx2 = x + DBXOFFSET[i] ny2 = y + DBYOFFSET[i] npos = ((nx1, ny1), (nx2, ny2)) for nx, ny in npos: if is_walkable(nx, ny, self.n_row, self.n_col, self.graph) and \ self.nodes[ny][nx].visited_by != CTARGET: nxt_node = self.nodes[ny][nx] if nxt_node.visited_by == CSOURCE: if rec: rec.append(('CLOSE', (nx, ny))) self._retrace((nx, ny), (x, y)) self.success = True return nxt_node.visited_by = CTARGET nxt_node.h = node.h + DDIST nxt_node.parent = (x, y) heappush(self.queue_target, (nxt_node.h, (nx, ny))) if rec != None: rec.append(('OPEN', (nx, ny))) rec.append(('VALUE', ('h', (nx, ny), nxt_node.h))) rec.append(('PARENT', ((nx, ny), (x, y))))
def _expand_source(self, rec): """Searches from the source. Until it meets a node which has been visited by the other tree. """ # take the first node from the source queue v, (x, y) = heappop(self.queue_source) node = self.nodes[y][x] diagonal_can = [] # stores the diagonal positions that can be accessed if rec != None: rec.append(('CLOSE', (x, y))) # inspect horizontally and vertically adjacent nodes for i in xrange(len(XOFFSET)): nx = x + XOFFSET[i] ny = y + YOFFSET[i] if is_walkable(nx, ny, self.n_row, self.n_col, self.graph): # if this node can be accessed, then then correponding # diagonal node can be accessed. diagonal_can.append(i) nxt_node = self.nodes[ny][nx] # if this node has been visited by source queue before, # then there's no need to inspect it again. if nxt_node.visited_by == CSOURCE: continue # if this node has been visited by *target* queue. # Then a path from source to target exists. # Reconstructs the path and return. if nxt_node.visited_by == CTARGET: if rec: rec.append(('CLOSE', (nx, ny))) self._retrace((x, y), (nx, ny)) self.success = True return # mark this node and update its info, then push the node # into the source queue nxt_node.visited_by = CSOURCE nxt_node.g = node.g + DIST nxt_node.parent = (x, y) heappush(self.queue_source, (nxt_node.g, (nx, ny))) if rec != None: rec.append(('OPEN', (nx, ny))) rec.append(('VALUE', ('g', (nx, ny), nxt_node.g))) rec.append(('PARENT', ((nx, ny), (x, y)))) # further investigate the diagonal nodes, the procedure is identical # with above for i in diagonal_can: nx1 = x + DAXOFFSET[i] ny1 = y + DAYOFFSET[i] nx2 = x + DBXOFFSET[i] ny2 = y + DBYOFFSET[i] npos = ((nx1, ny1), (nx2, ny2)) for nx, ny in npos: if is_walkable(nx, ny, self.n_row, self.n_col, self.graph) and \ self.nodes[ny][nx].visited_by != CSOURCE: nxt_node = self.nodes[ny][nx] if nxt_node.visited_by == CTARGET: if rec: rec.append(('CLOSE', (nx, ny))) self._retrace((x, y), (nx, ny)) self.success = True return nxt_node.visited_by = CSOURCE nxt_node.g = node.g + DDIST nxt_node.parent = (x, y) heappush(self.queue_source, (nxt_node.g, (nx, ny))) if rec != None: rec.append(('OPEN', (nx, ny))) rec.append(('VALUE', ('g', (nx, ny), nxt_node.g))) rec.append(('PARENT', ((nx, ny), (x, y))))