it-swarm.com.de

Berechnung der kürzesten Route zwischen zwei Punkten

Ich habe in den letzten Wochen an einem Multiplayer-HTML5-Spiel mit nodejs und websockets gearbeitet.

Ich bin seit einiger Zeit in diesem Problem stecken geblieben. Stellen Sie sich vor, ich habe diese Tilesheet-Map mit einem Array implementiert (wie unten gezeigt).

1 oder braune Kacheln - Es gibt ein Hindernis im Weg und der Spieler kann es nicht passieren.

0 oder grüne Kacheln - sind freie Pfade, auf denen sich der Spieler bewegen darf. 

Greifen Sie auf ein beliebiges Feld auf der Karte zu, indem Sie Folgendes anrufen:

 array[x][y]

 tilesheet map - calculate the shortest route

Ich möchte einen möglichst schnellen Algorithmus erstellen, um die kürzeste Route (falls vorhanden) zwischen zwei Punkten der Karte herauszufinden. Wie würden Sie dieses Problem angehen? Ich weiß, dass dies ein häufiges Problem ist. 

Beispiel

Spieler an der Position (1,7) feuert eine Kugel mit einer KI ab, die auf den gegnerischen Spieler an der Position (6,0) gerichtet ist. Bullet muss die kürzeste Route zwischen den beiden Spielern berechnen, und wenn es keine gibt, würde sie nur gegen eine Wand explodieren.

Frage

Wie kann man den kürzesten Weg zwischen zwei Punkten effizient finden?

19
Daniel Oliveira

Dies ist ein allgemeiner Graphentheorieproblemalgorithmus

In der Graphentheorie ist das Problem des kürzesten Pfades das Problem, einen Pfad zwischen zwei Scheitelpunkten (oder Knoten) in einem Graphen zu finden, so dass die Summe von Der Gewichte seiner konstituierenden Kanten minimiert wird.

Das Problem, den kürzesten Weg zwischen zwei Kreuzungen auf Einer Straßenkarte zu finden (die Scheitelpunkte des Graphen entsprechen Schnittpunkten und die Kanten entsprechen Straßensegmenten, die jeweils mit der Länge ihres Gewichtet sind. ] Straßensegment) kann durch einen Sonderfall des Problems mit dem kürzesten Pfad in Graphen modelliert werden.

Für jetzt gibt es viele Implementierungen dieses Algorithmus. Einfacher in der Implementierung ist ein Dijkstra-Algorithmus mit Worst-Case-Leistung als O(|E|+|V|log|V|) wo

  • | V | ist die Anzahl von Knoten
  • | E | ist die Anzahl von Kanten

Illustration der Algorithmusarbeit

 enter image description here

Definition des kürzesten Pfad-Algorithmus von Dijkstra

  • Anfangsknoten - der Knoten, an dem wir beginnen.
  • Abstand des Knotens Y - sei der Abstand vom Anfangsknoten bisY.

Der Algorithmus weist einige anfängliche Entfernungswerte zu und versucht, sie schrittweise zu verbessern:

  1. Weisen Sie jedem Knoten einen vorläufigen Abstandswert zu: Setzen Sie ihn für unseren Anfangsknoten auf 0 und für alle anderen Knoten auf ∞.

  2. Setzen Sie den Anfangsknoten als aktuell. Alle anderen Knoten markieren nicht besucht . Erstellen Sie eine Gruppe aller unvisited Knoten, die als unvisited set bezeichnet werden.

  3. Betrachten Sie für den aktuellen Knoten alle seine Nachbarn Unvisited und berechnen Sie die vorläufigen Entfernungen. Vergleichen Sie den neu berechneten vorläufigen Abstand mit dem aktuell zugewiesenen Wert und weisen Sie den kleineren zu.

  4. Wenn Sie alle Nachbarn des aktuellen Knotens betrachtet haben, markieren Sie den aktuellen Knoten als besucht und entfernen Sie ihn aus dem unvisited set . Ein besuchter Knoten wird nie mehr überprüft.

  5. Wenn der Zielknoten als besucht markiert wurde (beim Planen einer Route zwischen zwei bestimmten Knoten) oder wenn der kleinste vorläufige Abstand zwischen den Knoten in unvisited set ∞ ist (wenn ein vollständiger Durchlauf geplant wird, tritt dies auf, wenn dies der Fall ist keine Verbindung zwischen dem ursprünglichen Knoten und den verbleibenden nicht besuchten Knoten), dann aufhören.Der Algorithmus ist beendet.

  6. Wählen Sie andernfalls den Knoten unvisited aus, der mit der kleinsten vorläufigen Entfernung markiert ist, stellen Sie ihn als neuen "aktuellen Knoten" ein und fahren Sie mit Schritt 3 fort.

Weitere Implementierungen des Dijkstra-Algorithmus finden Sie im github-Repository mburst/dijkstras-algorithm .

Zum Beispiel ist hier JavaScript-Implementierung

17
Alex Filatov

Während der Dijkstra-Algorithmus definitiv funktioniert, ist das Diagramm in Ihrem Fall ein nicht gewichtetes Diagramm, daher sollte ein einfaches BFS ausreichen.

Pseudo-Code:

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

Das prev array kann auch verwendet werden, um zu überprüfen, ob ein Punkt besucht wird.

3
Can Nguyen

Hier gibt es keine Bedingung für die Berechnung der Pfadkosten, da alle Pfadkosten 1 sind. Sie können also den normalen 2D-BFS-Algorithmus ausführen und die Komplexität ist O (V + E) (Vertex und Edge).

Hier hat jeder Knoten zwei Eigenschaften. Einer ist Zeile und der andere ist Spalte. Sie können also ein Paar erstellen, um den Wert einer Zelle anzugeben. Hier ist der C++ - Code und die Erklärung:

#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
            }
        }
    }
}

Jetzt können Sie den kürzesten Weg in der Zelle d [x] [y] leicht finden.

1
rafana