Skip to content

Commit 47a9932

Browse files
A* Searching Algorithm Added
1 parent 40f65e8 commit 47a9932

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed

searches/A_star_search.py

+232
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# Python program for A* Search Algorithm
2+
import math
3+
import heapq
4+
from typing import List, Tuple
5+
6+
# Define the Cell class
7+
8+
9+
class Cell:
10+
def __init__(self)->None:
11+
# Parent cell's row index
12+
self.parent_i = 0
13+
# Parent cell's column index
14+
self.parent_j = 0
15+
# Total cost of the cell (g + h)
16+
self.f = float("inf")
17+
# Cost from start to this cell
18+
self.g = float("inf")
19+
# Heuristic cost from this cell to destination
20+
self.h = 0
21+
22+
23+
# Define the size of the grid
24+
ROW = 9
25+
COL = 10
26+
27+
# Check if a cell is valid (within the grid)
28+
29+
30+
def is_valid(row: int, col: int) -> bool:
31+
return (row >= 0) and (row < ROW) and (col >= 0) and (col < COL)
32+
33+
34+
# Check if a cell is unblocked
35+
36+
37+
def is_unblocked(grid: List[List[int]], row: int, col: int) -> bool:
38+
return grid[row][col] == 1
39+
40+
41+
# Check if a cell is the destination
42+
43+
44+
def is_destination(row: int, col: int, dest: Tuple[int, int]) -> bool:
45+
return row == dest[0] and col == dest[1]
46+
47+
48+
# Calculate the heuristic value of a cell (Euclidean distance to destination)
49+
50+
51+
def calculate_h_value(row: int, col: int, dest: Tuple[int, int]) -> float:
52+
return ((row - dest[0]) ** 2 + (col - dest[1]) ** 2) ** 0.5
53+
54+
55+
# Trace the path from source to destination
56+
57+
58+
def trace_path(cell_details: List[List[Cell]], dest: Tuple[int, int]) -> None:
59+
print("The Path is ")
60+
path = []
61+
row = dest[0]
62+
col = dest[1]
63+
64+
# Trace the path from destination to source using parent cells
65+
while not (
66+
cell_details[row][col].parent_i == row
67+
and cell_details[row][col].parent_j == col
68+
):
69+
path.append((row, col))
70+
temp_row = cell_details[row][col].parent_i
71+
temp_col = cell_details[row][col].parent_j
72+
row = temp_row
73+
col = temp_col
74+
75+
# Add the source cell to the path
76+
path.append((row, col))
77+
# Reverse the path to get the path from source to destination
78+
path.reverse()
79+
80+
# Print the path
81+
for i in path:
82+
print("->", i, end=" ")
83+
print()
84+
85+
86+
# Implement the A* search algorithm
87+
88+
89+
def a_star_search(grid: List[List[int]], src: Tuple[int, int], dest: Tuple[int, int]) -> None:
90+
# Check if the source and destination are valid
91+
if not is_valid(src[0], src[1]) or not is_valid(dest[0], dest[1]):
92+
print("Source or destination is invalid")
93+
return
94+
95+
# Check if the source and destination are unblocked
96+
if not is_unblocked(grid, src[0], src[1]) or not is_unblocked(
97+
grid, dest[0], dest[1]
98+
):
99+
print("Source or the destination is blocked")
100+
return
101+
102+
# Check if we are already at the destination
103+
if is_destination(src[0], src[1], dest):
104+
print("We are already at the destination")
105+
return
106+
107+
# Initialize the closed list (visited cells)
108+
closed_list = [[False for _ in range(COL)] for _ in range(ROW)]
109+
# Initialize the details of each cell
110+
cell_details = [[Cell() for _ in range(COL)] for _ in range(ROW)]
111+
112+
# Initialize the start cell details
113+
i = src[0]
114+
j = src[1]
115+
cell_details[i][j].f = 0
116+
cell_details[i][j].g = 0
117+
cell_details[i][j].h = 0
118+
cell_details[i][j].parent_i = i
119+
cell_details[i][j].parent_j = j
120+
121+
# Initialize the open list (cells to be visited) with the start cell
122+
open_list = []
123+
heapq.heappush(open_list, (0.0, i, j))
124+
125+
# Initialize the flag for whether destination is found
126+
found_dest = False
127+
128+
# Main loop of A* search algorithm
129+
while len(open_list) > 0:
130+
# Pop the cell with the smallest f value from the open list
131+
p = heapq.heappop(open_list)
132+
133+
# Mark the cell as visited
134+
i = p[1]
135+
j = p[2]
136+
closed_list[i][j] = True
137+
138+
# For each direction, check the successors
139+
directions = [
140+
(0, 1),
141+
(0, -1),
142+
(1, 0),
143+
(-1, 0),
144+
(1, 1),
145+
(1, -1),
146+
(-1, 1),
147+
(-1, -1),
148+
]
149+
for dir in directions:
150+
new_i = i + dir[0]
151+
new_j = j + dir[1]
152+
153+
# If the successor is valid, unblocked, and not visited
154+
if (
155+
is_valid(new_i, new_j)
156+
and is_unblocked(grid, new_i, new_j)
157+
and not closed_list[new_i][new_j]
158+
):
159+
# If the successor is the destination
160+
if is_destination(new_i, new_j, dest):
161+
# Set the parent of the destination cell
162+
cell_details[new_i][new_j].parent_i = i
163+
cell_details[new_i][new_j].parent_j = j
164+
print("The destination cell is found")
165+
# Trace and print the path from source to destination
166+
trace_path(cell_details, dest)
167+
found_dest = True
168+
return
169+
else:
170+
# Calculate the new f, g, and h values
171+
g_new = cell_details[i][j].g + 1.0
172+
h_new = calculate_h_value(new_i, new_j, dest)
173+
f_new = g_new + h_new
174+
175+
# If the cell is not in the open list or the new f value is smaller
176+
if (
177+
cell_details[new_i][new_j].f == float("inf")
178+
or cell_details[new_i][new_j].f > f_new
179+
):
180+
# Add the cell to the open list
181+
heapq.heappush(open_list, (f_new, new_i, new_j))
182+
# Update the cell details
183+
cell_details[new_i][new_j].f = f_new
184+
cell_details[new_i][new_j].g = g_new
185+
cell_details[new_i][new_j].h = h_new
186+
cell_details[new_i][new_j].parent_i = i
187+
cell_details[new_i][new_j].parent_j = j
188+
189+
# If the destination is not found after visiting all cells
190+
if not found_dest:
191+
print("Failed to find the destination cell")
192+
193+
194+
# Driver Code
195+
196+
197+
def main() -> None:
198+
"""
199+
Run the A* search algorithm on a predefined grid.
200+
201+
Returns:
202+
None
203+
204+
Examples:
205+
>>> main()
206+
The destination cell is found
207+
The Path is
208+
-> (8, 0) -> (7, 1) -> (6, 0) -> (5, 1) -> (4, 0) -> (3, 1) -> (2, 0) -> (1, 1) -> (0, 0)
209+
"""
210+
# Define the grid (1 for unblocked, 0 for blocked)
211+
grid = [
212+
[1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
213+
[1, 1, 1, 0, 1, 1, 1, 0, 1, 1],
214+
[1, 1, 1, 0, 1, 1, 0, 1, 0, 1],
215+
[0, 0, 1, 0, 1, 0, 0, 0, 0, 1],
216+
[1, 1, 1, 0, 1, 1, 1, 0, 1, 0],
217+
[1, 0, 1, 1, 1, 1, 0, 1, 0, 0],
218+
[1, 0, 0, 0, 0, 1, 0, 0, 0, 1],
219+
[1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
220+
[1, 1, 1, 0, 0, 0, 1, 0, 0, 1],
221+
]
222+
223+
# Define the source and destination
224+
src = (8, 0)
225+
dest = (0, 0)
226+
227+
# Run the A* search algorithm
228+
a_star_search(grid, src, dest)
229+
230+
if __name__ == "__main__":
231+
main()
232+

0 commit comments

Comments
 (0)