Skip to content

Commit c96dbf5

Browse files
Merge pull request avinashkranjan#499 from SpecTEviL/Shortest-Path-finder-GSSoC'21
Added the Shortest Path Finder gssoc'21
2 parents 96b63bf + fc5d543 commit c96dbf5

File tree

5 files changed

+292
-0
lines changed

5 files changed

+292
-0
lines changed
91.1 KB
Loading
91.3 KB
Loading
91.5 KB
Loading
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Shortest Path Finder (GUI)
2+
3+
Shortest Path finder is a GUI application which finds the shortest possible path between two points placed by the user on the board. The shortest path is marked with "Purple" colour. The program also shows the area of the board tracked by the algorithm in "Red" colour to find the shortest path. The "Green" border represents the border of the area tracked. The user can create obstacles simply by clicking on the cell on the board which is represented by "Black" colour. The start point is marked with "Yellow" colour and the end point is marked with "Sky Blue" colour.
4+
5+
## Setup instructions
6+
7+
In order to run this script, You just need the following modules:
8+
9+
- **Pygame:** It is a set of Python modules designed for writing video games.
10+
```bash
11+
pip install pygame
12+
```
13+
14+
## Controls
15+
- Click on boxes to mark start(Yellow Coloured) and end point(Sky Blue Coloured).
16+
- Then make some obstacles(Black Coloured).
17+
- Then finally press "SPACE" to find the shortest path between the start and end point.
18+
- The shortest path is represented by "Purple
19+
20+
## Screenshots
21+
22+
<p align="center">
23+
<img src="https://github.com/SpecTEviL/Amazing-Python-Scripts/blob/Shortest-Path-finder-GSSoC'21/Shortest-Path-Finder%20(GUI)/1.%20Marked%20Start%20and%20End%20Point.png" alt="1. Marked Start and End Point.png"/>
24+
<br>
25+
1. Marked Start and End Point
26+
</p>
27+
<p align="center">
28+
<img src="https://github.com/SpecTEviL/Amazing-Python-Scripts/blob/Shortest-Path-finder-GSSoC'21/Shortest-Path-Finder%20(GUI)/2.%20Made%20Obstacles.png" alt="2. Made Obstacles.png"/>
29+
<br>
30+
2. Made the Obstacles
31+
</p>
32+
<p align="center">
33+
<img src="https://github.com/SpecTEviL/Amazing-Python-Scripts/blob/Shortest-Path-finder-GSSoC'21/Shortest-Path-Finder%20(GUI)/3.%20Shortest%20Path%20marked%20in%20Purple%20by%20the%20Algorithm.png" alt="3. Shortest Path marked in Purple by the Algorithm.png"/>
34+
<br>
35+
3. Shortest Path marked in Purple by the Algorithm
36+
</p>
37+
38+
## Author
39+
40+
[Vishal Patil](https://github.com/SpecTEviL)
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# Click on boxes to mark start and end point. Then make some obstacles and once done
2+
# press SPACE to find the shortest path between the start and end point
3+
4+
import pygame as pg
5+
import math
6+
from queue import PriorityQueue
7+
8+
9+
WIDTH = 595
10+
WIN = pg.display.set_mode((WIDTH, WIDTH))
11+
pg.display.set_caption("Shortest Path Finder")
12+
13+
RED = (255, 0, 0)
14+
GREEN = (0, 255, 0)
15+
BLUE = (0, 0, 255)
16+
YELLOW = (255, 255, 0)
17+
WHITE = (255, 255, 255)
18+
BLACK = (0, 0, 0)
19+
GREY = (128, 128, 128)
20+
TURQUOISE = (64, 244, 208)
21+
ORANGE = (255, 165, 0)
22+
PURPLE = (128, 0, 128)
23+
24+
25+
class Spot:
26+
def __init__(self, row, col, width, total_rows):
27+
self.row = row
28+
self.col = col
29+
self.x = row * width
30+
self.y = col * width
31+
self.color = WHITE
32+
self.neighbour = []
33+
self.width = width
34+
self.total_rows = total_rows
35+
36+
def get_pos(self):
37+
return self.row, self.col
38+
39+
def is_closed(self):
40+
return self.color == RED
41+
42+
def is_open(self):
43+
return self.color == GREEN
44+
45+
def is_barrier(self):
46+
return self.color == BLACK
47+
48+
def is_start(self):
49+
return self.color == ORANGE
50+
51+
def is_end(self):
52+
return self.color == TURQUOISE
53+
54+
def reset(self):
55+
self.color = WHITE
56+
57+
def make_closed(self):
58+
self.color = RED
59+
60+
def make_open(self):
61+
self.color = GREEN
62+
63+
def make_barrier(self):
64+
self.color = BLACK
65+
66+
def make_start(self):
67+
self.color = ORANGE
68+
69+
def make_end(self):
70+
self.color = TURQUOISE
71+
72+
def make_path(self):
73+
self.color = PURPLE
74+
75+
def draw(self, win):
76+
pg.draw.rect(win, self.color, (self.x, self.y, self.width, self.width))
77+
78+
def update_neighbour(self, grid):
79+
self.neighbours = []
80+
if self.row < self.total_rows - 1 and not grid[self.row + 1][self.col].is_barrier(): # down
81+
self.neighbours.append(grid[self.row + 1][self.col])
82+
83+
if self.row > 0 and not grid[self.row - 1][self.col].is_barrier(): # up
84+
self.neighbours.append(grid[self.row - 1][self.col])
85+
86+
if self.col < self.total_rows - 1 and not grid[self.row][self.col + 1].is_barrier(): # right
87+
self.neighbours.append(grid[self.row][self.col + 1])
88+
89+
if self.col > 0 and not grid[self.row][self.col - 1].is_barrier(): # left
90+
self.neighbours.append(grid[self.row][self.col - 1])
91+
92+
93+
94+
def __lt__(self, other):
95+
return False
96+
97+
98+
def h(p1, p2):
99+
x1, y1 = p1
100+
x2, y2 = p2
101+
return abs(x1 - x2) + abs(y1 - y2)
102+
103+
104+
def reconstruct_path(came_from, current, draw):
105+
while current in came_from:
106+
current = came_from[current]
107+
current.make_path()
108+
draw()
109+
110+
111+
def algorithm(draw, grid, start, end):
112+
count = 0
113+
open_set = PriorityQueue()
114+
open_set.put((0, count, start))
115+
came_from = {}
116+
g_score = {spot: float("inf") for row in grid for spot in row}
117+
g_score[start] = 0
118+
f_score = {spot: float("inf") for row in grid for spot in row}
119+
f_score[start] = h(start.get_pos(), end.get_pos())
120+
121+
open_set_hash = {start}
122+
123+
while not open_set.empty():
124+
for event in pg.event.get():
125+
if event.type == pg.QUIT:
126+
pg.quit()
127+
128+
current = open_set.get()[2]
129+
open_set_hash.remove(current)
130+
131+
if current == end:
132+
reconstruct_path(came_from, end, draw)
133+
end.make_end()
134+
return True
135+
136+
for neighbour in current.neighbours:
137+
temp_g_score = g_score[current] + 1
138+
139+
if temp_g_score < g_score[neighbour]:
140+
came_from[neighbour] = current
141+
g_score[neighbour] = temp_g_score
142+
f_score[neighbour] = temp_g_score + h(neighbour.get_pos(), end.get_pos())
143+
if neighbour not in open_set_hash:
144+
count += 1
145+
open_set.put((f_score[neighbour], count, neighbour))
146+
open_set_hash.add(neighbour)
147+
neighbour.make_open()
148+
draw()
149+
150+
if current != start:
151+
current.make_closed()
152+
153+
return False
154+
155+
156+
def make_grid(rows, width):
157+
grid = []
158+
gap = width // rows
159+
for i in range(rows):
160+
grid.append([])
161+
for j in range(rows):
162+
spot = Spot(i, j, gap, rows)
163+
grid[i].append(spot)
164+
165+
return grid
166+
167+
168+
def draw_grid(win, rows, width):
169+
gap = width // rows
170+
for i in range(rows):
171+
pg.draw.line(win, GREY, (0, i*gap), (width, i*gap))
172+
for j in range(rows):
173+
pg.draw.line(win, GREY, (j*gap, 0), (j*gap, width))
174+
175+
176+
def draw(win, grid, rows, width):
177+
win.fill(WHITE)
178+
179+
for row in grid:
180+
for spot in row:
181+
spot.draw(win)
182+
183+
draw_grid(win, rows, width)
184+
pg.display.update()
185+
186+
187+
def get_clicked_pos(pos, rows, width):
188+
gap = width // rows
189+
y, x = pos
190+
191+
row = y // gap
192+
col = x // gap
193+
194+
return row, col
195+
196+
197+
def main(win, width):
198+
ROWS = 35
199+
grid = make_grid(ROWS, width)
200+
201+
start = None
202+
end = None
203+
204+
run = True
205+
started = False
206+
while run:
207+
draw(win, grid, ROWS, width)
208+
for event in pg.event.get():
209+
if event.type == pg.QUIT:
210+
run = False
211+
212+
if pg.mouse.get_pressed()[0]: # left mouse button
213+
pos = pg.mouse.get_pos()
214+
row, col = get_clicked_pos(pos, ROWS, width)
215+
spot = grid[row][col]
216+
if not start and spot != end:
217+
start = spot
218+
start.make_start()
219+
220+
elif not end and spot != start:
221+
end = spot
222+
end.make_end()
223+
224+
elif spot != end and spot != start:
225+
spot.make_barrier()
226+
227+
elif pg.mouse.get_pressed()[2]: # right mouse button
228+
pos = pg.mouse.get_pos()
229+
row, col = get_clicked_pos(pos, ROWS, width)
230+
spot = grid[row][col]
231+
spot.reset()
232+
if spot == start:
233+
start = None
234+
elif spot == end:
235+
end = None
236+
237+
if event.type == pg.KEYDOWN:
238+
if event.key == pg.K_SPACE and start and end:
239+
for row in grid:
240+
for spot in row:
241+
spot.update_neighbour(grid)
242+
243+
algorithm(lambda: draw(win, grid, ROWS, width), grid, start, end)
244+
245+
if event.key == pg.K_c:
246+
start = None
247+
end = None
248+
grid = make_grid(ROWS, width)
249+
250+
pg.quit()
251+
252+
main(WIN, WIDTH)

0 commit comments

Comments
 (0)