update code to get 10/10 from pylint

This commit is contained in:
Jakub Kliszko 2023-03-22 11:32:50 +01:00
parent 6c55a51756
commit 1cdca282a4

85
main.py
View File

@ -8,27 +8,26 @@ as simple as possible (but of course it does not have to). Example solution:
https://angeluriot.com/maze_solver/. https://angeluriot.com/maze_solver/.
Test multiple heuristics (at least two) h(n) and discuss the differences be- Test multiple heuristics (at least two) h(n) and discuss the differences be-
tween the obtained results. tween the obtained results.
"""
""" Technical requirements: Technical requirements:
- implemented in Python. - implemented in Python.
- adheres to basic standards of lean coding in accordance to PEP8 - adheres to basic standards of lean coding in accordance to PEP8
- comments in the crucial parts to help with readability and understanding. - comments in the crucial parts to help with readability and understanding.
- The clear instruction how to run and test the code should be included. - The clear instruction how to run and test the code should be included.
"""
"""
Thinks that do not work: Thinks that do not work:
Does not work if no Start (Should print out NO START FOUND) 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 End (Should print out NO END FOUND)
Does not work if no path (Should print out NO PATH FOUND) Does not work if no path (Should print out NO PATH FOUND)
""" """
import heapq import heapq
class MazeSolver:
class MazeSolver:
'''Maze Solver'''
# self corresponds to "this" in js, it refers to object of MazeSolver class # self corresponds to "this" in js, it refers to object of MazeSolver class
def __init__(self, maze): def __init__(self, maze):
# assign readed maze 2D array to parameter from class MazeSolver # assign readed maze 2D array to parameter from class MazeSolver
self.maze = maze self.maze = maze
@ -38,16 +37,19 @@ class MazeSolver:
# Start/End character # Start/End character
def find_start_and_end(self): def find_start_and_end(self):
'''Finds start and end points in the maze'''
start = end = None start = end = None
for row in range(len(self.maze)):
for col in range(len(self.maze[row])): for row_i, row in enumerate(self.maze):
if self.maze[row][col] == 'S': for col_i, cell in enumerate(row):
start = (row, col) if cell == 'S':
elif self.maze[row][col] == 'E': start = (row_i, col_i)
end = (row, col) elif cell == 'E':
end = (row_i, col_i)
if start is not None and end is not None: if start is not None and end is not None:
return start, end return start, end
print(f"DID NOT FOUND START OR END, Start: {start}, End: {end}") print(f"DID NOT FOUND START OR END, Start: {start}, End: {end}")
return start, end
# Go through each neighboor # Go through each neighboor
# N # N
@ -56,6 +58,7 @@ class MazeSolver:
# If it is not a "wall" (#) add its position to list of neighbors # If it is not a "wall" (#) add its position to list of neighbors
def get_neighbors(self, position): def get_neighbors(self, position):
'''Finds point's neighbours'''
row, col = position row, col = position
neighbors = [] neighbors = []
if row > 0 and self.maze[row - 1][col] != '#': if row > 0 and self.maze[row - 1][col] != '#':
@ -71,6 +74,7 @@ class MazeSolver:
# find path through maze # find path through maze
def solve(self): def solve(self):
'''Solves the maze'''
queue = [] queue = []
# set means that values inside can not repeat # set means that values inside can not repeat
visited = set() visited = set()
@ -79,15 +83,17 @@ class MazeSolver:
# we use heapq so the element with lowest heurisitc value will always # we use heapq so the element with lowest heurisitc value will always
# be at the top of heap # be at the top of heap
heapq.heappush( heapq.heappush(
queue, (self.heuristicEuclidean( queue, (self.heuristic_euclidean(
self.start), self.start, [ self.start), self.start, [
self.start])) self.start]))
# go through queue until it's empty # Go through queue until it's empty
# find neighbour (which is not wall) closests to END point (based on heuristic) # Find neighbour (which is not wall) closests to the
# go there and repeat # END point (based on heuristic)
# Go there and repeat
# if cannot find path it starts over but skips the path that lead it to # if cannot find path it starts over but skips the path that lead it to
# dead end # dead end
path = None
while queue: while queue:
# pop first element of heap # pop first element of heap
# first value is skipped and we only save current position and path # first value is skipped and we only save current position and path
@ -96,61 +102,68 @@ class MazeSolver:
# if we already visited current skip code and go to next iteration # if we already visited current skip code and go to next iteration
if current in visited: if current in visited:
continue continue
# if we found the end return path # if we found the end return path
if current == self.end: if current == self.end:
return path break
visited.add(current) visited.add(current)
for neighbor in self.get_neighbors(current): for neighbor in self.get_neighbors(current):
if neighbor not in visited: if neighbor not in visited:
new_path = path + [neighbor] new_path = path + [neighbor]
heapq.heappush( heapq.heappush(
queue, (self.heuristicEuclidean(neighbor), neighbor, new_path)) queue, (self.heuristic_euclidean(neighbor), neighbor, new_path))
print_maze(self.maze, new_path) print_maze(self.maze, new_path)
print() print()
return path
# This heuristic returns the Manhatan distance between the given position # This heuristic returns the Manhatan distance between the given position
# and the maze's end # and the maze's end
def heuristicManhatan(self, position): def heuristic_manhatan(self, position):
'''Heuristic function that uses Manhatan distance'''
return abs(position[0] - self.end[0]) + abs(position[1] - self.end[1]) return abs(position[0] - self.end[0]) + abs(position[1] - self.end[1])
# This heuristic returns the Euclidean distance between the given position # This heuristic returns the Euclidean distance between the given position
# and the maze's end # 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 + return (abs(position[0] - self.end[0])**2 +
abs(position[1] - self.end[1])**2)**0.5 abs(position[1] - self.end[1])**2)**0.5
# Open and load text file to array # Open and load text file to array
def load_maze(filename): def load_maze(filename):
'''Loads a maze from the specified file'''
# Open for reading only and save to fileContents # Open for reading only and save to fileContents
fileContents = open(filename, 'r') with open(filename, 'r', encoding='utf8') as file_contents:
# strip() removes extra white spaces from the beginning and the end of a string # strip() removes extra white spaces from the beginning and the end of
# a string
# list() changes string to array of chars # list() changes string to array of chars
# Inside of square brackets we will have an array of characters for each line of file # Inside of square brackets we will have an array of characters for
# after going through every line in a file we will have 2D array of arrays # each line of file
# After going through every line in a file we will have 2D array of arrays
# of characters of every line # of characters of every line
maze = [list(line.strip()) for line in fileContents] maze = [list(line.strip()) for line in file_contents]
return maze return maze
def print_maze(maze, path=None): def print_maze(maze, path=None):
'''Prints the maze'''
if path is None: if path is None:
path = [] path = []
for row in range(len(maze)): for row_i, row in enumerate(maze):
for col in range(len(maze[row])): for col_i, cell in enumerate(row):
if (row, col) in path: if (row_i, col_i) in path:
print('*', end='') print('*', end='')
else: else:
print(maze[row][col], end='') print(cell, end='')
print() print()
# Ran first in the code # Ran first in the code
if __name__ == '__main__': if __name__ == '__main__':
# Open and load text file to array # Open and load text file to array
maze = load_maze('mazes/mazeDeadEnd.txt') loadedMaze = load_maze('mazes/mazeDeadEnd.txt')
# Initialize MazeSolver object with maze as paramater # Initialize MazeSolver object with maze as paramater
solver = MazeSolver(maze) solver = MazeSolver(loadedMaze)
# Find path using MazeSolver solve method # Find path using MazeSolver solve method
path = solver.solve() solvedPath = solver.solve()
print_maze(maze, path) print_maze(loadedMaze, solvedPath)