Skip to content

Commit fa30b67

Browse files
authored
Create Puzzle.py
1 parent 6b4bcfd commit fa30b67

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

Puzzle.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import heapq
2+
3+
4+
def solve_puzzle(Board, Source, Destination):
5+
"""
6+
Finds and returns the path that covers the minimum number of cells of a
7+
puzzle traveling from the source to the destination cell.
8+
:param Board: Puzzle board as a list of lists. Each list represents a row
9+
in the puzzle. Each element is either ‘-’ for an empty cell
10+
(passable) or ‘#’ for an obstacle (impassable)
11+
:param Source: Tuple representing the indices of the starting position
12+
:param Destination: Tuple representing the indices of the goal position
13+
:return: List of tuples representing the indices of each position in the
14+
solution path, plus a string representing the directions taken
15+
"""
16+
# Handle edge case if Source is also the Destination cell
17+
if Source == Destination:
18+
return [Source]
19+
20+
# Use dictionary (initialized with Source cell) to store puzzle cells as
21+
# the keys and the value as a list of [min path distance from source to
22+
# cell, list of indices in the min distance path, and string of directions]
23+
min_path_dict = {Source: [0, [Source], '']}
24+
25+
# use priority queue to track the min distance path starting with Source
26+
pq = [(0, Source)]
27+
28+
while len(pq) > 0:
29+
# pop cell from priority queue that keeps path with overall min distance
30+
min_path, cell = heapq.heappop(pq)
31+
32+
# find all valid neighbors of popped cell using helper function
33+
neighbors = find_neighbors(Board, cell)
34+
35+
# for each neighbor, update min_path_dict if necessary
36+
for neighbor, direction in neighbors:
37+
# min distance from source to current cell is popped min_path + 1
38+
path_dist = min_path + 1
39+
40+
# update dict if neighbor not in dict or path_distance is smaller
41+
if neighbor not in min_path_dict or path_dist < min_path_dict[neighbor][0]:
42+
# create copy of path list of indices and append current cell
43+
path = min_path_dict[cell][1].copy()
44+
path.append(neighbor)
45+
46+
# append the direction to the directions string
47+
directions = min_path_dict[cell][2] + direction
48+
min_path_dict[neighbor] = [path_dist, path, directions]
49+
50+
# if Destination is reached, return relevant list slice of dict
51+
if neighbor == Destination:
52+
return min_path_dict[neighbor][1:]
53+
54+
# update the priority queue
55+
heapq.heappush(pq, (min_path_dict[neighbor][0], neighbor))
56+
57+
# if Destination is not reached, return None
58+
return None
59+
60+
61+
def find_neighbors(puzzle, cell):
62+
"""
63+
Finds and returns all valid neighbors of a cell in given puzzle
64+
:param puzzle: Puzzle board as a list of lists
65+
:param cell: Cell that we want to find all valid neighbors
66+
:return: List that includes indices of neighbor and its direction
67+
"""
68+
row = cell[0]
69+
col = cell[1]
70+
neighbors = []
71+
72+
# left move possible if col index is greater than 0 and cell is not '#'
73+
if col > 0 and puzzle[row][col - 1] != '#':
74+
neighbors.append(((row, col - 1), 'L'))
75+
76+
# up move possible if row index is greater than 0 and cell is not '#'
77+
if row > 0 and puzzle[row - 1][col] != '#':
78+
neighbors.append(((row - 1, col), 'U'))
79+
80+
# right move possible if col index is less than puzzle width - 1
81+
if col < len(puzzle[0]) - 1 and puzzle[row][col + 1] != '#':
82+
neighbors.append(((row, col + 1), 'R'))
83+
84+
# down move possible if row index is less than puzzle height - 1
85+
if row < len(puzzle) - 1 and puzzle[row + 1][col] != '#':
86+
neighbors.append(((row + 1, col), 'D'))
87+
88+
return neighbors

0 commit comments

Comments
 (0)