Skip to content

meshcher-roman/Animation_pp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A* Pathfinding Visualizer (PyQt6)

🗺️ Описание проекта

Данный проект представляет собой визуализатор алгоритма поиска кратчайшего пути A* (A-Star) на сетке (Grid Map), реализованный на Python с использованием библиотеки PyQt6. Приложение позволяет генерировать случайные лабиринты, вручную добавлять или удалять препятствия (стены) и в реальном времени наблюдать за процессом поиска оптимального пути между стартовой и конечной точкой.

✨ Реализация пользовательских запросов

На основе предоставленного кода были проанализированы и реализованы следующие функции:

  1. Простые изменения

    • Клик для добавления/удаления стен

      • Статус: Реализовано.

      • Как реализовано: Пользователь может кликать и перетаскивать левую кнопку мыши (ЛКМ) по карте, чтобы рисовать или стирать стены. Логика находится в методах GridMapWidget.mousePressEvent и GridMapWidget.mouseMoveEvent.

      • Показать длину пути

      • Статус: Реализовано.

      • Как реализовано: По завершении поиска в информационном окне (self.lbl_info) отображается точное количество шагов (ребер) в найденном пути. Расчет и вывод происходит в методе AStarWorker.reconstruct_path.

  2. Новые функции и гибкость

  • Разрешить движение по диагонали

    • Статус: Не реализовано.

    • Комментарий: Текущий код использует только 4-направленное (кардинальное) движение. Для активации диагоналей необходимо изменить функцию AStarWorker.get_neighbors (добавить 8 направлений) и использовать более точную эвристику, например, Евклидово расстояние.

    • Дополнительная интерактивная функция (Гибкость)

    • Статус: Реализована.

    • Комментарий: Функция интерактивного рисования/стирания стен с помощью ЛКМ и перетаскивания является ключевой интерактивной функцией приложения.

  • 🎓 Теория алгоритма A*

    • Алгоритм A* является одним из самых эффективных алгоритмов поиска пути, поскольку он объединяет информированный поиск (использует эвристику) и гарантию оптимальности.

    • Используемые формулы

    • A* использует функцию стоимости $F(n)$, которая определяет приоритет узла $n$:

    • $$F(n) = G(n) + H(n)$$

    • $F(n)$ (Общая стоимость): Оценочная общая стоимость пути от старта до финиша, проходящего через узел $n$.

    • $G(n)$ (Фактическая стоимость): Фактическая стоимость (длина) пути от начальной точки до узла $n$.

    • $H(n)$ (Эвристическая стоимость): Оценочная стоимость пути от узла $n$ до конечной точки.

  • В текущем коде используется Манхэттенское расстояние (Manhattan Distance) для расчета эвристики $H(n)$, что подходит для 4-направленного движения:

  • $$H(n) = |x_{n} - x_{end}| + |y_{n} - y_{end}|$$

Ответы на теоретические вопросы

  • Как компьютер знает, в каком направлении искать?

    Алгоритм всегда ищет узел с наименьшей F-стоимостью ($F = G + H$) из своего Открытого списка. Эвристика ($H$) направляет поиск к цели, а фактическое расстояние ($G$) гарантирует, что найденный путь будет кратчайшим (оптимальным).

  • Что будет, если не угадать направление (эвристика окажется неточной)?

    Если эвристика приведет алгоритм по неоптимальному пути, G-стоимость (фактическое пройденное расстояние) для этой ветки пути быстро возрастет, что увеличит общую $F$-стоимость. Благодаря этому, этот путь будет отброшен в пользу другого кандидата с более низкой $F$-стоимостью. При использовании допустимой эвристики (как Манхэттенское расстояние) A* всегда находит оптимальный путь.

  • Зачем вести два списка клеток?

    Open Set (Открытый список): Хранит кандидатов — узлы, которые были обнаружены, но еще не полностью обработаны. Этот список отсортирован по $F$-стоимости (используется heapq).

    Closed Set (Закрытый список): Хранит клетки, уже проверенные и оцененные. Это предотвращает повторную обработку и зацикливание, повышая эффективность.

  • Зачем проверять клетки больше одного раза?

    Узел, который уже был добавлен в Open Set, может быть переоценен, если алгоритм находит более короткий путь к нему через другого соседа (то есть, находит более низкую $G$-стоимость). В этом случае, $G$-стоимость узла обновляется, и он заново обрабатывается с новым, лучшим приоритетом $F$, чтобы обеспечить оптимальность.

