Skip to content

Add Maze-Solver-python. #207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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
232 changes: 232 additions & 0 deletions Maze-Solver-python/maze.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import sys

class Node():
def __init__(self,state,parent,action):
self.state = state
self.parent = parent
self.action = action


class StackFrontier():
def __init__(self):
self.frontier = []

def add(self,node):
self.frontier.append(node)

def contains_state(self, state):
return any(node.state == state for node in self.frontier)

def empty(self):
return len(self.frontier) == 0

def remove(self):
if self.empty():
raise Exception("Empty Frontier")
else:
node = self.frontier[-1]
self.frontier = self.frontier[:-1]
return node


class QueueFrontier(StackFrontier):

def remove(self):
if self.empty():
raise Exception("Empty Frontier")
else:
node = self.frontier[0]
self.frontier = self.frontier[1:]
return node


class Maze():
def __init__(self, filename):

with open(filename) as f:
contents = f.read()

# Validate start and end goal
if contents.count("A") != 1:
raise Exception("The maze needs to have 1 starting point")
if contents.count("B") != 1:
raise Exception("The maze needs to have 1 end point")

# Determine the height and width of a maze
contents = contents.splitlines()
self.height = len(contents)
self.width = max(len(line) for line in contents)

#Keep track of walls
self.walls = []
for i in range(self.height):
row = []
for j in range(self.width):
try :
if contents[i][j] == 'A':
self.start = (i, j)
row.append(False)
elif contents[i][j] == 'B':
self.goal = (i, j)
row.append(False)
elif contents[i][j] == " ":
row.append(False)
else:
row.append(True)
except IndexError:
row.append(False)
self.walls.append(row)

self.solution = None

def print(self):
solution = self.solution[1] if self.solution is not None else None
print()
for i, row in enumerate(self.walls):
for j, col in enumerate(row):
if col:
print("█", end="")
elif (i, j) == self.start:
print("A", end="")
elif (i, j) == self.goal:
print("B", end="")
elif solution is not None and (i, j) in solution:
print("*", end="")
else:
print(" ", end="")
print()
print()


def neighbours(self, state):
row, col = state
candidates = [
("up", (row - 1, col)),
("down", (row + 1, col)),
("left", (row, col - 1)),
("right", (row, col + 1))
]

result = []
for action, (r, c) in candidates:
if 0 <= r < self.height and 0 <= c < self.width and not self.walls[r][c]:
result.append((action, (r, c)))
return result

def solve(self):

## Number of states explored
self.num_explored = 0

# Initialize the frontier
start = Node(state=self.start , parent=None , action=None)
frontier = QueueFrontier() ##bfs
frontier.add(start)

##initialize an empty explored state
self.explored = set()

# Keep looking till we find solution
while True:

#If nothing is left in the frontier, then no solution
if frontier.empty():
raise("No solution")

#Remove a node from the frontier
node = frontier.remove()
self.num_explored += 1

#To check if goal state or not

if node.state == self.goal:
actions = []
cells = []
while node.parent is not None :
actions.append(node.action)
cells.append(node.state)
node = node.parent
actions.reverse()
cells.reverse()
self.solution = (actions, cells)
return
# Mark node as explored
self.explored.add(node.state)

#Add its neighbours to frontier

for actions, state in self.neighbours(node.state):
if not frontier.contains_state(state) and state not in self.explored :
child = Node(state=state , parent = node , action = actions)
frontier.add(child)

def output_image(self, filename, show_solution=True, show_explored=False):
from PIL import Image, ImageDraw
cell_size = 50
cell_border = 2

# Create a blank canvas
img = Image.new(
"RGBA",
(self.width * cell_size, self.height * cell_size),
"black"
)
draw = ImageDraw.Draw(img)

solution = self.solution[1] if self.solution is not None else None
for i, row in enumerate(self.walls):
for j, col in enumerate(row):

# Walls
if col:
fill = (40, 40, 40)

# Start
elif (i, j) == self.start:
fill = (255, 0, 0)

# Goal
elif (i, j) == self.goal:
fill = (0, 171, 28)

# Solution
elif solution is not None and show_solution and (i, j) in solution:
fill = (220, 235, 113)

# Explored
elif solution is not None and show_explored and (i, j) in self.explored:
fill = (212, 97, 85)

# Empty cell
else:
fill = (237, 240, 252)

# Draw cell
draw.rectangle(
([(j * cell_size + cell_border, i * cell_size + cell_border),
((j + 1) * cell_size - cell_border, (i + 1) * cell_size - cell_border)]),
fill=fill
)

img.save(filename)


if len(sys.argv) != 2:
sys.exit("Usage: python maze.py maze.txt")

file_path = sys.argv[1]
m=Maze(file_path)
print("Maze: ")
m.print()
print("Solving : ........")
m.solve()
print("Explored States : ",m.num_explored)
print("Solution : ")
m.print()
m.output_image("maze.png",show_explored=True)






6 changes: 6 additions & 0 deletions Maze-Solver-python/maze1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#####B#
##### #
#### #
#### ##
##
A######
16 changes: 16 additions & 0 deletions Maze-Solver-python/maze2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### #########
# ################### # #
# #### # # # #
# ################### # # # #
# # # # #
##################### # # # #
# ## # # # #
# # ## ### ## ######### # # #
# # # ##B# # # #
# # ## ################ # # #
### ## #### # # #
### ############## ## # # # #
### ## # # # #
###### ######## ####### # # #
###### #### # #
A ######################
6 changes: 6 additions & 0 deletions Maze-Solver-python/maze3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
## #
## ## #
#B # #
# ## ##
##
A######