web-dev-qa-db-ja.com

大きな地図での経路探索

10,000 x10,000のマップでゲームを作成しています。
ユーザーが場所を設定し、コンピューターがすぐに最適なパスを見つけられるようにしたいと思います。
ただし、マップは10,000 x 10,000であるため、ノードは1億個あり、A *やダイクストラなどの従来の方法でこのパスを見つけるには、大量のメモリと長い時間が必要になります。
それで私の質問は:どうすれば最良の道を見つけることができますか?
私が検討しているアルゴリズムは、世界を100のセクションに分割し、それぞれに1,000,000のノードがあります。次に、各セクションは100のサブセクションに分割されます。これは、各サブセクションに100個のノードが含まれるまで繰り返されます。次に、アルゴリズムは、ノードの最適なセットが見つかるまで、セクション、サブセクション、サブサブセクションの最適なパスを検索します。これは機能しますか?より良い方法はありますか?
ジャンプポイント検索も検討していますが、わかりません。それができないことを見つけるだけで学ぶのは大変です。

編集:A *を追加しようとしました。ただし、実行には約5秒かかり、理想よりも約4秒長くなります。

19
James McDowell

マップは10.000x 10.000であるため、ノードの数は100.000.000です。 A *の単純な実装を使用することは非現実的であり、確かにゲームをマップサイズでスケーラブルにすることはできません。

次の解決策を使用することをお勧めします。これは基本的にあなたが考えていたものです。

HPA *(階層パスA *)。このメソッドは、マップのさまざまな階層を作成します。 100x100ピクセルのすべてのブロックが領域であると言うことで、プロセスを自動化できます。次に、すべてのブロックについて、隣接するブロックと、各ブロックの入口と出口がどこにあるかを見つける必要があります。 2つのブロック間の接続がノードを超える場合は、2つのノードを使用して問題を表します。この画像は、私たちが作成しようとしている新しいグラフを説明しています。 (黒=障害物と灰色はブロック間のノードを接続しています)。

enter image description here

この方法は、すべてのブロックが10x10であるゲームBaldur's Gateのマップを使用した実行からわかるように、良好な結果を提供します。

enter image description here

詳細については、Nathan Sturtevantのこの記事を読んでください(彼はゲームに関して最も成功した経路探索研究者の1人です)。 https://skatgame.net/mburo/ps/path.pdf

HPAの説明については、スターテバントのこの講義を確認してください(HPAの場合は43:50分)。 https://www.youtube.com/watch?v=BVd5f66U4Rw

また、HPA *の動作を確認したい場合は、スターテバントが作成した次のビデオを確認してください。 https://www.youtube.com/watch?v=l7YQ5_Nbifo

8
Felipe Sulser

問題の記述についての私の最初の理解は次のようでした。マップ上には事前定義されたターミナルの場所があります。ユーザーが地図上の場所を選択し、それらの場所の最も近い場所への最適/最短パスを見つける必要があります。

私の理解が正しければ、BFSアルゴリズムを1回適用するだけで、マップ上のすべての場所の最短経路を事前に計算できます。ノードごとにわずか2ビットを使用してその情報を効率的に保存できます(各ノードに関連付けられた値は、最短パスにとどまるためにそのノードから移動する必要がある方向を示します)。

ただし、 tobias_k がコメントしているように、問題の定義は異なる場合があります。プレーヤーはマップ上の任意の場所を選択し、現在の場所からその場所への最適なパスを見つける必要があります。前述のアプローチは、次の条件で再び利用できます。

  1. プレイヤーはマップ内をあまり速く移動せず、
  2. ある程度の不正確さは許容できます。

次に、すでに説明したアルゴリズムを実行して、マップ上の任意の場所から、プレーヤーの現在の場所を中心とする小さな円周までの最短経路を見つけます。次に、そのデータを短期間使用して、準最短経路を地図上の任意の場所にすばやくルーティングできます。プレイヤーが移動中にその円の境界に近づきすぎると、アルゴリズムはプレイヤーの新しい場所に対してプリエンプティブに実行されます。

このアプローチの欠点は、多くのCPUリソースを消費することです。利点はその単純さです。

0
Leon

これはコメントに収まるものより少し長くなるので、答えです。

設定には明確化が必要です。 10,000x10,000はすべて適切ですが、このステートメントは適切ではありません。

マップは10,000x 10,000であるため、1億のノードがあります

座標系の各単位ごとに1つのノードがあるのはなぜですか?これはノードパスファインディングが機能する方法ではありません。代わりに、ノードはよりスパースであると想定され、その存在によってパスに沿った個々の(スパース)ポイントを記述します。ノードポイント間で、オブジェクトは他の方法で移動を処理します。 gridパスファインディングシステムは、最悪の場合(障害物がまったくない場合)、100,000,000ポイントを持つ可能性がありますが、Qがnodesと述べているように、これはノードパスファインディングに関するものだと思います。

100,000,000ノード