💻 Структура кода и назначение компонентов

  1. Конфигурация (config.json и load_config)

    • Настройки приложения загружаются из файла config.json или используются значения по умолчанию.

    • Назначение: Определяет размеры сетки, задержку симуляции, плотность стен и цветовые схемы для визуализации.

  2. Класс Node (Модель данных)

Класс, представляющий одну клетку на сетке.

  • Атрибуты:

    • row, col: Координаты узла.

    • is_wall: Булево значение, указывающее, является ли узел препятствием.

    • state: Текущее состояние узла (empty, open, closed, path, start, end).

    • g_cost, h_cost: Параметры стоимости A*.

    • parent: Ссылка на предыдущий узел в кратчайшем найденном пути.

  • Свойства и методы:

    • f_cost: Вычисляемое свойство ($G + H$).

    • lt: Реализует сравнение, необходимое для корректной работы кучи приоритетов (heapq).

    • reset_calc: Сбрасывает все стоимостные параметры при запуске нового поиска.

  1. Класс GridMapWidget (Виджет отрисовки карты)

    Виджет PyQt6, отвечающий за визуальное представление сетки и обработку взаимодействия с пользователем.

    • Методы отрисовки:

      • paintEvent(event): Оптимизированный метод отрисовки. Использует QPainter для заполнения прямоугольников цветами, соответствующими состоянию узлов. Рисует только ту часть сетки, которая нуждается в обновлении (partial update).

      • update_node(r, c): Вызывает перерисовку только одной конкретной клетки для повышения производительности во время симуляции.

    • Методы взаимодействия:

      • mousePressEvent и mouseMoveEvent: Обрабатывают клики и перетаскивание ЛКМ. Определяют, находится ли пользователь в режиме рисования или стирания стен (self.drawing_wall_mode) и вызывают apply_wall.
  2. Класс AStarWorker (Рабочий поток алгоритма A*)

    • Наследник QThread, выполняет сложный алгоритм A* в отдельном потоке, чтобы избежать зависания графического интерфейса.

    • Сигналы:

      • cell_updated(r, c, state): Отправляет информацию в основной поток, чтобы виджет карты мог обновить цвет измененной клетки.

      • finished_signal(msg): Отправляет сообщение о завершении работы (найден путь или нет).

    • Ключевые методы A*:

      • run(): Основной цикл A*. Извлекает узел с минимальным $F$ из open_set (куча приоритетов), проверяет его соседей и обновляет их стоимости.

      • heuristic(node_a, node_b): Вычисляет эвристическое расстояние ($H$) — Манхэттенское расстояние.

      • get_neighbors(node): Возвращает список из 4-х соседних узлов (вверх, вниз, влево, вправо), исключая стены.

      • reconstruct_path(end_node): После достижения цели, восстанавливает путь, идя от конечного узла к стартовому по ссылкам parent, и отправляет сигналы на отрисовку найденного пути.

  3. Класс AStarApp (Главное окно приложения)

Основной класс QMainWindow, объединяющий все компоненты.

  • Методы управления данными:

    • init_data: Создает начальную структуру узлов (self.grid_nodes).

    • reset_data: Сбрасывает только параметры поиска или полностью очищает все стены.

    • generate_random_walls: Случайно расставляет стены на карте согласно заданной плотности.

  • Методы I/O:

    • load_maze_from_file: Загружает карту из текстового файла (S — старт, E — финиш, # — стена).

    • save_maze_to_file: Сохраняет текущую карту в текстовый файл.

  • Управление потоком:

    • start_thread: Инициализирует и запускает AStarWorker.

    • on_cell_updated и on_finished: Слоты, принимающие сигналы от рабочего потока и обновляющие UI (виджет карты и информационную метку).

Демонстрация работы кода

image

About

Лабораторные работы по дисциплине "Практикум по программированию"

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages