Вычисление кратчайшего маршрута между двумя точками

Я работаю в последние недели в многопользовательской игре 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].