100,000,000ノードは、int32の場合は381メガバイト、float64の場合は763mbのメモリです。さらに、ノード接続があります。あなたの場合、これらがどのように設定されるかはわかりませんが、各接続には2つの整数、たとえばそれぞれ2バイトが必要です。つまり。ノードと同じ数の接続がある場合は、さらに381MBが必要です。全体として、グラフデータは1テラバイトに近くなり、確かに何かがおかしいと私は主張します。

まだ巨大なノードグラフ/巨大な領域がある場合、問題を解決するにはどうすればよいですか? (あなたが言ったように)より大きな象限を作成することによって、私はおそらく単純化するでしょう。ただし、各象限はノードを保持します4つのエッジに沿ってのみ-象限内のすべてのノードは直線に置き換えられます。このようにして、各象限の入口/出口点を解決します。これは、大まかな計算のための別個のノードグラフになります。次に、象限内で、常に内部ノードグラフをロードしますその象限については時間のみ。多くの場合、何らかのエラーが発生する可能性がありますが、それは現実ですよね?これが人間の行動に関するものである場合、それは必ずしも完全に最適化されているわけではありません。

事前計算、キャッシュ、速度、小さなデータはゲームコーディングのキーワードです。

0
Stormwind

高レベルの概念は、開始点と終了点(たとえば、点(0,0)と点(10000、10000))を見つけて、最初から最後まで進むパスを予備的に推測することです(この場合は斜め上と右に向かって走ります)次に、そこにうまく到達できるかどうかを確認します(そのパスに障害物があるかどうか)。次に、プログラムで同様のパスを選択するか、パスが失敗する場所を見つけてそこから開始し、機能するまで反復しようとすると、100%最速ではない可能性がありますが、考えられるすべての方法を見つけるよりもはるかに優れた結果が得られます。次に、そこから最短経路を推測します。

実装

  • 最初の最短経路を見つける方法
  • 実行して、機能するかどうかを確認します
    • 失敗した場合は、同様のパスを試すか、失敗から始めます
0
trevren11
  1. すべてのグラフデータがメモリにあることを確認してください
  2. 双方向ダイクストラを使用する-マルチコアがあると仮定する
  3. 収縮階層の使用を検討してください。これにより、パフォーマンスが大幅に向上します。
  4. パスの重みなど、可能なすべてのものを事前に計算します。
0
Nick

マップの重みが均一である場合(もちろん障害物を除く)、次のいずれかを使用するとパフォーマンスが向上する可能性があります。

  1. グリッドを前処理してグラフにし、大きな空のスペースを1つのノードに折りたたむアルゴリズム。ナビゲーションメッシュは、トラバース可能な領域を凸多角形に分割し、各ポリゴンを1つのステップでトラバースできます。 L1 path Finder 障害物をグループ化し、可視グラフに縮小して、その上のパスを計算します。

  2. すべてのノードを拡張するわけではないアルゴリズム。 ジャンプポイント検索 異なるパス間の対称性を利用して、障害物に隣接するノードのみを拡張しますが、A *は最短パスに沿ってすべてのノードを拡張します。

0
c2huc2hu

したがって、n行n列の正方形のマップ上に_n^4_最短経路がある場合でも。すべてのパスを格納するために、必ずしもO(n^4)スペースは必要ありません。マップ上の2つの異なるターゲット位置とそれらの最短経路ツリーが与えられた場合、それらの2つのポイントがマップ上に近いほど、より一般的な要素がそれらの最短経路ツリーを持つという考え方です。これは、障害物のあるグリッドのような平面マップを使用する場合に特に当てはまります。

したがって、ターゲットロケーションの小さなセット(ターゲットロケーションが1つだけの場合もあります)に対して、完全な最短パスツリーのみを格納するという考え方です。残りのターゲットロケーションでは、最短パスツリーと以前に保存された最短パスツリーの1つとの差のみが保存されます。

次に、ある場所からターゲットまでの最短経路を見つけるアルゴリズムは、完全に保存された最短経路ツリーをロードし、それにいくつかの差分を適用して、ターゲット場所の最短経路ツリーを取得することです。次に、O(n^2)の複雑さである最短パスツリーで現在のプレーヤーの位置のみを見つける必要があります。

最短経路ツリーとその差分を格納するために必要なストレージスペースの量については、確かな事実はありませんが、これはO(n^2 log(n^2))の範囲である可能性があります。 1つをロードしてdiffを適用すると、時間計算量はO(n^2)だけになる可能性があります。

ターゲットロケーションの最短パスツリーは、マップ上のすべてのロケーションからターゲットロケーションまでのすべての最短パスを表します。

このソリューションでは、使用されている最短パスツリーをメモリに保持し、必要に応じて差分を適用して、使用する新しい最短パスツリーを取得することもできます。その場合、最短パスツリーを取得する複雑さは、マップのサイズではなく、適用される差分のサイズによって制限されます。このシナリオは、元のSacredやDiabloのようなゲームで実際にうまく機能する可能性があります。

0
SpaceTrucker