Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Shortest-Path-Finder (GUI)/2. Made Obstacles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions Shortest-Path-Finder (GUI)/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Shortest Path Finder (GUI)

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.

## Setup instructions

In order to run this script, You just need the following modules:

- **Pygame:** It is a set of Python modules designed for writing video games.
```bash
pip install pygame
```

## Controls
- Click on boxes to mark start(Yellow Coloured) and end point(Sky Blue Coloured).
- Then make some obstacles(Black Coloured).
- Then finally press "SPACE" to find the shortest path between the start and end point.
- The shortest path is represented by "Purple

## Screenshots

<p align="center">
<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"/>
<br>
1. Marked Start and End Point
</p>
<p align="center">
<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"/>
<br>
2. Made the Obstacles
</p>
<p align="center">
<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"/>
<br>
3. Shortest Path marked in Purple by the Algorithm
</p>

## Author

[Vishal Patil](https://github.com/SpecTEviL)
252 changes: 252 additions & 0 deletions Shortest-Path-Finder (GUI)/Shortest Path Finder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
# Click on boxes to mark start and end point. Then make some obstacles and once done
# press SPACE to find the shortest path between the start and end point

import pygame as pg
import math
from queue import PriorityQueue


WIDTH = 595
WIN = pg.display.set_mode((WIDTH, WIDTH))
pg.display.set_caption("Shortest Path Finder")

RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREY = (128, 128, 128)
TURQUOISE = (64, 244, 208)
ORANGE = (255, 165, 0)
PURPLE = (128, 0, 128)


class Spot:
def __init__(self, row, col, width, total_rows):
self.row = row
self.col = col
self.x = row * width
self.y = col * width
self.color = WHITE
self.neighbour = []
self.width = width
self.total_rows = total_rows

def get_pos(self):
return self.row, self.col

def is_closed(self):
return self.color == RED

def is_open(self):
return self.color == GREEN

def is_barrier(self):
return self.color == BLACK

def is_start(self):
return self.color == ORANGE

def is_end(self):
return self.color == TURQUOISE

def reset(self):
self.color = WHITE

def make_closed(self):
self.color = RED

def make_open(self):
self.color = GREEN

def make_barrier(self):
self.color = BLACK

def make_start(self):
self.color = ORANGE

def make_end(self):
self.color = TURQUOISE

def make_path(self):
self.color = PURPLE

def draw(self, win):
pg.draw.rect(win, self.color, (self.x, self.y, self.width, self.width))

def update_neighbour(self, grid):
self.neighbours = []
if self.row < self.total_rows - 1 and not grid[self.row + 1][self.col].is_barrier(): # down
self.neighbours.append(grid[self.row + 1][self.col])

if self.row > 0 and not grid[self.row - 1][self.col].is_barrier(): # up
self.neighbours.append(grid[self.row - 1][self.col])

if self.col < self.total_rows - 1 and not grid[self.row][self.col + 1].is_barrier(): # right
self.neighbours.append(grid[self.row][self.col + 1])

if self.col > 0 and not grid[self.row][self.col - 1].is_barrier(): # left
self.neighbours.append(grid[self.row][self.col - 1])



def __lt__(self, other):
return False


def h(p1, p2):
x1, y1 = p1
x2, y2 = p2
return abs(x1 - x2) + abs(y1 - y2)


def reconstruct_path(came_from, current, draw):
while current in came_from:
current = came_from[current]
current.make_path()
draw()


def algorithm(draw, grid, start, end):
count = 0
open_set = PriorityQueue()
open_set.put((0, count, start))
came_from = {}
g_score = {spot: float("inf") for row in grid for spot in row}
g_score[start] = 0
f_score = {spot: float("inf") for row in grid for spot in row}
f_score[start] = h(start.get_pos(), end.get_pos())

open_set_hash = {start}

while not open_set.empty():
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()

current = open_set.get()[2]
open_set_hash.remove(current)

if current == end:
reconstruct_path(came_from, end, draw)
end.make_end()
return True

for neighbour in current.neighbours:
temp_g_score = g_score[current] + 1

if temp_g_score < g_score[neighbour]:
came_from[neighbour] = current
g_score[neighbour] = temp_g_score
f_score[neighbour] = temp_g_score + h(neighbour.get_pos(), end.get_pos())
if neighbour not in open_set_hash:
count += 1
open_set.put((f_score[neighbour], count, neighbour))
open_set_hash.add(neighbour)
neighbour.make_open()
draw()

if current != start:
current.make_closed()

return False


def make_grid(rows, width):
grid = []
gap = width // rows
for i in range(rows):
grid.append([])
for j in range(rows):
spot = Spot(i, j, gap, rows)
grid[i].append(spot)

return grid


def draw_grid(win, rows, width):
gap = width // rows
for i in range(rows):
pg.draw.line(win, GREY, (0, i*gap), (width, i*gap))
for j in range(rows):
pg.draw.line(win, GREY, (j*gap, 0), (j*gap, width))


def draw(win, grid, rows, width):
win.fill(WHITE)

for row in grid:
for spot in row:
spot.draw(win)

draw_grid(win, rows, width)
pg.display.update()


def get_clicked_pos(pos, rows, width):
gap = width // rows
y, x = pos

row = y // gap
col = x // gap

return row, col


def main(win, width):
ROWS = 35
grid = make_grid(ROWS, width)

start = None
end = None

run = True
started = False
while run:
draw(win, grid, ROWS, width)
for event in pg.event.get():
if event.type == pg.QUIT:
run = False

if pg.mouse.get_pressed()[0]: # left mouse button
pos = pg.mouse.get_pos()
row, col = get_clicked_pos(pos, ROWS, width)
spot = grid[row][col]
if not start and spot != end:
start = spot
start.make_start()

elif not end and spot != start:
end = spot
end.make_end()

elif spot != end and spot != start:
spot.make_barrier()

elif pg.mouse.get_pressed()[2]: # right mouse button
pos = pg.mouse.get_pos()
row, col = get_clicked_pos(pos, ROWS, width)
spot = grid[row][col]
spot.reset()
if spot == start:
start = None
elif spot == end:
end = None

if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE and start and end:
for row in grid:
for spot in row:
spot.update_neighbour(grid)

algorithm(lambda: draw(win, grid, ROWS, width), grid, start, end)

if event.key == pg.K_c:
start = None
end = None
grid = make_grid(ROWS, width)

pg.quit()

main(WIN, WIDTH)