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
277 changes: 277 additions & 0 deletions bin/A-Star-GUI/AStarGUI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
# A * Pathfinding Algorithm 🌟

# Implemented with pygame, this script will find the shortest distance between two nodes using A * Algorithm 🎮

# Instructions / Keys Functionalities:
# -Left Click to add start and end nodes
# -Right Click to remove the nodes
# -Space Bar to start finding the shortest distance
# -'C' to clear and reset the grid

# Requirements:
# pip install pygame

# By Susnata Goswami(https://github.com/proghead00)

import pygame
import math
from queue import PriorityQueue

WIDTH = 800
WIN = pygame.display.set_mode((WIDTH, WIDTH)) # dimension to make it a square
pygame.display.set_caption("A* Path Finding Algorithm")

RED = (235, 77, 75)
GREEN = (186, 220, 88)
BLUE = (48, 51, 107)
YELLOW = (249, 202, 36)
WHITE = (255, 255, 255)
BLACK = (53, 59, 72)
PURPLE = (130, 88, 159)
ORANGE = (225, 95, 65)
GREY = (128, 128, 128)
TURQUOISE = (10, 189, 227)


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.neighbors = []
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_start(self):
self.color = ORANGE

def make_closed(self):
self.color = RED

def make_open(self):
self.color = GREEN

def make_barrier(self):
self.color = BLACK

def make_end(self):
self.color = TURQUOISE

def make_path(self):
self.color = PURPLE

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

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

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

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

if self.col > 0 and not grid[self.row][self.col - 1].is_barrier(): # LEFT
self.neighbors.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) # finding absolute distance


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 = {}
# keeps track of current shortest distance from start node to this node
g_score = {spot: float("inf") for row in grid for spot in row}
g_score[start] = 0
# keeps track of predicted distance from this node to end node
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 pygame.event.get():
if event.type == pygame.QUIT:
pygame.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 neighbor in current.neighbors:
temp_g_score = g_score[current] + 1

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

draw()

if current != start:
current.make_closed()

return False


def make_grid(rows, width):
grid = []
gap = width // rows # integer division: gap b/w each of these 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):
pygame.draw.line(win, GREY, (0, i * gap),
(width, i * gap)) # horizontal line
for j in range(rows):
pygame.draw.line(win, GREY, (j * gap, 0),
(j * gap, width)) # vertical lines


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)
pygame.display.update()

# getting mouse postiion


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 = 50
grid = make_grid(ROWS, width)

start = None
end = None

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

if pygame.mouse.get_pressed()[0]: # LEFT MOUSE BUTTON: 0
pos = pygame.mouse.get_pos()
# actual spot in 2D list where mouse is clicked
row, col = get_clicked_pos(pos, ROWS, width)
spot = grid[row][col]

# if start and end aren't done
if not start and spot != end:
start = spot
start.make_start()

# to avoid overlapping of start and end node
elif not end and spot != start:
end = spot
end.make_end()

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

elif pygame.mouse.get_pressed()[2]: # RIGHT MOUSE BUTTON: 2
pos = pygame.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 == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and start and end:
for row in grid:
for spot in row:
spot.update_neighbors(grid)

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

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

pygame.quit()


main(WIN, WIDTH)
18 changes: 18 additions & 0 deletions bin/A-Star-GUI/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# A\* Pathfinding Algorithm 🌟

## Implemented with pygame, this script will find the shortest distance between two nodes using A\* Algorithm 🎮

## Instructions/ Keys Functionalities :

- ### Left Click to add start and end nodes
- ### Right Click to remove the nodes
- ### Space Bar to start finding the shortest distance
- ### 'C' to clear and reset the grid

## Requirements:

<code> pip install pygame </code>

![ss](https://user-images.githubusercontent.com/55017730/92324354-88be8200-f05e-11ea-8d10-e8314ec8f5c1.png)

### By Susnata Goswami(https://github.com/proghead00)
1 change: 1 addition & 0 deletions bin/A-Star-GUI/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pygame
7 changes: 6 additions & 1 deletion docs/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
"description": "<ul><li>This script renders the air quality from the location of the user</li><li>The location is fetched using the user's IP address</li><li>This script requires a key from WAQI</li><li>It is free and can be fetched from <a href='http://aqicn.org/data-platform/token/#/'>http://aqicn.org/data-platform/token/#/</a></li></ul><b>Release History</b></br><b>0.0.1</b> - Work in progress",
"usage": "python air-quality.py token",
"type": "data"
},{
"name": "A* Pathfinding Algorithm with GUI",
"description": "It will find the shortes distance between two nodes, and it's implemented with a GUI.",
"usage": "cd A-Star-GUI -> python AStarGUI.py ",
"type": "data"
},{
"name": "Approximating pi",
"description": "This script is useful to show a way to approximate the value of pi using a Monte Carlo method. It is also optimized using the <code>@jit</code> (just-in-time) decorator from the <a href='https://numba.pydata.org'>numba</a> library.",
Expand Down Expand Up @@ -153,4 +158,4 @@
"usage": "python reveal-md.py -d folder_name -c config",
"note": "the config is optional. You can specify with keys as here https://github.com/hakimel/reveal.js/#configuration in a json file. Reveal.js cdn link is included in generated html you may need to download them if you want to use the presentation offline",
"type": "util"
}]
}]
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.