A *経路探索の動作方法を基本的なレベルで理解したいと思います。すべてのコードまたは擬似コードの実装と視覚化が役立ちます。
A *経路探索の動作方法を基本的なレベルで理解したいと思います。すべてのコードまたは擬似コードの実装と視覚化が役立ちます。
回答:
オンラインで見つかるA *のコード例と説明が山ほどあります。この質問には、多くの便利なリンクを含む多くの素晴らしい回答が寄せられています。私の答えでは、アルゴリズムの図解された例を提供しようとします。これは、コードや説明よりも理解しやすいかもしれません。
A *を理解するために、まずダイクストラのアルゴリズムをご覧になることをお勧めします。ダイクストラのアルゴリズムが検索のために実行する手順を説明します。
開始ノードはでA
あり、への最短パスを検索する必要がありますF
。グラフの各エッジには、それに関連する移動コストがあります(エッジの隣に黒い数字で示されます)。目標ノードに到達するまで、グラフの各頂点(またはノード)の最小移動コストを評価することが目標です。
これが私たちの出発点です。調べるリストノードがありますが、現在このリストは次のとおりです。
{ A(0) }
A
のコストがあり0
、他のすべてのノードは無限に設定されます(典型的な実装では、これはint.MAX_VALUE
似たようなものになります)。
ノードのリストから最もコストの低いノードを取得し(リストにはのみが含まれるためA
、これが候補である)、そのすべての隣接ノードを訪問します。各ネイバーのコストを次のように設定します。
Cost_of_Edge + Cost_of_previous_Node
前のノード(ノードの下に小さなピンク色の文字で表示)を追跡します。A
解決済み(赤)としてマークすることができるため、再度アクセスすることはありません。候補者のリストは次のようになります。
{ B(2), D(3), C(4) }
繰り返しますが、リスト(B
)から最低コストのノードを取得し、その近隣ノードを評価します。へのパスD
はの現在のコストよりも高いD
ため、このパスは破棄できます。E
候補のリストに追加され、次のようになります。
{ D(3), C(4), E(4) }
次に調べるノードはD
です。C
パスは既存のコストよりも短くないため、への接続を破棄できます。E
しかし、より短いパスが見つかったため、コストE
とその前のノードが更新されます。リストは次のようになります。
{ E(3), C(4) }
したがって、前に行ったように、リストから最もコストの低いノードを調べますE
。E
未解決のネイバーは1つのみであり、これもターゲットノードです。ターゲットノードに到達するコストはに設定され10
、その前のノードはに設定されますE
。候補者のリストは次のようになります。
{ C(4), F(10) }
次にを調べC
ます。のコストと前のノードを更新できますF
。リストには現在F
、最低コストのノードが含まれているため、作業は完了です。パスは、以前の最短ノードをバックトラックすることで構築できます。
だから、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のヒューリスティックに関するページには、一般的なヒューリスティックに関する概要があります。
A *パス検出は、追加のヒューリスティックを使用するベストファーストタイプの検索です。
最初に行う必要があるのは、検索エリアを分割することです。この説明では、マップはタイルの正方形グリッドです。これは、ほとんどの2Dゲームがタイルのグリッドを使用するためであり、視覚化が簡単だからです。ただし、検索領域は任意の方法で分割できることに注意してください:おそらく16進グリッド、またはリスクのような任意の形状です。さまざまなマップ位置は「ノード」と呼ばれ、このアルゴリズムは、通過する多数のノードがあり、ノード間の接続を定義している場合はいつでも機能します。
とにかく、与えられた開始タイルから開始:
開始タイルの周囲の8つのタイルは、a)現在のタイルから次のタイルに移動するコストに基づいて「スコアリング」されます(通常、水平または垂直の動きの場合は1、斜めの動きの場合はsqrt(2))。
各タイルには、追加の「ヒューリスティック」スコアが割り当てられます。これは、各タイルに移動する相対的な価値の近似値です。さまざまなヒューリスティックが使用されます。最も単純なのは、指定されたタイルと終了タイルの中心間の直線距離です。
次に、現在のタイルは「クローズ」され、エージェントは、開いている、移動スコアが最も低く、ヒューリスティックスコアが最も低い隣接タイルに移動します。
このプロセスは、目標ノードに到達するか、オープンノードがなくなるまで繰り返されます(エージェントがブロックされることを意味します)。
これらの手順を示す図については、この初心者向けチュートリアルを参照してください。
主にヒューリスティックの改善において、いくつかの改善が可能です。
地形の違い、粗さ、急勾配などを考慮に入れる
また、グリッドを「スイープ」して、効率的なパスではないマップの領域をブロックすることも役立つ場合があります。たとえば、エージェントに面したUシェイプです。掃引テストを行わない場合、エージェントは最初にUに入り、向きを変え、次にUの端を出て行きます。「本物の」インテリジェントエージェントはU字型トラップに気付き、それを単に回避します。スイープはこれをシミュレートするのに役立ちます。
最高とはほど遠いですが、これは数年前にC ++でA *を実装したものです。
おそらく、アルゴリズム全体を説明しようとするよりも、リソースを指す方が良いでしょう。また、Wikiの記事を読みながら、デモを試して、どのように機能するかを視覚化できるかどうかを確認してください。特定の質問がある場合は、コメントを残してください。
ActiveTutのパス検索に関する記事が役立つかもしれません。A *とダイクストラのアルゴリズムの両方と、それらの違いについて説明します。Flash開発者向けですが、Flashを使用していなくても、理論に関する優れた洞察が得られるはずです。
A *とダイクストラのアルゴリズムを扱う際に視覚化することが重要なことの1つは、A *が向けられていることです。どの方向を見るかを「推測」することにより、特定のポイントへの最短経路を見つけようとします。ダイクストラのアルゴリズムは、/ every /ポイントへの最短経路を見つけます。
したがって、最初のステートメントのように、A *は本質的にグラフ探索アルゴリズムです。通常、ゲームでは、グラフとしてタイルまたは他のワールドジオメトリのいずれかを使用しますが、他のものにはA *を使用できます。グラフトラバーサルの2つのurアルゴリズムは、深さ優先探索と幅優先探索です。DFSでは、常に現在のノードの兄弟を見る前に現在のブランチを完全に探索し、BFSでは常に最初に兄弟を見て、次に子を調べます。A *は、目的の目標に近づいているときにブランチを探索する(DFSに似ている)これらの中間点を見つけようとしますが、ブランチでより良い結果が得られる場合は、一時停止して兄弟を試します。実際の数学は、可能なノードのリストを保持して、次にそれぞれが「良さ」を持つ場所を探索することです 目標にどれだけ近いか(ある種の抽象的な意味で)を示すスコア。スコアが低いほど良い(0は目標を見つけたことを意味します)。次に使用するものを選択するには、スコアの最小値とルートから離れたノードの数(通常、現在の構成、またはパスファインディングの現在の位置)を見つけます。ノードを探索するたびに、すべての子をこのリストに追加してから、新しい最適なものを選択します。
抽象レベルでは、A *は次のように機能します。