forked from UNN/2026-rff_mp
136 lines
4.7 KiB
Python
136 lines
4.7 KiB
Python
import os
|
||
from maze_core import Maze, Cell
|
||
from maze_builder import TextMazeBuilder
|
||
from pathfinding import BFSSearch, DFSSearch, AStarSearch
|
||
from solver import MazeSolver
|
||
from patterns import ConsoleObserver, Player, MoveCommand
|
||
|
||
def select_maze_file() -> str:
|
||
print("\n Доступные лабиринты:")
|
||
print("1 - small (10×10, демо)")
|
||
print("2 - medium (50×50, стандарт)")
|
||
print("3 - large (100×100, сложный)")
|
||
print("4 - empty (пустой, тест скорости)")
|
||
print("5 - no_exit (без выхода, проверка ошибок)")
|
||
|
||
while True:
|
||
choice = input("\nВыберите номер (1-5): ").strip()
|
||
mapping = {
|
||
'1': 'small.txt', '2': 'medium.txt', '3': 'large.txt',
|
||
'4': 'empty.txt', '5': 'no_exit.txt'
|
||
}
|
||
if choice in mapping:
|
||
return mapping[choice]
|
||
print(" Неверный ввод. Введите число от 1 до 5.")
|
||
|
||
def draw_maze(maze: Maze, path=None):
|
||
if maze.width > 30 or maze.height > 30:
|
||
return False
|
||
|
||
path_set = set(path) if path else set()
|
||
print("\n Карта лабиринта:")
|
||
for y in range(maze.height):
|
||
row = []
|
||
for x in range(maze.width):
|
||
cell = maze.cell_at(x, y)
|
||
if cell in path_set:
|
||
if cell.is_start: row.append('S')
|
||
elif cell.is_exit: row.append('E')
|
||
else: row.append('*')
|
||
else:
|
||
row.append(str(cell))
|
||
print(''.join(row))
|
||
return True
|
||
|
||
def main():
|
||
|
||
selected_file = select_maze_file()
|
||
maze_path = os.path.join(os.path.dirname(__file__), 'data', selected_file)
|
||
|
||
try:
|
||
builder = TextMazeBuilder()
|
||
maze = builder.load(maze_path)
|
||
print(f"\nЗагружен: {selected_file} ({maze.width}x{maze.height})")
|
||
|
||
if not draw_maze(maze):
|
||
print(" (слишком большой для отрисовки в консоли)")
|
||
except FileNotFoundError:
|
||
print(f" Файл {selected_file} не найден в папке data/")
|
||
return
|
||
except Exception as e:
|
||
print(f" Ошибка загрузки: {e}")
|
||
return
|
||
|
||
|
||
solver = MazeSolver(maze)
|
||
view = ConsoleObserver()
|
||
solver.add_observer(view)
|
||
|
||
strategies = {
|
||
"BFS": BFSSearch(),
|
||
"DFS": DFSSearch(),
|
||
"A*": AStarSearch()
|
||
}
|
||
|
||
results = []
|
||
for name, strategy in strategies.items():
|
||
solver.set_strategy(strategy)
|
||
print(f"\n🔍 {name}:")
|
||
stats = solver.solve()
|
||
|
||
print(f" Время: {stats.time_ms:.3f} мс")
|
||
print(f" Клеток посещено: {stats.visited_cells}")
|
||
print(f" Длина пути: {stats.path_length}")
|
||
|
||
if solver.last_path:
|
||
if not draw_maze(maze, path=solver.last_path):
|
||
print(" (путь не отрисован из-за размера)")
|
||
else:
|
||
print(" Путь не найден!")
|
||
|
||
results.append((name, stats))
|
||
|
||
print(f"{'Алгоритм':<10} {'Время (мс)':<15} {'Посещено':<12} {'Длина':<8}")
|
||
|
||
for name, stats in results:
|
||
print(f"{name:<10} {stats.time_ms:<15.3f} {stats.visited_cells:<12} {stats.path_length:<8}")
|
||
|
||
# 4. Интерактивный режим (только для маленьких)
|
||
if maze.width <= 30 and maze.height <= 30:
|
||
if input("\n Запустить интерактивный режим? (y/n): ").lower() == 'y':
|
||
interactive_mode(maze)
|
||
else:
|
||
print("\n Для игры запустите программу ещё раз и выберите small.txt")
|
||
|
||
def interactive_mode(maze: Maze):
|
||
player = Player(maze.start_cell)
|
||
view = ConsoleObserver()
|
||
history = []
|
||
|
||
while True:
|
||
view.draw(maze, player=player.pos)
|
||
if player.pos == maze.exit_cell:
|
||
print("\n Ура победа! Выход найден!")
|
||
break
|
||
|
||
move = input("Ход (W/A/S/D, U=отмена, Q=выход): ").upper()
|
||
if move == 'Q': break
|
||
if move == 'U' and history:
|
||
history.pop().undo()
|
||
continue
|
||
|
||
dirs = {'W': (0,-1), 'S': (0,1), 'A': (-1,0), 'D': (1,0)}
|
||
if move not in dirs: continue
|
||
|
||
dx, dy = dirs[move]
|
||
new_cell = maze.cell_at(player.pos.x + dx, player.pos.y + dy)
|
||
|
||
if new_cell and new_cell.passable():
|
||
cmd = MoveCommand(player, new_cell)
|
||
cmd.execute()
|
||
history.append(cmd)
|
||
else:
|
||
print(" Стена! Нельзя пройти.")
|
||
|
||
if __name__ == "__main__":
|
||
main() |