A *パスファインディングはどのように機能しますか?


67

A *経路探索の動作方法を基本的なレベルで理解したいと思います。すべてのコードまたは擬似コードの実装と視覚化が役立ちます。


ダイクストラのアルゴリズムが動いているアニメーションGIFを使用した小さな記事次に示します。
オラフルWaage

AmitのA *ページは、私にとって良い紹介でした。YouTube でAStar Algorithmを検索するための多くの優れた視覚化を見つけることができます。
jdeseno

私はこの偉大なチュートリアルを見つける前に、私は*の説明の数で混同されてきた:policyalmanac.org/games/aStarTutorial.htmは、私はActionScriptで*の実装を書いたとき、私はほとんどそれを参照:newarteest.com/flashを/astar.html
jhocking

4
-1 ウィキペディアには、説明、ソースコード、視覚化、および...を含むA *に関する記事があります。ここの回答の一部には、そのWikiページからの外部リンクがあります。
user712092

4
また、これはゲーム開発者にとって非常に興味深い非常に複雑なテーマなので、ここで情報が欲しいと思います。人々がプログラミングの質問をグーグルで検索するときにStackOverflowをトップヒットにしたいとジョエルが言ったことを思い出します。
-jhocking

回答:


63

免責事項

オンラインで見つかるA *のコード例と説明が山ほどあります。この質問には、多くの便利なリンクを含む多くの素晴らしい回答が寄せられています。私の答えでは、アルゴリズムの図解された例を提供しようとします。これは、コードや説明よりも理解しやすいかもしれません。


ダイクストラのアルゴリズム

A *を理解するために、まずダイクストラのアルゴリズムご覧になることをお勧めします。ダイクストラのアルゴリズムが検索のために実行する手順を説明します。

開始ノードはでAあり、への最短パスを検索する必要がありますF。グラフの各エッジには、それに関連する移動コストがあります(エッジの隣に黒い数字で示されます)。目標ノードに到達するまで、グラフの各頂点(またはノード)の最小移動コストを評価することが目標です。

ダイクストラのイラスト、パート1

これが私たちの出発点です。調べるリストノードがありますが、現在このリストは次のとおりです。

{ A(0) }

Aのコストがあり0、他のすべてのノードは無限に設定されます(典型的な実装では、これはint.MAX_VALUE似たようなものになります)。

ダイクストラのイラスト、パート2

ノードのリストから最もコストの低いノードを取得し(リストにはのみが含まれるためA、これが候補である)、そのすべての隣接ノードを訪問します。各ネイバーのコストを次のように設定します

Cost_of_Edge + Cost_of_previous_Node

前のノード(ノードの下に小さなピンク色の文字で表示)を追跡します。A解決済み(赤)としてマークすることができるため、再度アクセスすることはありません。候補者のリストは次のようになります。

{ B(2), D(3), C(4) }

ダイクストラのイラスト、パート3

繰り返しますが、リスト(B)から最低コストのノードを取得し、その近隣ノードを評価します。へのパスDはの現在のコストよりも高いDため、このパスは破棄できます。E候補のリストに追加され、次のようになります。

{ D(3), C(4), E(4) }

ダイクストラのイラスト、パート4

次に調べるノードはDです。Cパスは既存のコストより短くないため、への接続を破棄できます。Eしかし、より短いパスが見つかったため、コストEとその前のノードが更新されます。リストは次のようになります。

{ E(3), C(4) }

ダイクストラのイラスト、パート5

したがって、前に行ったように、リストから最もコストの低いノードを調べますEE未解決のネイバーは1つのみであり、これもターゲットノードです。ターゲットノードに到達するコストはに設定され10、その前のノードはに設定されますE。候補者のリストは次のようになります。

{ C(4), F(10) }

ダイクストラのイラスト、パート6

次にを調べCます。のコストと前のノードを更新できますF。リストには現在F、最低コストのノードが含まれているため、作業は完了です。パスは、以前の最短ノードをバックトラックすることで構築できます。


A *アルゴリズム

だから、A *アルゴリズムの代わりにダイクストラをあなたに説明したのはなぜだろうか?さて、唯一の違いは、候補者を計量(またはソート)する方法です。ダイクストラの場合:

Cost_of_Edge + Cost_of_previous_Node

A *の場合:

Cost_of_Edge + Cost_of_previous_Node + Estimated_Cost_to_reach_Target_from(Node)

どこEstimated_Cost_to_reach_Target_from一般的に呼ばれているヒューリスティック機能。これは、ターゲットノードに到達するためのコストを推定しようとする関数です。優れたヒューリスティック関数を使用すると、ターゲットを見つけるためにアクセスする必要があるノードが少なくなります。ダイクストラのアルゴリズムはすべての側面に拡張されますが、A *は(ヒューリスティックのおかげで)ターゲットの方向に検索します。

Amitのヒューリスティックに関するページには、一般的なヒューリスティックに関する概要があります。


