diff --git a/novikovsd/maze.py b/novikovsd/maze.py index 4500451..73c103e 100644 --- a/novikovsd/maze.py +++ b/novikovsd/maze.py @@ -99,12 +99,101 @@ class TextFileMazeBuilder(MazeBuilder): return maze class PathFindingStrategy(ABC): + @abstractmethod + def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]: + pass class BFSStrategy(PathFindingStrategy): + def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]: + if start == exit: + self.last_visited = 1 + return [start] + + queue = deque() + queue.append(start) + parent = {start: None} + visited = {start} + visited_count = 1 + + while queue: + current = queue.popleft() + if current == exit: + break + for neighbor in maze.get_neighbors(current): + if neighbor not in visited: + visited.add(neighbor) + visited_count += 1 + parent[neighbor] = current + queue.append(neighbor) + + self.last_visited = visited_count + if exit not in parent: + return [] + + path = [] + cur = exit + while cur is not None: + path.append(cur) + cur = parent[cur] + path.reverse() + return path class DFSStrategy(PathFindingStrategy): + def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]: + stack = [(start, [start])] + visited = {start} + visited_count = 1 + + while stack: + current, path = stack.pop() + if current == exit: + self.last_visited = visited_count + return path + for neighbor in maze.get_neighbors(current): + if neighbor not in visited: + visited.add(neighbor) + visited_count += 1 + stack.append((neighbor, path + [neighbor])) + self.last_visited = visited_count + return [] class AStarStrategy(PathFindingStrategy): + def heuristic(self, a: Cell, b: Cell) -> int: + return abs(a.x - b.x) + abs(a.y - b.y) + + def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]: + open_set = [] + counter = 0 + heappush(open_set, (0, counter, start)) + came_from = {} + g_score = {start: 0} + f_score = {start: self.heuristic(start, exit)} + visited_count = 0 + + while open_set: + _, _, current = heappop(open_set) + visited_count += 1 + if current == exit: + path = [] + while current in came_from: + path.append(current) + current = came_from[current] + path.append(start) + path.reverse() + self.last_visited = visited_count + return path + + for neighbor in maze.get_neighbors(current): + tentative_g = g_score[current] + 1 + if neighbor not in g_score or tentative_g < g_score[neighbor]: + came_from[neighbor] = current + g_score[neighbor] = tentative_g + f = tentative_g + self.heuristic(neighbor, exit) + f_score[neighbor] = f + counter += 1 + heappush(open_set, (f, counter, neighbor)) + self.last_visited = visited_count + return [] class SearchStats: