Skip to content

Commit ccbe55e

Browse files
authored
add dijkstra pathfinding algorithm (#359)
1 parent 84f545b commit ccbe55e

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

Python/dijkstra.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
class Position:
2+
def __init__(self, north = False, east = False, south = False, west = False, exit = False):
3+
self.north = north
4+
self.east = east
5+
self.south = south
6+
self.west = west
7+
self.exit = exit
8+
9+
def get_maze_size(maze):
10+
try:
11+
height = len(maze)
12+
width = len(maze[0])
13+
return (height, width)
14+
except IndexError:
15+
return (0, 0)
16+
17+
# returns (y, x), index is 0-3 referencing north-west
18+
def get_offset(index):
19+
return [
20+
(-1, 0), # north
21+
(0, 1), # east
22+
(1, 0), # south
23+
(0, -1) # west
24+
][index]
25+
26+
# the opposite direction's index
27+
def get_opposite_index(index):
28+
return [2, 3, 0, 1][index]
29+
30+
def get_direction(index):
31+
return ["north", "east", "south", "west"][index]
32+
33+
# the "closed list"
34+
def create_unavailable_grid(height, width):
35+
# False if empty, True if occupied
36+
return [[False for x in range(width)] for y in range(height)]
37+
38+
# the parent of a node (at its position)
39+
def create_parent_grid(height, width):
40+
return [[None for x in range(width)] for y in range(height)]
41+
42+
def escape_route(maze):
43+
final = []
44+
45+
# check if the maze has valid dimensions
46+
height, width = get_maze_size(maze)
47+
if height < 1 or width < 1:
48+
return None
49+
50+
# create status tracking lists
51+
y, x = 0, 0
52+
parent = create_parent_grid(height, width)
53+
unavailable = create_unavailable_grid(height, width)
54+
55+
# initialise lists with current node
56+
available = [ # the "open list"
57+
[], # y positions
58+
[] # x positions
59+
]
60+
unavailable[y][x] = True
61+
62+
# find a path to the exit
63+
while not maze[y][x].exit:
64+
# mark adjacent nodes as available
65+
current = maze[y][x]
66+
directions = [
67+
current.north,
68+
current.east,
69+
current.south,
70+
current.west
71+
]
72+
for index in range(4):
73+
if directions[index]:
74+
yo, xo = get_offset(index)
75+
yn, xn = (y + yo), (x + xo)
76+
if not unavailable[yn][xn]:
77+
available[0].append(yn)
78+
available[1].append(xn)
79+
parent[yn][xn] = get_opposite_index(index)
80+
81+
# mark the current node as unavailable
82+
unavailable[y][x] = True
83+
84+
# ran out of positions to move to
85+
if len(available[0]) < 1 or len(available[1]) < 1:
86+
return None
87+
88+
# get the next available node
89+
y, x = available[0].pop(0), available[1].pop(0)
90+
91+
# backtrack current node to get the path
92+
while parent[y][x] is not None:
93+
index = get_opposite_index(parent[y][x])
94+
final.insert(0, get_direction(index))
95+
# reference the next parent
96+
yo, xo = get_offset(parent[y][x])
97+
y, x = (y + yo), (x + xo)
98+
99+
return final
100+
101+
def can_escape(maze):
102+
return escape_route(maze) is not None
103+
104+
def create_maze(height, width):
105+
return [[None for x in range(width)] for y in range(height)]
106+
107+
if __name__ == "__main__":
108+
maze = create_maze(2, 2)
109+
maze[0][0] = Position(False, True, False, False, False)
110+
maze[0][1] = Position(False, False, True, False, False)
111+
maze[1][1] = Position(False, False, False, True, False)
112+
maze[1][0] = Position(False, False, False, True, True)
113+
path = escape_route(maze)
114+
print(path)
115+
116+

0 commit comments

Comments
 (0)