2
ヒューリスティックが常に最適なルートを見つけるために検索をプッシュするわけではないことに注意してください。たとえば、ヒューリスティックがターゲットまでの距離であるが、実行可能なルートがマップの端の周りにある場合-この例では、検索は正しいルートを取得する前にマップ全体を検索します。確かに、あなたは考えているに違いありません、私が得ないものがありますか?これは機能しません!-理解すべきことは、ヒューリスティックの目的はほとんどの場合検索を削減することであり、あなたの仕事はあなたの特定のニーズのために利用可能なすべてのソリューションの中で「最良」であるものを見つけることです。
サーヤカロット

2
@AsherEinhorn Djikstraのような情報のない検索よりも優れています(最悪の場合は同等です)。
bummzack

はい、はい、あなたは絶対に正しいです。上記のコメントで説明したインスタンスは、A *の理論上の「最悪の場合」のシナリオであり、そのヒューリスティックですが、ダイクストラが毎回行うことは不明です。ほとんどの場合、A *は非常に単純なヒューリスティックを使用しても改善されます。私のポイントは、「ターゲットまでの距離」がすべてのシナリオで常に意味をなさないため、ヒューリスティックは最初は混乱する可能性があるということでした。
サーヤカロット

また、これを参照してください:qiao.github.io/PathFinding.js/visual
David Chouinard

この答えは、A *が最短経路を見つけることを保証するという意味で、ヒューリスティックを許容可能にするものについての言及を使用できます。(簡単に:ヒューリスティックは許容できるように、ターゲットまでの実際の距離を過大評価してはなりません。許容できないヒューリスティックは役に立つ場合がありますが、A *が次善のパスを返すことがあります。)
Ilmari Karonen 14年

26

A *パス検出は、追加のヒューリスティックを使用するベストファーストタイプの検索です。

最初に行う必要があるのは、検索エリアを分割することです。この説明では、マップはタイルの正方形グリッドです。これは、ほとんどの2Dゲームがタイルのグリッドを使用するためであり、視覚化が簡単だからです。ただし、検索領域は任意の方法で分割できることに注意してください:おそらく16進グリッド、またはリスクのような任意の形状です。さまざまなマップ位置は「ノード」と呼ばれ、このアルゴリズムは、通過する多数のノードがあり、ノード間の接続を定義している場合はいつでも機能します。

とにかく、与えられた開始タイルから開始:

  • 開始タイルの周囲の8つのタイルは、a)現在のタイルから次のタイルに移動するコストに基づいて「スコアリング」されます(通常、水平または垂直の動きの場合は1、斜めの動きの場合はsqrt(2))。

  • 各タイルには、追加の「ヒューリスティック」スコアが割り当てられます。これは、各タイルに移動する相対的な価値の近似値です。さまざまなヒューリスティックが使用されます。最も単純なのは、指定されたタイルと終了タイルの中心間の直線距離です。

  • 次に、現在のタイルは「クローズ」され、エージェントは、開いている、移動スコアが最も低く、ヒューリスティックスコアが最も低い隣接タイルに移動します。

  • このプロセスは、目標ノードに到達するか、オープンノードがなくなるまで繰り返されます(エージェントがブロックされることを意味します)。

これらの手順を示す図については、この初心者向けチュートリアルを参照してください

主にヒューリスティックの改善において、いくつかの改善が可能です。

  • 地形の違い、粗さ、急勾配などを考慮に入れる

  • また、グリッドを「スイープ」して、効率的なパスではないマップの領域をブロックすることも役立つ場合があります。たとえば、エージェントに面したUシェイプです。掃引テストを行わない場合、エージェントは最初にUに入り、向きを変え、次にUの端を出て行きます。「本物の」インテリジェントエージェントはU字型トラップに気付き、それを単に回避します。スイープはこれをシミュレートするのに役立ちます。


1
グラフ、ノード、エッジを使用した説明は、単なるタイルよりも明確です。ゲームの空間構造がどのようなものであっても、この空間に位置情報をリンクしている限り、同じアルゴリズムを適用できることを理解するのに役立ちません。
クライム

視覚化するのが難しいので、実際にはそれほど明確ではないと主張します。しかし、この説明では、タイルグリッドは不要であることに言及する必要があります。実際に、私は中にそのポイントを編集します。
jhocking

14

最高とはほど遠いですが、これは数年前にC ++A *を実装したものです。

おそらく、アルゴリズム全体を説明しようとするよりも、リソースを指す方が良いでしょう。また、Wikiの記事を読みながら、デモを試して、どのように機能するかを視覚化できるかどうかを確認してください。特定の質問がある場合は、コメントを残してください。

  1. ウィキペディアのA *
  2. A * Javaデモ

4
Pythonの例はC ++です。
アルミニウムのパン

@finish-誰かがそれをキャッチするのを見るのは良いことです!最近の日々の活動は、Pythonを中心に展開しています。ありがとう!
デビッドマグロウ

3
C ++の例もCかもしれません
減速

4
この例は、それが持つすべての構造のアセンブラーにもある可能性があります。それはA *でさえありません、これはどのように受け入れられた答えですか?

