def calculate(start: tuple, goal: tuple, grid: utils.Grid = utils.Grid()):
    """ Finds path from start to goal using the Bidirectional Search algorithm.

    NOT FUNCTIONAL YET

    Starts to search from both start and goal simultaneously, performing Breadth-First search at both ends,
    until the two searches intersect.

    :param start: A tuple representing the starting point, e.g. (0, 0).
    :param goal: A tuple representing the goal point, e.g. (10, 10).
    :param grid: A Grid object representing the space where start and goal are located, optional.
    """

    queue_start, queue_goal = deque([start]), deque([goal])

    visited = [start, goal]

    child_parent_pairs = dict()

    found_path = False

    intersect_point = None

    while queue_start and queue_goal and not found_path:

        for i, [q, q_other] in enumerate(
                zip([queue_start, queue_goal], [queue_goal, queue_start])):
            if q:
                x = q.pop()
                if x == [goal, start][i] or x in q_other:
                    # success
                    found_path = True
                    intersect_point = x
                    print("intersect_point", intersect_point, flush=True)
                    # break
                for neighbor in grid.get_point_neighbors(x):
                    if neighbor not in visited:
                        visited.append(neighbor)
                        q.appendleft(neighbor)
                        child_parent_pairs[neighbor] = x

                        # if i == 0:
                        #     child_parent_pairs[neighbor] = x
                        # else:
                        #     child_parent_pairs[x] = neighbor

    start_to_intersect = utils.calculate_path(intersect_point, start,
                                              child_parent_pairs)
    goal_to_intersect = utils.calculate_path(goal, intersect_point,
                                             child_parent_pairs)

    path = start_to_intersect.extend(reversed(goal_to_intersect[:-1]))
    print(path)
    return {
        "path": path,
        "visited": visited,
        "grid": grid.to_ndarray(),
        "start": start,
        "goal": goal
    }
Beispiel #2
0
    def __init__(self, record=False):
        QtWidgets.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)
        self.scene = QtWidgets.QGraphicsScene()

        # Buttons
        self.runPathFinding.clicked.connect(self.run_algorithm)
        self.setCoordinates.clicked.connect(self.show_coordinates)
        self.setRandomCoordinates.clicked.connect(self.random_coordinates)
        self.generateMaze.clicked.connect(self.generate_maze)
        self.runPathFinding.setEnabled(False)
        self.startXValue.setPlainText("0")
        self.startYValue.setPlainText("0")
        self.goalXValue.setPlainText(str(GRIDSIZE - 1))
        self.goalYValue.setPlainText(str(GRIDSIZE - 1))

        # Combobox
        for algorithm in ALGORITHMS.keys():
            self.chooseAlgorithm.addItem(algorithm)

        self.maze = False
        self.grid = utils.Grid()

        # GridDraw
        self.draw_grid(self.scene, penGrid, SIDE)

        # For recording UI for demo GIFs
        self.record = record
        self.frame = QImage(int(self.scene.sceneRect().width()),
                            int(self.scene.sceneRect().height()),
                            QImage.Format_ARGB32_Premultiplied)
        self.painter = QPainter(self.frame)
Beispiel #3
0
def main():
    # the code here is just for testing, the program can just call calculate() above and skip this
    grid = utils.Grid(size=19, create_maze=True)

    res = calculate(grid=grid, start=(0, 0), goal=(18, 18))

    # the following allows visualizing results in the terminal (thus only works when script is run from the terminal)
    utils.visualize_asciimatics(res)
Beispiel #4
0
def calculate(start: tuple, goal: tuple, grid: utils.Grid = utils.Grid()):
    """ Finds path from start to goal using Dijkstra's algorithm.

    Implementation of this algorithm was based on the example provided in Wikipedia:
    https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm#Pseudocode

    :param start: A tuple representing the starting point, e.g. (0, 0).
    :param goal: A tuple representing the goal point, e.g. (10, 10).
    :param grid: A Grid object representing the space where start and goal are located, optional.
    """

    pq = utils.PriorityQueue()
    distances = dict()
    child_parent_pairs = dict()
    visited = []

    # add all points in grid to priority queue with infinite distances and no parents
    for y, x in np.ndindex(grid.to_ndarray().shape):
        distances[(y, x)] = math.inf
        child_parent_pairs[(y, x)] = ""
        pq.add_point((y, x), math.inf)

    # update starting point's distance and priority to 0
    distances[start] = 0
    pq.add_point(start, priority=0)

    while pq.has_points():
        # get point with lowest priority and remove from queue
        current_point = pq.get_lowest_priority_point()
        visited.append(current_point)

        if current_point == goal:
            # goal has been reached
            break

        for neighbor in grid.get_point_neighbors(current_point):
            if pq.contains_point(neighbor):

                # neighbors always 1 step away from current
                alt_distance = distances[current_point] + 1

                if alt_distance < distances[neighbor]:
                    distances[neighbor] = alt_distance
                    # update neighbor's priority with new distance
                    pq.add_point(neighbor, alt_distance)
                    child_parent_pairs[neighbor] = current_point

    path = utils.calculate_path(start, goal, child_parent_pairs)

    return {
        "path": path,
        "visited": visited,
        "grid": grid.to_ndarray(),
        "start": start,
        "goal": goal
    }
