Очень долго в последнее время работаю над созданием интерактивных диаграмм. Одна из задача в таких диаграммах — это правильная прорисовка соединений. Соединения должны обходить препятствия.
Решения всегда разные, но один из самых распространенных случаев — применение алгоритма AStar. Подробно я его описывать не буду. Ибо его описание есть на вики. А цель этой статьи описать более понятный и конкретный алгоритм работы для дальнейшей реализации на Scala.
Предусловия:
- начальная позиция никогда не является препятствием
Алгоритм:
- Проверка на возможность пути (если проверка не успешная то выходим)
- Если начальная и конечная позиции равны, то возвращаем путь из одной вершины
- Если конечная позиция является препятствием, то путь невозможен и поэтому выходим
- В открытый список добавляется первая точка c вычисленными параметрами
- Цикл, пока не достигнем целевой точки
- Ищем в открытом списке (необработанный список) вершину с наименьшим значением эвристической функции F
- Если не нашли то путь невозможен и поэтому выходим
- Если нашли, то раскрываем эту вершину циклом по всем ее соседям:
- Проверяем является ли вершина препятствием. Если да, то переходим к следующей соседней
- Проверяем находится ли вершина в закрытом списке. Если да, то переходим к следующей соседней
- Вычисляем параметры вершины
- Если ее нет в открытом списке, то добавляем ее туда
- Раскрытую вершину удаляем из открытого списка и добавляем в закрытый
- Достигли целевой точки поэтому собираем путь (по параметру parent) и возвращаем его
Абстрактная реализация на Scala:
Для конкретной реализации необходимо:
- Реализовать класс вершины с примесью ASTarNode, в которой:
- Переопределен метод isAStarObstacle (возвращает true, если вершина является препятствием)
- Переопределить методы hashCode и euals таким образом, чтобы они зависели от координат вершины
- Реализовать класс поля на котором ищется путь с примесью ASTarField, в котором:
- Переопределить методы получения начальной и конечной вершины пути: getSourceNode и getTargetNode
- Переопределить метод получения эвристической функции — getHeuristic
- Переопределить метод итерации по соседним вершинам
Вот пример реализации для сетки, в которой вершины являются квадратными, а соседними вершинами считаются клетки по четырем сторонам:
На последок, совсем ужатая версия AStar.