web-dev-qa-db-ja.com

2点間の最短ルートを計算する

私は過去数週間、nodejswebsocketsを使用してマルチプレイヤーHTML5ゲームに取り組んできました。

私はしばらくの間この問題で立ち往生しています。このタイルシートマップが配列で実装されていることを想像してください(次に示すように)。

1または茶色のタイル-障害物があり、プレイヤーはそれを通過できません。

または緑のタイル-プレイヤーが許可されているフリーパスです移動します。

次のコマンドを呼び出して、マップ上の任意のタイルにアクセスします。

 array[x][y]

tilesheet map - calculate the shortest route

地図の2点間の最短ルート(存在する場合)を見つけるために、可能な限り最速のアルゴリズムを作成したいと思います。この問題にどのように取り組みますか?これはよくある問題です。

(1,7)の位置にいるプレーヤーは、AI(6,0)の位置にいる敵プレーヤーに向かっていくAIで弾丸を発射します。 Bulletは、2人のプレイヤー間の最短ルートを計算する必要があります。ルートがない場合は、壁に向かって爆発します。

質問

2点間の最短ルートを効率的に見つける方法は?

19
Daniel Oliveira

これは一般的です グラフ理論問題アルゴリズム

グラフ理論では、最短経路問題は、グラフ内の2つの頂点(またはノード)間の経路を見つけて、その構成エッジの重みの合計が最小になる問題です。

道路地図上の2つの交差点間の最短経路を見つける問題(グラフの頂点は交差点に対応し、エッジは道路セグメントに対応し、それぞれが道路セグメントの長さで重み付けされます)は、最短経路の特殊なケースによってモデル化できます。グラフの問題。

今のところ存在します 多くの実装 このアルゴリズムの。より単純な実装は Dijkstraのアルゴリズム で、最悪の場合のパフォーマンスはO(|E|+|V|log|V|)

  • Vノードの数です
  • Eエッジの数です

アルゴリズム作業の図

enter image description here

ダイクストラの最短経路アルゴリズムの定義

  • 初期ノード-開始するノード。
  • ノードYの距離-初期ノードから[〜#〜] y [〜#〜]までの距離を指定します。

アルゴリズムはいくつかの初期距離値を割り当て、それらを段階的に改善しようとします:

  1. すべてのノードに暫定的な距離値を割り当てます。初期ノードの場合は0に設定し、他のすべてのノードの場合は∞に設定します。

  2. 初期ノードを現在のものとして設定します。他のすべてのノードをマークしますnvisitednvisited setと呼ばれるすべてのnvisitedノードのセットを作成します。

  3. 現在のノードについて、そのすべてのnvisitedネイバーを考慮し、それらの暫定距離を計算します。新しく計算された暫定距離を現在割り当てられている値と比較し、小さい方を割り当てます。

  4. 現在のノードのすべての隣接ノードの検討が終了したら、現在のノードを訪問済みとしてマークし、nvisited setから削除します。訪れたノードは二度とチェックされません。

  5. 宛先ノードが訪問済みとマークされている場合(2つの特定のノード間のルートを計画している場合)、またはnvisited set内のノード間の最小の仮の距離が∞である場合(完全なトラバーサルを計画している場合。最初のノードと残りの未訪問ノードの間に接続がない)、停止します。 アルゴリズムが終了しました

  6. それ以外の場合は、最小の暫定距離でマークされているnvisitedノードを選択し、それを新しい「現在のノード」として設定して、手順3に戻ります。

Githubリポジトリ mburst/dijkstras-algorithm で見つけることができるダイクストラアルゴリズムのより多くの実装。

たとえば、ここに JavaScript実装

17
Alex Filatov

ダイクストラアルゴリズムは確実に機能しますが、あなたの場合、グラフは重み付けされていないグラフであるため、単純な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
Can Nguyen

ここでは、すべてのパスコストが1であるため、パスコストを計算する条件はありません。したがって、ここで通常の2D BFSアルゴリズムを実行でき、複雑度はO(V + E)(頂点とエッジ)になります。

ここで、すべてのノードには2つのプロパティがあります。 1つは行で、もう1つは列です。したがって、uはセルの値を示すためのペアを作成できます。これがc ++コードと説明です:

#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]セルから最短経路を簡単に見つけることができます。

1
rafana