139 lines
4.8 KiB
Python
139 lines
4.8 KiB
Python
|
|
"""
|
|||
|
|
Главный файл запуска — интерактивное меню.
|
|||
|
|
|
|||
|
|
Запуск: python main.py
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
|
|||
|
|
from maze_builder import TextFileMazeBuilder
|
|||
|
|
from maze_solver import MazeSolver
|
|||
|
|
from strategies import BFSStrategy, DFSStrategy, AStarStrategy, DijkstraStrategy
|
|||
|
|
from observer import ConsoleView
|
|||
|
|
from command import Player, MoveCommand
|
|||
|
|
|
|||
|
|
STRATEGIES = {
|
|||
|
|
"1": ("BFS", BFSStrategy),
|
|||
|
|
"2": ("DFS", DFSStrategy),
|
|||
|
|
"3": ("A*", AStarStrategy),
|
|||
|
|
"4": ("Dijkstra", DijkstraStrategy),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DIRECTION_MAP = {
|
|||
|
|
"w": (0, -1),
|
|||
|
|
"s": (0, 1),
|
|||
|
|
"a": (-1, 0),
|
|||
|
|
"d": (1, 0),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def choose_strategy():
|
|||
|
|
print("\nВыберите алгоритм:")
|
|||
|
|
for key, (name, _) in STRATEGIES.items():
|
|||
|
|
print(f" {key}. {name}")
|
|||
|
|
choice = input("Ваш выбор: ").strip()
|
|||
|
|
if choice not in STRATEGIES:
|
|||
|
|
print("Неверный выбор, используется BFS.")
|
|||
|
|
return BFSStrategy()
|
|||
|
|
name, cls = STRATEGIES[choice]
|
|||
|
|
print(f"Выбран: {name}")
|
|||
|
|
return cls()
|
|||
|
|
|
|||
|
|
|
|||
|
|
def interactive_walk(maze, path):
|
|||
|
|
"""Пошаговое ручное перемещение игрока по лабиринту (паттерн Command)."""
|
|||
|
|
player = Player(maze.start)
|
|||
|
|
view = ConsoleView()
|
|||
|
|
history: list[MoveCommand] = []
|
|||
|
|
|
|||
|
|
print("\n=== Ручное управление ===")
|
|||
|
|
print("W/A/S/D — движение, U — отмена, Q — выход")
|
|||
|
|
view.render(maze, path=path, player=player.current_cell)
|
|||
|
|
|
|||
|
|
while True:
|
|||
|
|
cmd_input = input("Ход: ").strip().lower()
|
|||
|
|
|
|||
|
|
if cmd_input == "q":
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if cmd_input == "u":
|
|||
|
|
if history:
|
|||
|
|
history.pop().undo()
|
|||
|
|
view.render(maze, path=path, player=player.current_cell)
|
|||
|
|
else:
|
|||
|
|
print("Нет ходов для отмены.")
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
if cmd_input in DIRECTION_MAP:
|
|||
|
|
dx, dy = DIRECTION_MAP[cmd_input]
|
|||
|
|
nx, ny = player.current_cell.x + dx, player.current_cell.y + dy
|
|||
|
|
if 0 <= nx < maze.width and 0 <= ny < maze.height:
|
|||
|
|
target = maze.get_cell(nx, ny)
|
|||
|
|
cmd = MoveCommand(player, target, maze)
|
|||
|
|
cmd.execute()
|
|||
|
|
history.append(cmd)
|
|||
|
|
view.render(maze, path=path, player=player.current_cell)
|
|||
|
|
if player.current_cell == maze.exit:
|
|||
|
|
print("🎉 Вы достигли выхода!")
|
|||
|
|
break
|
|||
|
|
else:
|
|||
|
|
print("За пределами лабиринта.")
|
|||
|
|
else:
|
|||
|
|
print("Неизвестная команда.")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
print("╔══════════════════════════════╗")
|
|||
|
|
print("║ Решатель лабиринтов ║")
|
|||
|
|
print("╚══════════════════════════════╝")
|
|||
|
|
|
|||
|
|
# Выбор файла
|
|||
|
|
mazes_dir = "mazes"
|
|||
|
|
if os.path.isdir(mazes_dir):
|
|||
|
|
files = [f for f in sorted(os.listdir(mazes_dir)) if f.endswith(".txt")]
|
|||
|
|
if files:
|
|||
|
|
print("\nДоступные лабиринты:")
|
|||
|
|
for i, f in enumerate(files, 1):
|
|||
|
|
print(f" {i}. {f}")
|
|||
|
|
choice = input("Выберите номер (или введите путь): ").strip()
|
|||
|
|
if choice.isdigit() and 1 <= int(choice) <= len(files):
|
|||
|
|
maze_path = os.path.join(mazes_dir, files[int(choice) - 1])
|
|||
|
|
else:
|
|||
|
|
maze_path = choice
|
|||
|
|
else:
|
|||
|
|
maze_path = input("Путь к файлу лабиринта: ").strip()
|
|||
|
|
else:
|
|||
|
|
maze_path = input("Путь к файлу лабиринта: ").strip()
|
|||
|
|
|
|||
|
|
# Загрузка
|
|||
|
|
builder = TextFileMazeBuilder()
|
|||
|
|
try:
|
|||
|
|
maze = builder.build_from_file(maze_path)
|
|||
|
|
print(f"\nЛабиринт загружен: {maze.width}×{maze.height}")
|
|||
|
|
except (FileNotFoundError, ValueError) as e:
|
|||
|
|
print(f"Ошибка: {e}")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# Выбор стратегии и решение
|
|||
|
|
strategy = choose_strategy()
|
|||
|
|
view = ConsoleView()
|
|||
|
|
|
|||
|
|
solver = MazeSolver(maze, strategy)
|
|||
|
|
solver.add_observer(view)
|
|||
|
|
stats = solver.solve()
|
|||
|
|
|
|||
|
|
print(f"\n── Статистика ──────────────────")
|
|||
|
|
print(f" Время: {stats.time_ms:.4f} мс")
|
|||
|
|
print(f" Посещено клеток: {stats.visited_cells}")
|
|||
|
|
print(f" Длина пути: {stats.path_length}")
|
|||
|
|
|
|||
|
|
# Предложить ручное управление
|
|||
|
|
if stats.path:
|
|||
|
|
walk = input("\nЗапустить ручное управление? (y/n): ").strip().lower()
|
|||
|
|
if walk == "y":
|
|||
|
|
interactive_walk(maze, stats.path)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|