128 lines
4.1 KiB
Python
128 lines
4.1 KiB
Python
|
||
|
||
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):
|
||
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("Решатель лабиринтов")
|
||
|
||
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()
|