Вычисление кратчайшего маршрута между двумя точками
Я работаю в последние недели в многопользовательской игре HTML5, используя nodejs
и websockets
.
Я немного застрял в этой проблеме.
Представьте, что у меня есть эта карта плитки, реализованная с массивом (как показано ниже).
1 или коричневые плитки - на пути есть препятствие, и игрок не может пройти через него.
0 или зеленые плитки - это бесплатные пути, где игроку разрешено перемещаться.
Доступ к любому фрагменту на карте, вызвав:
array[x][y]
![карта плитки - вычисление кратчайшего маршрута]()
Я хотел бы создать самый быстрый алгоритм, чтобы узнать самый короткий маршрут (если есть) между двумя точками карты. Как вы подходите к этой проблеме? Я знаю, что это обычная проблема.
Пример:
Игрок в позиции (1,7) стреляет пулей с некоторым ИИ, который будет направлен против вражеского игрока в позицию (6,0). Bullet должен рассчитать кратчайший маршрут между двумя игроками, и если он не будет просто взорваться от стены.
Вопрос:
Как эффективно найти кратчайший маршрут между двумя точками?
Ответы
Ответ 1
Это общий алгоритм алгоритм теории графов
В теории графов проблема кратчайшего пути - проблема нахождения путь между двумя вершинами (или узлами) в графе, так что сумма вес его составляющих ребер минимизируется.
Проблема нахождения кратчайшего пути между двумя пересечениями на дорожная карта (вершины графа соответствуют пересечениям и края соответствуют сегментам дороги, каждый из которых взвешен по длине участок дороги) может быть смоделирован специальным случаем кратчайшего пути проблема в графах.
На данный момент существует множество реализаций этого алгоритма. Более простым в реализации является алгоритм Dijkstra с наихудшей производительностью как O(|E|+|V|log|V|)
где
- | V | - количество узлов
- | E | - количество ребер
Иллюстрация работы алгоритма
![введите описание изображения здесь]()
Определение алгоритма кратчайшего пути Dijkstra
- начальный node - node, с которого мы начинаем.
- расстояние node Y - расстояние от начального node до Y.
Алгоритм назначит некоторые начальные значения расстояния и попытается улучшить их шаг за шагом:
-
Присвойте каждому node ориентировочное значение расстояния: установите для этого начального node значение 0, а для всех остальных узлов - ∞.
-
Установите начальный node как текущий. Отметьте все остальные узлы unvisited. Создайте набор всех невидимых узлов, которые называются unvisited set.
-
Для текущего node рассмотрите все его невидимые соседи и вычислите их предварительные расстояния. Сравните недавно просчитанное предварительное расстояние до текущего назначенного значения и назначьте меньший.
-
Когда мы закончим рассмотрение всех соседей текущего node, пометьте текущий node как посещенный и удалите его из неперечисленного набора. Посещенный node больше никогда не будет проверен.
-
Если пункт назначения node был отмечен посещенным (при планировании маршрута между двумя конкретными узлами) или если наименьшее предварительное расстояние между узлами в недоступном наборе равно ∞ (когда планирование полного обхода, происходит, когда нет связи между начальным node и оставшимися нераскрытыми узлами), а затем останавливается. Законченный алгоритм.
-
В противном случае выберите unvisited node, который отмечен наименьшим ориентировочным расстоянием, установите его как новый "текущий node" и вернитесь к шагу 3.
Дополнительные реализации алгоритма Дейкстры, которые вы можете найти в репозитории github mburst/dijkstras-algorithm.
Например, здесь реализация JavaScript
Ответ 2
Хотя алгоритм dijkstra определенно работает, в вашем случае график является невзвешенным графом, поэтому достаточно просто BFS.
Псевдокод:
queue = [startingposition]
prev = [-1, -1, -1 ...] (array of n elements, all -1)
while (queue not empty)
u <- pop(queue)
if u = targetposition then DONE! trace the *prev* array for path
for (v in every unvisited points adjacent to u):
prev[v] = u
push v to queue
end for
end while
Аргумент prev также может использоваться для проверки того, посетила ли точка.
Ответ 3
Здесь нет условия вычисления стоимости пути, потому что все затраты на путь равны 1. Таким образом, вы можете запускать здесь обычный 2D-алгоритм BFS, а сложность будет O (V + E) (вершина и край).
Здесь каждый node имеет два свойства. Один - это строка, а другая - столбец. Таким образом, u может создать пару для обозначения значения ячейки. Вот код и объяснение С++:
#define pii pair<int,int>
int fx[]={1,-1,0,0}; //Direction array for moving one cell to another cell horizontaly
int fy[]={0,0,1,-1}; //Direction array for moving one cell to another cell verticaly
int cell[100][100]; //cell[x][y] if this cell is -1 then it is block (Here it is your brown cell)
int d[100][100],vis[100][100]; //d means destination from source.
int row,col;
void bfs(int sx,int sy) //Source node is in [sx][sy] cell.
{
memset(vis,0,sizeof vis);
vis[sx][sy]=1;
queue<pii>q; //A queue containing STL pairs
q.push(pii(sx,sy));
while(!q.empty())
{
pii top=q.front(); q.pop();
for(int k=0;k<4;k++)
{
int tx=top.uu+fx[k];
int ty=top.vv+fy[k]; //Neighbor cell [tx][ty]
if(tx>=0 and tx<row and ty>=0 and ty<col and cell[tx][ty]!=-1 and vis[tx][ty]==0) //Check if the neighbor is valid and not visited before.
{
vis[tx][ty]=1;
d[tx][ty]=d[top.uu][top.vv]+1;
q.push(pii(tx,ty)); //Pushing a new pair in the queue
}
}
}
}
Теперь вы можете легко найти свой самый короткий путь из ячейки d [x] [y].