diff --git a/zaharoves/задание 2/.idea/.gitignore b/zaharoves/задание 2/.idea/.gitignore
new file mode 100644
index 0000000..b58b603
--- /dev/null
+++ b/zaharoves/задание 2/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/zaharoves/задание 2/.idea/inspectionProfiles/profiles_settings.xml b/zaharoves/задание 2/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/zaharoves/задание 2/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zaharoves/задание 2/.idea/misc.xml b/zaharoves/задание 2/.idea/misc.xml
new file mode 100644
index 0000000..1d3ce46
--- /dev/null
+++ b/zaharoves/задание 2/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zaharoves/задание 2/.idea/modules.xml b/zaharoves/задание 2/.idea/modules.xml
new file mode 100644
index 0000000..4984091
--- /dev/null
+++ b/zaharoves/задание 2/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zaharoves/задание 2/.idea/vcs.xml b/zaharoves/задание 2/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/zaharoves/задание 2/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zaharoves/задание 2/.idea/задание 2.iml b/zaharoves/задание 2/.idea/задание 2.iml
new file mode 100644
index 0000000..b6731d8
--- /dev/null
+++ b/zaharoves/задание 2/.idea/задание 2.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zaharoves/задание 2/Maze_solver.py b/zaharoves/задание 2/Maze_solver.py
index e69de29..edf5990 100644
--- a/zaharoves/задание 2/Maze_solver.py
+++ b/zaharoves/задание 2/Maze_solver.py
@@ -0,0 +1,660 @@
+
+import os
+import time
+import heapq
+import csv
+import random
+from abc import ABC, abstractmethod
+from collections import deque
+from dataclasses import dataclass
+from typing import Optional
+
+
+#1. Модель лабиринта — классы Cell и Maze
+
+class Cell:
+ """Клетка лабиринта."""
+
+ def __init__(self, x: int, y: int, is_wall: bool = False,
+ is_start: bool = False, is_exit: bool = False, weight: int = 1):
+ self.x = x
+ self.y = y
+ self.is_wall = is_wall
+ self.is_start = is_start
+ self.is_exit = is_exit
+ self.weight = weight # для взвешенного лабиринта (Этап 6 доп.)
+
+ def is_passable(self) -> bool:
+ return not self.is_wall
+
+ def __repr__(self):
+ return f"Cell({self.x},{self.y})"
+
+ def __eq__(self, other):
+ return isinstance(other, Cell) and self.x == other.x and self.y == other.y
+
+ def __hash__(self):
+ return hash((self.x, self.y))
+
+ def __lt__(self, other):
+ return (self.x, self.y) < (other.x, other.y)
+
+
+class Maze:
+ """Лабиринт — двумерный массив клеток."""
+
+ def __init__(self, width: int, height: int):
+ self.width = width
+ self.height = height
+ self.cells: list[list[Cell]] = []
+ self.start: Optional[Cell] = None
+ self.exit: Optional[Cell] = None
+
+ def get_cell(self, x: int, y: int) -> Optional[Cell]:
+ if 0 <= x < self.width and 0 <= y < self.height:
+ return self.cells[y][x]
+ return None
+
+ def get_neighbors(self, cell: Cell) -> list[Cell]:
+ """Возвращает проходимых соседей (вверх, вниз, влево, вправо)."""
+ directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]
+ neighbors = []
+ for dx, dy in directions:
+ neighbor = self.get_cell(cell.x + dx, cell.y + dy)
+ if neighbor and neighbor.is_passable():
+ neighbors.append(neighbor)
+ return neighbors
+
+
+#2. Загрузка лабиринта из файла — паттерн Builder
+
+class MazeBuilder(ABC):
+ """Интерфейс строителя лабиринта."""
+
+ @abstractmethod
+ def build_from_file(self, filename: str) -> Maze:
+ pass
+
+
+class TextFileMazeBuilder(MazeBuilder):
+
+ WEIGHT_MAP = {' ': 1, 'S': 1, 'E': 1, '.': 2, '~': 3, '#': 0}
+
+ def build_from_file(self, filename: str) -> Maze:
+ with open(filename, 'r', encoding='utf-8') as f:
+ lines = f.read().splitlines()
+
+ if not lines:
+ raise ValueError("Файл лабиринта пуст")
+
+ height = len(lines)
+ width = max(len(line) for line in lines)
+ maze = Maze(width, height)
+
+ for y, line in enumerate(lines):
+ row = []
+ for x in range(width):
+ ch = line[x] if x < len(line) else ' '
+ is_wall = ch == '#'
+ is_start = ch == 'S'
+ is_exit = ch == 'E'
+ weight = self.WEIGHT_MAP.get(ch, 1)
+ cell = Cell(x, y, is_wall=is_wall, is_start=is_start,
+ is_exit=is_exit, weight=weight)
+ row.append(cell)
+ if is_start:
+ maze.start = cell
+ if is_exit:
+ maze.exit = cell
+ maze.cells.append(row)
+
+ if maze.start is None:
+ raise ValueError("В лабиринте не задана стартовая клетка (S)")
+ if maze.exit is None:
+ raise ValueError("В лабиринте не задана выходная клетка (E)")
+
+ return maze
+
+
+#3. Стратегии поиска пути — паттерн Strategy
+
+@dataclass
+class SearchStats:
+ """Статистика одного запуска поиска."""
+ time_ms: float = 0.0
+ visited_cells: int = 0
+ path_length: int = 0
+
+
+class PathFindingStrategy(ABC):
+ """Интерфейс стратегии поиска пути."""
+
+ @abstractmethod
+ def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> list[Cell]:
+ pass
+
+ def _reconstruct_path(self, parent: dict, start: Cell, exit_cell: Cell) -> list[Cell]:
+ path = []
+ current = exit_cell
+ while current is not None:
+ path.append(current)
+ current = parent.get(current)
+ path.reverse()
+ if path and path[0] == start:
+ return path
+ return []
+
+
+class BFSStrategy(PathFindingStrategy):
+ """Поиск в ширину"""
+
+ def __init__(self):
+ self.visited_count = 0
+
+ def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> list[Cell]:
+ queue = deque([start])
+ parent: dict[Cell, Optional[Cell]] = {start: None}
+ self.visited_count = 0
+
+ while queue:
+ current = queue.popleft()
+ self.visited_count += 1
+
+ if current == exit_cell:
+ return self._reconstruct_path(parent, start, exit_cell)
+
+ for neighbor in maze.get_neighbors(current):
+ if neighbor not in parent:
+ parent[neighbor] = current
+ queue.append(neighbor)
+
+ return []
+
+
+class DFSStrategy(PathFindingStrategy):
+ """Поиск в глубину"""
+
+ def __init__(self):
+ self.visited_count = 0
+
+ def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> list[Cell]:
+ stack = [start]
+ parent: dict[Cell, Optional[Cell]] = {start: None}
+ self.visited_count = 0
+
+ while stack:
+ current = stack.pop()
+ self.visited_count += 1
+
+ if current == exit_cell:
+ return self._reconstruct_path(parent, start, exit_cell)
+
+ for neighbor in maze.get_neighbors(current):
+ if neighbor not in parent:
+ parent[neighbor] = current
+ stack.append(neighbor)
+
+ return []
+
+
+class AStarStrategy(PathFindingStrategy):
+ """A* с манхэттенской эвристикой"""
+
+ def __init__(self):
+ self.visited_count = 0
+
+ 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: Cell) -> list[Cell]:
+ g_score = {start: 0}
+ parent: dict[Cell, Optional[Cell]] = {start: None}
+ open_heap = [(self._heuristic(start, exit_cell), 0, start)]
+ closed_set: set[Cell] = set() # уже обработанные клетки
+ self.visited_count = 0
+ counter = 0 # счётчик для устранения неоднозначности
+
+ while open_heap:
+ _, _, current = heapq.heappop(open_heap)
+
+ if current in closed_set:
+ continue
+ closed_set.add(current)
+ self.visited_count += 1
+
+ if current == exit_cell:
+ return self._reconstruct_path(parent, start, exit_cell)
+
+ for neighbor in maze.get_neighbors(current):
+ if neighbor in closed_set:
+ continue
+ tentative_g = g_score[current] + neighbor.weight
+ if tentative_g < g_score.get(neighbor, float('inf')):
+ g_score[neighbor] = tentative_g
+ parent[neighbor] = current
+ f = tentative_g + self._heuristic(neighbor, exit_cell)
+ counter += 1
+ heapq.heappush(open_heap, (f, counter, neighbor))
+
+ return []
+
+
+class DijkstraStrategy(PathFindingStrategy):
+ """Дейкстра"""
+
+ def __init__(self):
+ self.visited_count = 0
+
+ def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> list[Cell]:
+ dist = {start: 0}
+ parent: dict[Cell, Optional[Cell]] = {start: None}
+ open_heap = [(0, 0, start)]
+ self.visited_count = 0
+ counter = 0
+
+ while open_heap:
+ cost, _, current = heapq.heappop(open_heap)
+ if cost > dist.get(current, float('inf')):
+ continue
+ self.visited_count += 1
+
+ if current == exit_cell:
+ return self._reconstruct_path(parent, start, exit_cell)
+
+ for neighbor in maze.get_neighbors(current):
+ new_cost = dist[current] + neighbor.weight
+ if new_cost < dist.get(neighbor, float('inf')):
+ dist[neighbor] = new_cost
+ parent[neighbor] = current
+ counter += 1
+ heapq.heappush(open_heap, (new_cost, counter, neighbor))
+
+ return []
+
+
+#4. Оркестратор — MazeSolver
+
+class MazeSolver:
+ """Оркестратор"""
+
+ def __init__(self, maze: Maze, strategy: PathFindingStrategy):
+ self.maze = maze
+ self.strategy = strategy
+ self._observers: list['Observer'] = []
+ self._last_path: list[Cell] = []
+
+ def set_strategy(self, strategy: PathFindingStrategy):
+ self.strategy = strategy
+
+ def add_observer(self, observer: 'Observer'):
+ self._observers.append(observer)
+
+ def _notify(self, event: str, **kwargs):
+ for obs in self._observers:
+ obs.update(event, **kwargs)
+
+ def solve(self) -> SearchStats:
+ start = self.maze.start
+ exit_cell = self.maze.exit
+ self._notify("search_start", strategy=type(self.strategy).__name__)
+
+ t0 = time.perf_counter()
+ path = self.strategy.find_path(self.maze, start, exit_cell)
+ t1 = time.perf_counter()
+
+ self._last_path = path
+ visited = getattr(self.strategy, 'visited_count', 0)
+ stats = SearchStats(
+ time_ms=(t1 - t0) * 1000,
+ visited_cells=visited,
+ path_length=len(path)
+ )
+ self._notify("path_found", path=path, stats=stats)
+ return stats
+
+ def get_last_path(self) -> list[Cell]:
+ return self._last_path
+
+
+#5.1. Observer — ConsoleView
+
+class Observer(ABC):
+ """Интерфейс наблюдателя."""
+
+ @abstractmethod
+ def update(self, event: str, **kwargs):
+ pass
+
+
+class ConsoleView(Observer):
+ """Консольный вид"""
+
+ SYMBOLS = {
+ 'wall': '█',
+ 'path': '·',
+ 'start': 'S',
+ 'exit': 'E',
+ 'player': '@',
+ 'visited': '°',
+ 'empty': ' ',
+ }
+
+ def update(self, event: str, **kwargs):
+ if event == "search_start":
+ print(f"\n[Поиск] Алгоритм: {kwargs.get('strategy', '?')}")
+ elif event == "path_found":
+ path = kwargs.get('path', [])
+ stats = kwargs.get('stats')
+ if path:
+ print(f"[Готово] Путь найден! Длина: {stats.path_length}, "
+ f"Посещено: {stats.visited_cells}, Время: {stats.time_ms:.2f} мс")
+ else:
+ print("[Готово] Путь не найден!")
+ elif event == "move":
+ cell = kwargs.get('cell')
+ print(f"[Ход] Игрок перемещается в {cell}")
+
+ def render(self, maze: Maze, player_pos: Optional[Cell] = None,
+ path: Optional[list[Cell]] = None):
+ """Рисует лабиринт в консоли."""
+ path_set = set(path) if path else set()
+ print()
+ for y in range(maze.height):
+ row = ''
+ for x in range(maze.width):
+ cell = maze.cells[y][x]
+ if cell.is_wall:
+ row += self.SYMBOLS['wall']
+ elif player_pos and cell == player_pos:
+ row += self.SYMBOLS['player']
+ elif cell.is_start:
+ row += self.SYMBOLS['start']
+ elif cell.is_exit:
+ row += self.SYMBOLS['exit']
+ elif cell in path_set:
+ row += self.SYMBOLS['path']
+ else:
+ row += self.SYMBOLS['empty']
+ print(row)
+ print()
+
+
+#5.2. Command — Player и MoveCommand
+
+class Player:
+ """Игрок с текущей позицией в лабиринте."""
+
+ def __init__(self, start_cell: Cell):
+ self.current_cell = start_cell
+
+ def move_to(self, cell: Cell):
+ self.current_cell = cell
+
+
+class Command(ABC):
+ """Интерфейс команды."""
+
+ @abstractmethod
+ def execute(self):
+ pass
+
+ @abstractmethod
+ def undo(self):
+ pass
+
+
+class MoveCommand(Command):
+ """Команда перемещения игрока в указанную клетку."""
+
+ def __init__(self, player: Player, target_cell: Cell, solver: MazeSolver):
+ self.player = player
+ self.target_cell = target_cell
+ self.previous_cell = player.current_cell
+ self.solver = solver
+
+ def execute(self):
+ self.previous_cell = self.player.current_cell
+ self.player.move_to(self.target_cell)
+ self.solver._notify("move", cell=self.target_cell)
+
+ def undo(self):
+ self.player.move_to(self.previous_cell)
+ self.solver._notify("move", cell=self.previous_cell)
+
+
+#6. Экспериментальная часть
+
+def generate_maze_file(filename: str, width: int, height: int,
+ wall_density: float = 0.3, no_exit: bool = False):
+ """Генерирует случайный лабиринт и сохраняет в файл."""
+ random.seed(42)
+ grid = []
+ for y in range(height):
+ row = []
+ for x in range(width):
+ if x == 0 or y == 0 or x == width - 1 or y == height - 1:
+ row.append('#')
+ else:
+ row.append('#' if random.random() < wall_density else ' ')
+ grid.append(row)
+
+ # Старт и выход
+ grid[1][1] = 'S'
+ grid[height - 2][width - 2] = 'E'
+ if no_exit:
+ ex, ey = width - 2, height - 2
+ for dx, dy in [(0, -1), (0, 1), (-1, 0), (1, 0)]:
+ nx, ny = ex + dx, ey + dy
+ if 0 < nx < width - 1 and 0 < ny < height - 1:
+ grid[ny][nx] = '#'
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ for row in grid:
+ f.write(''.join(row) + '\n')
+
+
+def run_experiments(mazes_config: list[dict], strategies: dict,
+ runs: int = 5) -> list[dict]:
+ builder = TextFileMazeBuilder()
+ results = []
+
+ for maze_cfg in mazes_config:
+ name = maze_cfg['name']
+ filepath = maze_cfg['file']
+
+ # Генерируем файл лабиринта
+ if 'generate' in maze_cfg:
+ gen = maze_cfg['generate']
+ generate_maze_file(filepath, gen['width'], gen['height'],
+ gen.get('density', 0.3),
+ gen.get('no_exit', False))
+
+ try:
+ maze = builder.build_from_file(filepath)
+ except Exception as e:
+ print(f"[Пропуск] {name}: {e}")
+ continue
+
+ for strat_name, strategy_cls in strategies.items():
+ times, visited, lengths = [], [], []
+ for _ in range(runs):
+ strategy = strategy_cls()
+ solver = MazeSolver(maze, strategy)
+ stats = solver.solve()
+ times.append(stats.time_ms)
+ visited.append(stats.visited_cells)
+ lengths.append(stats.path_length)
+
+ results.append({
+ 'лабиринт': name,
+ 'стратегия': strat_name,
+ 'время_мс': round(sum(times) / runs, 4),
+ 'посещено_клеток': int(sum(visited) / runs),
+ 'длина_пути': int(sum(lengths) / runs),
+ })
+ print(f" {name} / {strat_name}: "
+ f"time={results[-1]['время_мс']:.3f}ms, "
+ f"visited={results[-1]['посещено_клеток']}, "
+ f"path={results[-1]['длина_пути']}")
+
+ return results
+
+
+def save_csv(results: list[dict], filename: str):
+ if not results:
+ return
+ with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
+ writer = csv.DictWriter(f, fieldnames=results[0].keys())
+ writer.writeheader()
+ writer.writerows(results)
+ print(f"\nРезультаты сохранены в {filename}")
+
+
+def print_table(results: list[dict]):
+ if not results:
+ print("Нет результатов.")
+ return
+ header = f"{'Лабиринт':<20} {'Стратегия':<12} {'Время,мс':>10} {'Посещено':>10} {'Путь':>8}"
+ print("\n" + "=" * len(header))
+ print(header)
+ print("=" * len(header))
+ for r in results:
+ print(f"{r['лабиринт']:<20} {r['стратегия']:<12} "
+ f"{r['время_мс']:>10.4f} {r['посещено_клеток']:>10} {r['длина_пути']:>8}")
+ print("=" * len(header))
+
+
+#Демонстрация
+
+def demo_interactive(maze: Maze, solver: MazeSolver, view: ConsoleView):
+ """Пошаговый режим с Command."""
+ path = solver.get_last_path()
+ if not path:
+ print("Путь не найден — пошаговый режим недоступен.")
+ return
+
+ player = Player(maze.start)
+ history: list[MoveCommand] = []
+ view.render(maze, player_pos=player.current_cell, path=path)
+
+ print("Пошаговый режим: [N] — следующий шаг, [U] — отмена, [Q] — выход")
+ step_index = 1 # 0-й шаг — старт, уже там
+
+ while True:
+ cmd = input("Команда: ").strip().upper()
+ if cmd == 'Q':
+ break
+ elif cmd == 'N':
+ if step_index < len(path):
+ move = MoveCommand(player, path[step_index], solver)
+ move.execute()
+ history.append(move)
+ step_index += 1
+ os.system('cls' if os.name == 'nt' else 'clear')
+ view.render(maze, player_pos=player.current_cell, path=path)
+ if player.current_cell == maze.exit:
+ print("🎉 Вы достигли выхода!")
+ break
+ else:
+ print("Вы уже в конце пути.")
+ elif cmd == 'U':
+ if history:
+ move = history.pop()
+ move.undo()
+ step_index -= 1
+ os.system('cls' if os.name == 'nt' else 'clear')
+ view.render(maze, player_pos=player.current_cell, path=path)
+ else:
+ print("Нечего отменять.")
+ else:
+ print("Неизвестная команда.")
+
+
+def main():
+ print("=" * 60)
+ print(" Поиск выхода из лабиринта — ООП + паттерны GoF")
+ print("=" * 60)
+
+ small_maze_file = "maze_small.txt"
+
+ builder = TextFileMazeBuilder()
+ maze = builder.build_from_file(small_maze_file)
+
+ #2. Создаём представление (Observer)
+ view = ConsoleView()
+
+ #3. Демонстрация стратегий
+ strategies = {
+ 'BFS': BFSStrategy,
+ 'DFS': DFSStrategy,
+ 'A*': AStarStrategy,
+ 'Дейкстра': DijkstraStrategy,
+ }
+
+ print(f"\nЛабиринт ({maze.width}×{maze.height}):")
+ view.render(maze)
+
+ for name, cls in strategies.items():
+ strategy = cls()
+ solver = MazeSolver(maze, strategy)
+ solver.add_observer(view)
+ stats = solver.solve()
+
+ #Визуализация пути A*
+ print("\n--- Путь, найденный A* ---")
+ a_star = AStarStrategy()
+ solver = MazeSolver(maze, a_star)
+ solver.add_observer(view)
+ solver.solve()
+ view.render(maze, path=solver.get_last_path())
+
+ #4. Пошаговый режим Command
+ ans = input("Запустить пошаговый режим? (y/n): ").strip().lower()
+ if ans == 'y':
+ demo_interactive(maze, solver, view)
+
+ #5. Экспериментальная часть
+ print("\n" + "=" * 60)
+ print(" Экспериментальная часть")
+ print("=" * 60)
+
+ mazes_config = [
+ {
+ 'name': 'Маленький 10×10',
+ 'file': 'maze_small.txt',
+ },
+ {
+ 'name': 'Средний 50×50',
+ 'file': 'maze_medium.txt',
+ },
+ {
+ 'name': 'Большой 100×100',
+ 'file': 'maze_large.txt',
+ },
+ {
+ 'name': 'Пустой 50×50',
+ 'file': 'maze_empty.txt',
+ },
+ {
+ 'name': 'Без выхода 20×20',
+ 'file': 'maze_no_exit.txt',
+ },
+ ]
+
+ all_strategies = {
+ 'BFS': BFSStrategy,
+ 'DFS': DFSStrategy,
+ 'A*': AStarStrategy,
+ 'Дейкстра': DijkstraStrategy,
+ }
+
+ print("\nЗапуск экспериментов (5 прогонов каждого)...")
+ results = run_experiments(mazes_config, all_strategies, runs=5)
+ print_table(results)
+ save_csv(results, "results.csv")
+
+ print("\nГотово!")
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/zaharoves/задание 2/graphs.py b/zaharoves/задание 2/graphs.py
index e69de29..708c983 100644
--- a/zaharoves/задание 2/graphs.py
+++ b/zaharoves/задание 2/graphs.py
@@ -0,0 +1,57 @@
+import pandas as pd
+import matplotlib.pyplot as plt
+
+
+df = pd.read_csv('results.csv', encoding='utf-8-sig')
+
+print(df)
+
+# Получаем список лабиринтов
+mazes = df['лабиринт'].unique()
+
+#График времени
+for maze in mazes:
+ subset = df[df['лабиринт'] == maze]
+
+ plt.figure(figsize=(8, 5))
+ plt.bar(subset['стратегия'], subset['время_мс'])
+
+ plt.title(f'Время выполнения — {maze}')
+ plt.xlabel('Алгоритм')
+ plt.ylabel('Время (мс)')
+
+ plt.tight_layout()
+ plt.savefig(f'time_{maze}.png')
+ plt.close()
+
+#График посещенных клеток
+for maze in mazes:
+ subset = df[df['лабиринт'] == maze]
+
+ plt.figure(figsize=(8, 5))
+ plt.bar(subset['стратегия'], subset['посещено_клеток'])
+
+ plt.title(f'Посещённые клетки — {maze}')
+ plt.xlabel('Алгоритм')
+ plt.ylabel('Количество клеток')
+
+ plt.tight_layout()
+ plt.savefig(f'visited_{maze}.png')
+ plt.close()
+
+# ===== ГРАФИК ДЛИНЫ ПУТИ =====
+for maze in mazes:
+ subset = df[df['лабиринт'] == maze]
+
+ plt.figure(figsize=(8, 5))
+ plt.bar(subset['стратегия'], subset['длина_пути'])
+
+ plt.title(f'Длина пути — {maze}')
+ plt.xlabel('Алгоритм')
+ plt.ylabel('Длина пути')
+
+ plt.tight_layout()
+ plt.savefig(f'path_{maze}.png')
+ plt.close()
+
+print('Графики успешно построены!')
\ No newline at end of file
diff --git a/zaharoves/задание 2/maze_empty.txt b/zaharoves/задание 2/maze_empty.txt
new file mode 100644
index 0000000..c83b6cd
--- /dev/null
+++ b/zaharoves/задание 2/maze_empty.txt
@@ -0,0 +1,50 @@
+##################################################
+#S #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# #
+# E#
+##################################################
diff --git a/zaharoves/задание 2/maze_large.txt b/zaharoves/задание 2/maze_large.txt
new file mode 100644
index 0000000..1e4f4a3
--- /dev/null
+++ b/zaharoves/задание 2/maze_large.txt
@@ -0,0 +1,100 @@
+####################################################################################################
+#S ## # ## ## # # # ## ####### ## # # ## ## ## # # ### # #
+# # # # # # # # # # # # # # # # ## ### # ## ## ## # ## ## #
+# # # # # # ## # # ## ## # # # # # ### # # # ### # # # # ## ##
+# ## ## ### # # # # # ### # # # ## # # # ## #
+# ## # ## #### # # # # # # ## ## #### ## # # # #
+### # # # # # # # # ### #### # # # ## # # # # # # # # #
+# # ## ## # ## ##### ## ###### # # ## # ## # # ## #### #
+# ## ## ## ## ## ## # # # # # # ## # # #
+## # # # # # # # # ## # # # # ## # # ###
+## # # # # # # # # ## ## # # # # ### ## # #
+## # # # # # ## # ## # ## # # #### ## # ## # # # ## ## # #
+# # # # # # ## # # ## # ## # # # # ### # # # # # # ### # #
+## # ## ## # # # # ### # ## ## # # ### ## # #
+## ## # # ## ### # # # # # # # # ## # # # # # #
+# ## # # ## # ### ## # # # ## # # # ## # # # #### # # # #
+# # # # # # # ## ## ## # # # # ### # # #
+# # # ### # # # # ## # ### # # #### # # # # # #
+# # # # # # ## # # # # # # # ## # ### # ##
+## # ### ## ## # # # # # # # # # # # # # # ### ## # #
+## ## ### # # # # ### ## # # # # ## # # # # # # # #
+##### # # # #### # ## # # # # # # ### # ## # # # # #
+## # # ### # # # # ## # # # # # # #### # # # ### #
+# # ## ## ### # # ## # ## ## ### # # # # # # # ###
+## ## # # # # # # # # # # ## ## # # ##
+# # # ### # # # # ## # # # ### # # # # # ## ## ## # ## #
+# # # # # ##### # ## # # # # # # # # # ## ## # # # ##
+# # # # # # # ## # ## # # # # # # ## ### ## # # ##### #
+# # # # # ## # # ## # # ## # ## # # # # ## # # # ## #
+## ## # # # # # # ### # ## ### ## # ### # ## # # # ## # # ## # #
+# # # # #### # ## #### # # # # # # # # # # ### # ## # #
+# # ## # # # # # # # # # # ###### # ## # ## # # # #### #### # #
+# # ##### # # # ### # # # # # # # # # ## ### # #
+# # # # # # # ## # # ## # # ## # # # # # # # ## # # ###
+## # ## # # # #### # # ## # ## ## # ## # # ## # #
+## # # # ## # # # # # # # # # # # ###### # ## # # ## ### # #### # #
+## # # # # # # # # # # # ## # # # # # # ## # # # ## # ##
+## # # # ### # # # # # # # # # # # # # # ###
+# # ### # # # # # ## ## ## # # ## # ### ### # # #
+# # # # # ## # # ## ## # # # # # # ## ## ## #
+# ### # # ### # # # # ### # # # # # # # ## # ##
+# # ### ## ## ## ## # # ### # ## # # # # ## ## # # # # # #
+# ## # # # ## # # # # ## # ### #### # ## ###### ### #
+# # # # ### ### # # ## # # # ### ## # ## # # ## ##
+# # # ### #### # # # # ### # # # ## ### ## # ## #### # #
+# ### ## # # # # # # # # ### # # # # ## # ### ### ## #
+# # # # # # # # # # # ### ## ### # ## # # # ## # #### # ## # #
+# # # # # # # # # # # ### # # # # # ## # # # # # # #
+# ## # # # # ## # # # ## ## ## # # ## # ## # # ## # ## #
+# # # ## # # # # ### # # # # # # ## # # # ## # ### ## # # #
+## # ## # ## ### ## # # # # ## # # # # # # #
+## ## # # ### # # # # # ## # # # # # ## # ## # # # #
+# # # ## # ### # ## # # ## # # # # # # # #
+# # # # # ## #### # # ### # ## # # ## # # ## #
+# # # # ## # ### # ## ## # # # # ### # # #
+# # # # # # # # # ## # ## ## ### ### # # ## # # # ## #
+# # # # ## # # ### ##### # # # # ## # # # # # ## # # #
+## # # # ## # # ## # ## ## # ## # ### # # # # #
+# ## ## # ### # ## ### # # ## # # # # # # # # # # # ###
+# ## # # # # # # # # # # # ## # # # # # # # # # # # ## #
+# # # # ## # # # # # ## # # ## # # ## # # # ### ### # # # ##
+# # # # ## # ## # # # # # # # ## # # ## # ### ##
+### # # ## ### # ## # # #### # # # # ##### # ## #### #
+# # # # # # # #### ## # ### ### # ## # # # # ## # # # # # # ###
+# #### # ## # # # # # # ## # # # # # # # #
+# ## # # # # # # ## # ## ## # ### #### # # # # ## #
+# # ## # ## # # # # ## ## # ## # ## #
+# # # # # # # ## # # # # # # ### ## ### # ## # # ###
+### # # # ##### # ## ## # # # ## # ## ## # # # # # #
+# # # # # # ## ##### # ### # ## # # # ## # ### #### # #
+# # ### # ## # # ### ## ## # ## # ### # ## ### # ###
+# ## ## ## # # # # # # ### # ## # # ## # # # #
+## ## ## # ## # ## # # # ## # ## # ## # ## # # # #
+# # # # # # # # ## # # # ####### # ## ## ## ##
+# # # # # # # # # ## # # # # # ## # # ### # ##
+# # ## #### # # # # # ## ### # ### # ### # ### ## # # #
+## # # ## # # # # # # # # ## # ##### # ## ##### #### ###
+# # # # ## # ## # # ## # # ### ## ## # ######
+# # ## # # # # # # # # # ## ## # ## ## ## # ## # #
+### #### # # ## # # # # # ## # # ## # # # #### # # ## # #
+# ## ## # # ## # ## ## # # ## # # # # # #### # #
+# ## # # # ## ### ## #### # # # # # # ## ### # # ##
+## # # # # # # # ## # ## ### # ## # ## # # #
+# # # # # # # # # ### # # # ## # # ## ## # #### #
+# # ## # # # # # # # # # # ## ### # # # ##
+## ## # ## # # # ## # # # # # #### # # ## ### #
+## # ## ## # # # # ### # # ## # # # ## ## # # # # ## #
+# ## # ## # # #### # # # # # # ## # # # # # # ### #
+# ## # #### # # ## # # # # ### ## # ## ### # ## ## ##
+# # # # # # ## # # # ## # #### # ##### # # # # # # #
+# # ## ## ### # ### ### # # #### # # # # ## # ## # # # # #### # #
+# # # # ## # # ## # # ## # # ## # ## # # # ## ## #
+# # ## # # # ## ## # ### ## # ## # # # # # # # ## # # #
+# # ## # ## ## ## # # ## # # # # # ## # # # # ### # #
+# # # ## # # # # # # # # # # # # ## # # # ## # # #
+## # ## # # # # ## # # ## # # # # # # ## # # # # # # # #
+# # ## # ## # ### # # ### # ## # # # ## # ### # ## # #
+# # # ## # # ## # # # ## # # #### ## # # # ### # ##
+# #### ## ### ### # # ### # # ## # # # ### # ####### # ## # E#
+####################################################################################################
diff --git a/zaharoves/задание 2/maze_medium.txt b/zaharoves/задание 2/maze_medium.txt
new file mode 100644
index 0000000..76efa05
--- /dev/null
+++ b/zaharoves/задание 2/maze_medium.txt
@@ -0,0 +1,50 @@
+##################################################
+#S# # ## ## # # ## ### ########
+# # # # ##### # ## # # ### # #
+# # # # # # # # ### ## # # # # #
+# # ## ### ### # ## ## ## # # ## ##
+## # # # # ## # # ## ## # #
+# # # ## ### # # # ### # # # ##
+# ## # ## ### ### # # # # # #
+## # #### # # # ## # # # # ## ## #
+# ## # ## # ## # #### # # # # # #
+## ## ## ##### ## # # #
+# # ## ## # # # # # ## ### # ##
+#### # # # ### # # # # # # # #
+# # # # # ## # ## # ## # # ######
+# ## ###### # ## # ## # # # #
+# # ## #### ## ### ## ## ###
+## ## # ### # # ## # # #
+## ## # # # # # ## # # ## ##
+# # # # # # ## # #
+## # # ## # # ### # # # # # # # #
+## # ## ## # ## # # #
+# ### ## # # # # # # # # ###
+# # ## # ## ## # #### ## ### # # ##
+# ## ## # # # ## # # # ## ## #
+# # ## # ## ### # # # # ### #
+# # # # # # ####### # # ## ### ##
+# # #### # # ### # ## ### # # # #
+# # ### # ## # # # # # # ## #
+# # ## ### # ## # # # # # # #
+# # ## # # # # # ### # # ## # ##
+### #### # # ## # # # ## # ## #
+## # #### # # ## # ## # #
+# # # # # ## ## ## # # #
+# # ### ### # ## # # # ###
+#### # # ## # # ## # ### # # #
+# # # #### # ## # ## # # # ##
+# # # # # ### # # ## # # #
+# # # # #### #### ## # ## # ### ## #
+### ## # # # # # # # # # # # #
+# # # # # # ### ## # ###### #
+## # ### ## # ### ## # # # ## ## # #
+# # ### # # ## #### #
+#### # #### # ## # # # ### ### ##
+# # # ### # ## # # # # # # #
+# # # ### ## # # # ## # #
+## # # # # #### # # # ### #
+## ## ## # # ### # # # # ## #
+# # ## #### ### # # # # # # ## # ### #
+# ### # ## ## ## # # # # # E#
+##################################################
diff --git a/zaharoves/задание 2/maze_no_exit.txt b/zaharoves/задание 2/maze_no_exit.txt
new file mode 100644
index 0000000..639bf8f
--- /dev/null
+++ b/zaharoves/задание 2/maze_no_exit.txt
@@ -0,0 +1,20 @@
+####################
+#S### # ## ## # #
+# # # ## #
+# ####### ## #
+# # # ## ## #
+# ## # # ###
+## # # # # #
+# # # # # # #
+## # # # # # #
+# # # ## ### #
+## ## ## ## #
+# # ## ## ##
+# # # # # #
+# ## # # ## #
+### # # # # #
+## ### # ##
+# # ### # # # ##
+# ## # ## ###
+# ### # #E#
+####################
diff --git a/zaharoves/задание 2/maze_small.txt b/zaharoves/задание 2/maze_small.txt
new file mode 100644
index 0000000..07daed1
--- /dev/null
+++ b/zaharoves/задание 2/maze_small.txt
@@ -0,0 +1,10 @@
+##########
+#S #
+# # ######
+# # # #
+# # # # #
+# # # # #
+# #
+#### #####
+# E #
+##########
diff --git a/zaharoves/задание 2/path_Без выхода 20×20.png b/zaharoves/задание 2/path_Без выхода 20×20.png
new file mode 100644
index 0000000..6bbf31f
Binary files /dev/null and b/zaharoves/задание 2/path_Без выхода 20×20.png differ
diff --git a/zaharoves/задание 2/path_Большой 100×100.png b/zaharoves/задание 2/path_Большой 100×100.png
new file mode 100644
index 0000000..2d0a2d7
Binary files /dev/null and b/zaharoves/задание 2/path_Большой 100×100.png differ
diff --git a/zaharoves/задание 2/path_Маленький 10×10.png b/zaharoves/задание 2/path_Маленький 10×10.png
new file mode 100644
index 0000000..aa24ab2
Binary files /dev/null and b/zaharoves/задание 2/path_Маленький 10×10.png differ
diff --git a/zaharoves/задание 2/path_Пустой 50×50.png b/zaharoves/задание 2/path_Пустой 50×50.png
new file mode 100644
index 0000000..8abd9e9
Binary files /dev/null and b/zaharoves/задание 2/path_Пустой 50×50.png differ
diff --git a/zaharoves/задание 2/path_Средний 50×50.png b/zaharoves/задание 2/path_Средний 50×50.png
new file mode 100644
index 0000000..3e42168
Binary files /dev/null and b/zaharoves/задание 2/path_Средний 50×50.png differ
diff --git a/zaharoves/задание 2/results.csv b/zaharoves/задание 2/results.csv
new file mode 100644
index 0000000..6f54560
--- /dev/null
+++ b/zaharoves/задание 2/results.csv
@@ -0,0 +1,21 @@
+лабиринт,стратегия,время_мс,посещено_клеток,длина_пути
+Маленький 10×10,BFS,0.0791,39,14
+Маленький 10×10,DFS,0.0605,30,18
+Маленький 10×10,A*,0.1048,34,14
+Маленький 10×10,Дейкстра,0.114,39,14
+Средний 50×50,BFS,1.9826,1305,95
+Средний 50×50,DFS,0.8278,529,199
+Средний 50×50,A*,0.909,303,95
+Средний 50×50,Дейкстра,3.9224,1305,95
+Большой 100×100,BFS,10.3434,6583,195
+Большой 100×100,DFS,8.13,5190,521
+Большой 100×100,A*,6.0666,1978,195
+Большой 100×100,Дейкстра,20.0361,6583,195
+Пустой 50×50,BFS,3.7195,2304,95
+Пустой 50×50,DFS,2.5223,1223,1129
+Пустой 50×50,A*,7.1408,2304,95
+Пустой 50×50,Дейкстра,7.6677,2304,95
+Без выхода 20×20,BFS,0.2898,193,0
+Без выхода 20×20,DFS,0.2849,193,0
+Без выхода 20×20,A*,0.5278,193,0
+Без выхода 20×20,Дейкстра,0.5431,193,0
diff --git a/zaharoves/задание 2/time_Без выхода 20×20.png b/zaharoves/задание 2/time_Без выхода 20×20.png
new file mode 100644
index 0000000..7f21fd2
Binary files /dev/null and b/zaharoves/задание 2/time_Без выхода 20×20.png differ
diff --git a/zaharoves/задание 2/time_Большой 100×100.png b/zaharoves/задание 2/time_Большой 100×100.png
new file mode 100644
index 0000000..1f77c66
Binary files /dev/null and b/zaharoves/задание 2/time_Большой 100×100.png differ
diff --git a/zaharoves/задание 2/time_Маленький 10×10.png b/zaharoves/задание 2/time_Маленький 10×10.png
new file mode 100644
index 0000000..325498b
Binary files /dev/null and b/zaharoves/задание 2/time_Маленький 10×10.png differ
diff --git a/zaharoves/задание 2/time_Пустой 50×50.png b/zaharoves/задание 2/time_Пустой 50×50.png
new file mode 100644
index 0000000..470a18b
Binary files /dev/null and b/zaharoves/задание 2/time_Пустой 50×50.png differ
diff --git a/zaharoves/задание 2/time_Средний 50×50.png b/zaharoves/задание 2/time_Средний 50×50.png
new file mode 100644
index 0000000..5aba1c7
Binary files /dev/null and b/zaharoves/задание 2/time_Средний 50×50.png differ
diff --git a/zaharoves/задание 2/visited_Без выхода 20×20.png b/zaharoves/задание 2/visited_Без выхода 20×20.png
new file mode 100644
index 0000000..0a01f3d
Binary files /dev/null and b/zaharoves/задание 2/visited_Без выхода 20×20.png differ
diff --git a/zaharoves/задание 2/visited_Большой 100×100.png b/zaharoves/задание 2/visited_Большой 100×100.png
new file mode 100644
index 0000000..edcb37c
Binary files /dev/null and b/zaharoves/задание 2/visited_Большой 100×100.png differ
diff --git a/zaharoves/задание 2/visited_Маленький 10×10.png b/zaharoves/задание 2/visited_Маленький 10×10.png
new file mode 100644
index 0000000..249fbd9
Binary files /dev/null and b/zaharoves/задание 2/visited_Маленький 10×10.png differ
diff --git a/zaharoves/задание 2/visited_Пустой 50×50.png b/zaharoves/задание 2/visited_Пустой 50×50.png
new file mode 100644
index 0000000..aa7c867
Binary files /dev/null and b/zaharoves/задание 2/visited_Пустой 50×50.png differ
diff --git a/zaharoves/задание 2/visited_Средний 50×50.png b/zaharoves/задание 2/visited_Средний 50×50.png
new file mode 100644
index 0000000..b35591d
Binary files /dev/null and b/zaharoves/задание 2/visited_Средний 50×50.png differ
diff --git a/zaharoves/задание 2/Графики.docx b/zaharoves/задание 2/Графики.docx
new file mode 100644
index 0000000..7bcb5f3
Binary files /dev/null and b/zaharoves/задание 2/Графики.docx differ
diff --git a/zaharoves/задание 2/Отчёт.docx b/zaharoves/задание 2/Отчёт.docx
new file mode 100644
index 0000000..4abdb82
Binary files /dev/null and b/zaharoves/задание 2/Отчёт.docx differ