How to find the shortest path between two coordinates in a 2-dimensional array?

Question:

I am trying to find the shortest way to get from one point in a 2D array (one coordinate with x and y values representing its position in the array) to another.

I would like to output an array of coordinates which must be travelled through to get from the initial to the final coordinates.

One example of an array like this could be:

arr = [
          [0, 1, 2],
          [3, 4, 5],
          [6, 7, 8]
      ]

In this case, we can say that we will begin at arr[0][0] and end at arr[2][2]. Thus, the coordinates would be (0, 0) and (2, 2).

So, for example, if we take our starting coordinate to be (0, 2) and our ending one to be (2, 1), the expected output would be [(0, 2), (1, 2), (2, 2), (2, 1)] (or something of the same length).


What I tried

I managed to make a semi-successful function below, but it is very inefficient and time-consuming in larger cases.

import math

arr = [
          [0, 1, 2],
          [3, 4, 5],
          [6, 7, 8]
      ]

coor1 = (0, 0) # seen as 2 in the arr array
coor2 = (2, 2) # seen as 7 in the arr array

def pythagoras(a, b):

    # find pythagorean distances between the two
    distance_y = max(a[0], b[0]) - min(a[0], b[0])
    distance_x = max(a[1], b[1]) - min(a[1], b[1])

    # calculate pythagorean distance to 3 d.p.
    pythag_distance = round(math.sqrt(distance_x**2 + distance_y**2), 3)

    return pythag_distance


def find_shortest_path(arr, position, target):
    ''' finds shortest path between two coordinates, can't go diagonally '''
    coordinates_for_distances = []
    distances = []

    for i in range(len(arr)):
        for r in range(len(arr)):
            coordinates_for_distances.append((i, r))
            distances.append(pythagoras((i, r), target))

    route = []

    while position != target:
        acceptable_y_range = [position[1] + 1, position[1] - 1]
        acceptable_x_range = [position[0] + 1, position[0] - 1]

        possibilities = []
        distance_possibilities = []

        for i in range(len(coordinates_for_distances)):
            if coordinates_for_distances[i][0] == position[0] and coordinates_for_distances[i][1] in acceptable_y_range:
                possibilities.append(coordinates_for_distances[i])
                distance_possibilities.append(distances[i])

            elif coordinates_for_distances[i][1] == position[1] and coordinates_for_distances[i][0] in acceptable_x_range:
                possibilities.append(coordinates_for_distances[i])
                distance_possibilities.append(distances[i])

        zipped_lists = zip(distance_possibilities, possibilities)
        minimum = min(zipped_lists)
        position = minimum[1]
        route.append(position)

    return route
Asked By: Destaq

||

Answers:

In order to find the shortest path between a pair of coordinates, we can translate this to a graph problem, in which each coordinate is a graph node. Now under this setting, finding the shortest paths between two nodes is a well known graph theory problem, and is fairly easy to solve with the right tools.

We can use NetworkX, which actually has a Graph generator, that returns the 2d grid graph of mxn nodes, each being connected to its nearest neighbors. Which is perfect for out case:

import networkx as nx
from matplotlib import pyplot as plt

G = nx.grid_2d_graph(3,3)

plt.figure(figsize=(6,6))
pos = {(x,y):(y,-x) for x,y in G.nodes()}
nx.draw(G, pos=pos, 
        node_color='lightgreen', 
        with_labels=True,
        node_size=600)

                  enter image description here

Now we can use networkX’s nx.bidirectional_shortest_path to find the shortest path between both coordinates:

coor1 = (0, 2) # seen as 2 in the arr array
coor2 = (2, 1) # seen as 7 in the arr array

nx.bidirectional_shortest_path(G, source=coor1, target=coor2)
# [(0, 2), (1, 2), (2, 2), (2, 1)]

Note that nx.grid_2d_graph will generate grid graphs with up to an arbitrarily large m and n, an by positioning the labels you can also plot the grid of coordinates just as above:

                    enter image description here

Answered By: yatu