mirror of
https://github.com/kuhyx/WUT_Computer_Science.git
synced 2026-07-04 20:03:04 +02:00
Merge branch 'pylint-update'
# Conflicts: # main.py
This commit is contained in:
commit
9242930433
88
main.py
88
main.py
@ -8,29 +8,27 @@ as simple as possible (but of course it does not have to). Example solution:
|
||||
https://angeluriot.com/maze_solver/.
|
||||
Test multiple heuristics (at least two) h(n) and discuss the differences be-
|
||||
tween the obtained results.
|
||||
"""
|
||||
""" Technical requirements:
|
||||
|
||||
Technical requirements:
|
||||
- implemented in Python.
|
||||
- adheres to basic standards of lean coding in accordance to PEP8
|
||||
- comments in the crucial parts to help with readability and understanding.
|
||||
- The clear instruction how to run and test the code should be included.
|
||||
"""
|
||||
"""
|
||||
|
||||
Thinks that do not work:
|
||||
Does not work if no Start (Should print out NO START FOUND)
|
||||
Does not work if no End (Should print out NO END FOUND)
|
||||
Does not work if no path (Should print out NO PATH FOUND)
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
import heapq
|
||||
import sys
|
||||
|
||||
class MazeSolver:
|
||||
|
||||
class MazeSolver:
|
||||
'''Maze Solver'''
|
||||
# self corresponds to "this" in js, it refers to object of MazeSolver class
|
||||
|
||||
def __init__(self, maze):
|
||||
# assign read maze 2D array to parameter from class MazeSolver
|
||||
self.maze = maze
|
||||
@ -40,16 +38,19 @@ class MazeSolver:
|
||||
# Start/End character
|
||||
|
||||
def find_start_and_end(self):
|
||||
'''Finds start and end points in the maze'''
|
||||
start = end = None
|
||||
for row in range(len(self.maze)):
|
||||
for col in range(len(self.maze[row])):
|
||||
if self.maze[row][col] == 'S':
|
||||
start = (row, col)
|
||||
elif self.maze[row][col] == 'E':
|
||||
end = (row, col)
|
||||
|
||||
for row_i, row in enumerate(self.maze):
|
||||
for col_i, cell in enumerate(row):
|
||||
if cell == 'S':
|
||||
start = (row_i, col_i)
|
||||
elif cell == 'E':
|
||||
end = (row_i, col_i)
|
||||
if start is not None and end is not None:
|
||||
return start, end
|
||||
print(f"DID NOT FOUND START OR END, Start: {start}, End: {end}")
|
||||
return start, end
|
||||
|
||||
# Go through each neighbor
|
||||
# N
|
||||
@ -58,6 +59,7 @@ class MazeSolver:
|
||||
# If it is not a "wall" (#) add its position to list of neighbors
|
||||
|
||||
def get_neighbors(self, position):
|
||||
'''Finds point's neighbours'''
|
||||
row, col = position
|
||||
neighbors = []
|
||||
if row > 0 and self.maze[row - 1][col] != '#':
|
||||
@ -73,6 +75,7 @@ class MazeSolver:
|
||||
# find path through maze
|
||||
|
||||
def solve(self):
|
||||
'''Solves the maze'''
|
||||
queue = []
|
||||
# set means that values inside can not repeat
|
||||
visited = set()
|
||||
@ -81,15 +84,17 @@ class MazeSolver:
|
||||
# we use heapq so the element with lowest heuristic value will always
|
||||
# be at the top of heap
|
||||
heapq.heappush(
|
||||
queue, (self.heuristicEuclidean(
|
||||
queue, (self.heuristic_euclidean(
|
||||
self.start), self.start, [
|
||||
self.start]))
|
||||
|
||||
# go through queue until it's empty
|
||||
# find neighbor (which is not wall) closest to END point (based on heuristic)
|
||||
# go there and repeat
|
||||
# Go through queue until it's empty
|
||||
# Find neighbor (which is not wall) closests to the
|
||||
# END point (based on heuristic)
|
||||
# Go there and repeat
|
||||
# if cannot find path it starts over but skips the path that lead it to
|
||||
# dead end
|
||||
path = None
|
||||
while queue:
|
||||
# pop first element of heap
|
||||
# first value is skipped and we only save current position and path
|
||||
@ -98,52 +103,59 @@ class MazeSolver:
|
||||
# if we already visited current skip code and go to next iteration
|
||||
if current in visited:
|
||||
continue
|
||||
# if we found the end return path
|
||||
# if we found the end return path
|
||||
if current == self.end:
|
||||
return path
|
||||
break
|
||||
visited.add(current)
|
||||
for neighbor in self.get_neighbors(current):
|
||||
if neighbor not in visited:
|
||||
new_path = path + [neighbor]
|
||||
heapq.heappush(
|
||||
queue, (self.heuristicEuclidean(neighbor), neighbor, new_path))
|
||||
queue, (self.heuristic_euclidean(neighbor), neighbor, new_path))
|
||||
print_maze(self.maze, new_path)
|
||||
print()
|
||||
return path
|
||||
|
||||
# This heuristic returns the Manhattan distance between the given position
|
||||
# and the maze's end
|
||||
def heuristicManhattan(self, position):
|
||||
def heuristic_manhattan(self, position):
|
||||
'''Heuristic function that uses Manhattan distance'''
|
||||
return abs(position[0] - self.end[0]) + abs(position[1] - self.end[1])
|
||||
|
||||
# This heuristic returns the Euclidean distance between the given position
|
||||
# and the maze's end
|
||||
def heuristicEuclidean(self, position):
|
||||
def heuristic_euclidean(self, position):
|
||||
'''Heuristic function that uses Euclidean distance'''
|
||||
return (abs(position[0] - self.end[0])**2 +
|
||||
abs(position[1] - self.end[1])**2)**0.5
|
||||
|
||||
|
||||
# Open and load text file to array
|
||||
def load_maze(filename):
|
||||
'''Loads a maze from the specified file'''
|
||||
# Open for reading only and save to fileContents
|
||||
fileContents = open(filename, 'r')
|
||||
# strip() removes extra white spaces from the beginning and the end of a string
|
||||
# list() changes string to array of chars
|
||||
# Inside of square brackets we will have an array of characters for each line of file
|
||||
# after going through every line in a file we will have 2D array of arrays
|
||||
# of characters of every line
|
||||
maze = [list(line.strip()) for line in fileContents]
|
||||
with open(filename, 'r', encoding='utf8') as file_contents:
|
||||
# strip() removes extra white spaces from the beginning and the end of
|
||||
# a string
|
||||
# list() changes string to array of chars
|
||||
# Inside of square brackets we will have an array of characters for
|
||||
# each line of file
|
||||
# After going through every line in a file we will have 2D array of arrays
|
||||
# of characters of every line
|
||||
maze = [list(line.strip()) for line in file_contents]
|
||||
return maze
|
||||
|
||||
|
||||
def print_maze(maze, path=None):
|
||||
'''Prints the maze'''
|
||||
if path is None:
|
||||
path = []
|
||||
for row in range(len(maze)):
|
||||
for col in range(len(maze[row])):
|
||||
if (row, col) in path:
|
||||
for row_i, row in enumerate(maze):
|
||||
for col_i, cell in enumerate(row):
|
||||
if (row_i, col_i) in path:
|
||||
print('*', end='')
|
||||
else:
|
||||
print(maze[row][col], end='')
|
||||
print(cell, end='')
|
||||
print()
|
||||
|
||||
|
||||
@ -154,9 +166,9 @@ if __name__ == '__main__':
|
||||
if len(sys.argv) > 1:
|
||||
file_name = sys.argv[1]
|
||||
# Open and load text file to array
|
||||
maze = load_maze(file_name)
|
||||
loadedMaze = load_maze(file_name)
|
||||
# Initialize MazeSolver object with maze as parameter
|
||||
solver = MazeSolver(maze)
|
||||
solver = MazeSolver(loadedMaze)
|
||||
# Find path using MazeSolver solve method
|
||||
path = solver.solve()
|
||||
print_maze(maze, path)
|
||||
solvedPath = solver.solve()
|
||||
print_maze(loadedMaze, solvedPath)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user