def main():
    # grid = utils.new_grid(20)
    #
    # grid[:17, 4] = "+"
    # grid[1, 1:9] = "+"
    # grid[10, 6:18] = "+"
    # grid[10:, 7] = "+"

    # the code here is just for testing, the program can just call calculate() above and skip this
    grid = utils.Grid(size=3)

    res = calculate(grid=grid, start=(0, 0), goal=(2, 2))

    # the following allows visualizing results in the terminal (thus only works when script is run from the terminal)
    utils.visualize_asciimatics(res)
def calculate(start: tuple, goal: tuple, grid: utils.Grid = utils.Grid()):
    """ Finds path from start to goal using the Depth-First Search algorithm.

    Works by creating a double ended queue (deque) - by always appending to the **right** of the queue,
    and then considering the **right-most** points in the queue first, the deque essentially works as a LIFO
    queue/stack.

    :param start: A tuple representing the starting point, e.g. (0, 0).
    :param goal: A tuple representing the goal point, e.g. (10, 10).
    :param grid: A Grid object representing the space where start and goal are located, optional.
    """

    queue = deque([start])

    visited = []

    child_parent_pairs = dict()

    while queue:  # stops when all points have been considered or when goal is reached

        current_point = queue.pop()  # get right-most point in queue

        visited.append(current_point)  # mark point as visited

        if current_point == goal:
            # goal has been reached
            # do not return from here, by returning below the case where no path is found is captured
            break

        for neighbor in grid.get_point_neighbors(current_point):
            if neighbor not in visited:  # check if already visited this point
                queue.append(neighbor)  # append to the right of the queue
                child_parent_pairs[neighbor] = current_point

    path = utils.calculate_path(start, goal, child_parent_pairs)

    return {
        "path": path,
        "visited": visited,
        "grid": grid.to_ndarray(),
        "start": start,
        "goal": goal
    }
Beispiel #7
0
 def generate_maze(self):
     self.runPathFinding.setEnabled(False)
     window.setCoordinates.setEnabled(False)
     window.setRandomCoordinates.setEnabled(False)
     window.generateMaze.setEnabled(False)
     self.maze = True
     self.grid = utils.Grid(create_maze=True,
                            size=GRIDSIZE,
                            random_seed=42 if self.record else None)
     for y in range(GRIDSIZE):
         for x in range(GRIDSIZE):
             self.scene.addRect(x * SIDE, y * SIDE, 10, 10, penPoint,
                                wallBrush)
     for i, (x, y) in enumerate(self.grid.get_maze_history()):
         QtTest.QTest.qWait(2)
         self.scene.addRect(x * SIDE, y * SIDE, 10, 10, penPoint, gridBrush)
         if self.record:
             self.render_and_save_frame(i, "maze")
     window.setRandomCoordinates.setEnabled(True)
def calculate(start: tuple, goal: tuple, grid: utils.Grid = utils.Grid(), heuristic: str = "manhattan"):
    """ Finds path from start to goal using the A* algorithm.

    Implementation of this algorithm was based on the example provided in Wikipedia:
    https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode

    :param start: A tuple representing the starting point, e.g. (0, 0).
    :param goal: A tuple representing the goal point, e.g. (10, 10).
    :param grid: A Grid object representing the space where start and goal are located, optional.
    :param heuristic: The heuristic the algorithm will use, defaults to the Manhattan distance. Currently options
     "manhattan" and "euclidean" are supported.
    """

    if heuristic == "manhattan":
        h_score = heuristics.manhattan_distance
    elif heuristic == "euclidean":
        h_score = heuristics.euclidean_distance
    else:
        raise NameError("Heuristic name provided not applicable/erroneous.")

    visited = []

    child_parent_pairs = dict()

    g_scores = dict()
    g_scores[start] = 0

    f_scores = dict()  # the f_score is calculated by f(n) = g(n) + h(n)
    f_scores[start] = g_scores[start] + \
                      h_score(start, goal)  # the g_score of start is 0

    # create a priority queue, and add start to it; priority in A* corresponds to the fScore, and the points with
    # lowest fScores are considered first
    pq = utils.PriorityQueue()
    pq.add_point(start, f_scores[start])

    while pq.has_points():
        # get point with lowest priority and remove from queue
        current_point = pq.get_lowest_priority_point()

        visited.append(current_point)

        if current_point == goal:
            # goal has been reached
            # do not return from here, by returning below the case where no path is found is captured
            break

        for neighbor in grid.get_point_neighbors(current_point):
            # neighbors always 1 step away from current
            tentative_g_score = g_scores[current_point] + 1
            if neighbor in g_scores and g_scores[neighbor] < tentative_g_score:
                # neighbor already reached from another point that resulted in a lower g_score, so skip it
                continue

            # path to this neighbor is better than any previous, so record it
            child_parent_pairs[neighbor] = current_point
            g_scores[neighbor] = tentative_g_score
            f_scores[neighbor] = tentative_g_score + h_score(neighbor, goal)
            pq.add_point(neighbor, f_scores[neighbor])

    path = utils.calculate_path(start, goal, child_parent_pairs)

    return {"path": path, "visited": visited, "grid": grid.to_ndarray(), "start": start, "goal": goal}