4
申し訳ありませんが、これは標準的なものではありません。それは、私が始めたときの最初のコーディングの試みの1つでした。コメントに投稿したり、投稿を編集して独自のソリューションを共有してください。
デビッドマグロウ

6

ActiveTutのパス検索に関する記事が役立つかもしれません。A *とダイクストラのアルゴリズムの両方と、それらの違いについて説明します。Flash開発者向けですが、Flashを使用していなくても、理論に関する優れた洞察が得られるはずです。


4

A *とダイクストラのアルゴリズムを扱う際に視覚化することが重要なことの1つは、A *が向けられていることです。どの方向を見るかを「推測」することにより、特定のポイントへの最短経路を見つけようとします。ダイクストラのアルゴリズムは、/ every /ポイントへの最短経路を見つけます。


1
これは、実際にはA *とダイクストラの違いを正確に記述したものではありません。ダイクストラがすべてのポイントの単一ソースを解決するのは事実ですが、ゲームで使用する場合、通常、ゴールへのパスが見つかるとすぐに切断されます。2つの実際の違いは、A *がヒューリスティックによって通知され、より少ないブランチでその目標を見つけることができることです。

ジョーの説明に追加するには:A *はすべてのポイントへのパスも見つけます(許可した場合)が、ゲームでは通常早く停止する必要があります。A *はDijsktraのアルゴリズムと同様に機能しますが、ヒューリスティックはノードを並べ替えて最も有望なパスを最初に探索するのに役立ちます。そうすれば、通常、ダイクストラのアルゴリズムよりも早く停止できます。たとえば、マップの中心から東側へのパスを検索する場合、ダイクストラのアルゴリズムはすべての方向に等しく探索し、東側が見つかったら停止します。A *は西よりも東に行く時間が多く、早く到着します。
amitp

3

したがって、最初のステートメントのように、A *は本質的にグラフ探索アルゴリズムです。通常、ゲームでは、グラフとしてタイルまたは他のワールドジオメトリのいずれかを使用しますが、他のものにはA *を使用できます。グラフトラバーサルの2つのurアルゴリズムは、深さ優先探索と幅優先探索です。DFSでは、常に現在のノードの兄弟を見る前に現在のブランチを完全に探索し、BFSでは常に最初に兄弟を見て、次に子を調べます。A *は、目的の目標に近づいているときにブランチを探索する(DFSに似ている)これらの中間点を見つけようとしますが、ブランチでより良い結果が得られる場合は、一時停止して兄弟を試します。実際の数学は、可能なノードのリストを保持して、次にそれぞれが「良さ」を持つ場所を探索することです 目標にどれだけ近いか(ある種の抽象的な意味で)を示すスコア。スコアが低いほど良い(0は目標を見つけたことを意味します)。次に使用するものを選択するには、スコアの最小値とルートから離れたノードの数(通常、現在の構成、またはパスファインディングの現在の位置)を見つけます。ノードを探索するたびに、すべての子をこのリストに追加してから、新しい最適なものを選択します。


3

抽象レベルでは、A *は次のように機能します。

  • あなたは世界を離散的な数の接続されたノードとして扱います。グリッド、またはグラフ。
  • その世界を横断するパスを見つけるには、その空間内で隣接する「ノード」のリストを見つけて、開始からゴールまで導く必要があります。
  • 単純なアプローチは次のようになります。開始ノードで始まり、終了ノードで終わるノードの可能なすべての順列を計算し、最も安いものを選択します。これは、最も小さなスペースを除いて、明らかに永遠にかかります。
  • したがって、別のアプローチでは、世界についての知識を使用して、どの順列を最初に検討する価値があるかを推測し、特定の解決策に勝てるかどうかを判断しようとします。この推定は、ヒューリスティックと呼ばれます。
  • A *には、許容可能なヒューリスティックが必要です。これは、過大評価されないことを意味します。
    • 2点間の最短ルートは直線であることがわかっているため、パス検索の問題の優れたヒューリスティックはユークリッド距離です。これは、実際のシミュレーションで距離を過大評価することはありません。
  • A *は開始ノードから始まり、そのノードと各隣人、および隣人の隣人などの連続した順列を試行し、ヒューリスティックを使用して次に試す順列を決定します。
  • 各ステップで、A *はこれまでで最も有望なパスを調べ、これまでに移動した距離と、そこからどれだけ離れるかのヒューリスティックの推定値に基づいて、「最良」と思われる次の隣接ノードを選択します。ノード。
  • ヒューリスティックは過大評価することはなく、これまでに移動した距離は正確であることがわかっているため、常に最も楽観的な次のステップを選択します。
    • 次のステップが目標に到達した場合、最後の位置から最短ルートが見つかったことがわかります。これは、有効なルートの最も楽観的な推測だからです。
    • 目標に到達しなかった場合、後で探索するための可能なポイントとして残されます。アルゴリズムは次に最も有望な可能性を選択するため、上記のロジックが引き続き適用されます。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.