World of Warcraft などの MMOARPG ゲームをプレイしたことがあるなら、キャラクターの歩行がとても面白いことに気づくでしょう。実際の歩行体験をシミュレートするために、キャラクターは目的地に到達するまでの最短ルートを選択し、山や湖を避け、箱や森を迂回して、選択した目的地に到達します。 この一見普通の経路探索は、プログラムに実装する際には特定の経路探索アルゴリズムで解決する必要があります。最短時間で最短ルートを見つける方法は、経路探索アルゴリズムが考慮しなければならない最初の問題です。 この記事では、パスファインディング アルゴリズムがどのように進化してきたかを段階的に説明します。アルゴリズムが遭遇する問題が単純なものから効率的なものまで、また改善のプロセスもわかります。質問を念頭に置いて読むと、より早く理解できます。 この記事には主に以下の内容が含まれています。
1. ゲーム内のキャラクターはどうやって道を見つけるのですか?人々が歩いている様子を見る方法: 開発者が実際にどう見ているか: あるいはこれ: マップの場合、開発者は特定のスキームを通じてマップをデータ オブジェクトに変換する必要があります。最も一般的なのは、前述のようにマップをグリッドに分割することです。もちろん、マップを必ずしもグリッドに分割する必要はありません。ポリゴンも使用できます。ゲームによって異なります。一般的に、同じエリアのマップでは使用する頂点の数が少なくなり、パス検索アルゴリズムが高速になります。パスファインディングでよく使われるデータ構造はグラフです。以下で見てみましょう。 2. 写真経路探索アルゴリズムについて説明する前に、まずデータ構造、つまりグラフについて理解しましょう。データ構造はアルゴリズム計算の基礎となります。優れたデータ構造はアルゴリズムを理解しやすくするだけでなく、アルゴリズムの効率も向上させます。ある意味では、グリッドもグラフの進化形ですが、グラフィックが変わったという点が異なります。グラフの概念を理解すると、経路探索アルゴリズムをより深く理解できるようになります。 グラフの基本的な定義:
3. 検索アルゴリズム
深さ優先探索深さ優先アルゴリズムは最小パスとはほとんど関係がないので、ここでは簡単に紹介するだけにします。
幅優先探索幅優先探索アルゴリズム (略して BFS) は、幅優先探索とも呼ばれ、最短経路の最初のモデルを探索するのに非常に適したグラフ探索アルゴリズムです。この考え方に沿って、引き続き説明していきます。 BFS は、グラフ内のすべてのノードを体系的に拡張してチェックし、結果を見つけることを目的としたブラインド検索方法です。つまり、結果の可能性のある場所を考慮するのではなく、結果が見つかるまでグラフ全体を徹底的に検索します。手順は次のとおりです。
グリッド: コード (js) を見てみましょう: var フロンティア = 新しい配列(); frontier.put(開始); var 訪問 = 新しい配列(); 訪問[開始] = true; フロンティアの長さが0を超える場合 現在の = frontier.get(); //周囲の頂点を見つける for(next in graph.neighbors(current)){ var notInVisited = visits.indexOf(next)==-1; // 訪問されていない if(notInVisited) { frontier.put(次へ); 訪問[次] = true; } } } 上記から、幅の検索は開始頂点から始まり、その子ノードを訪問し (グリッドでは周囲のノードを訪問します)、ターゲットが見つかるまでこのプロセスを継続的にループすることがわかります。このアルゴリズムは従来のロジックに沿っており、すべての頂点を列挙します。しかし、この方法には明らかな欠点もあります。 欠陥:
この問題を解決するにはどうすればいいでしょうか?ダイクストラのアルゴリズムを見てみましょう。 4. ダイクストラアルゴリズム幅優先探索アルゴリズムは、開始頂点から目標頂点までの経路計画問題を解決しますが、エッジに重み (距離など) がなく、経路を推定して最適なソリューションを比較できないため、最適かつ最も適切なアルゴリズムではありません。なぜ重みがそれほど重要なのでしょうか? 実際の環境では、2 つの頂点間のルートは必ずしも直線ではないからです。目的地に到達するには、森林、湖、山などの障害物を迂回する必要があり、これらはすべて直接通過するのではなく迂回する必要があります。 たとえば、幅優先アルゴリズムを使用すると、次の状況では障害物 (緑の部分) を直接通過しますが、これは明らかに望ましい結果ではありません。 問題点を解決する:
ダイクストラ アルゴリズムは、幅優先アルゴリズムに基づいた改良版です。最短パス ツリーに最短エッジを追加し、貪欲アルゴリズムを使用して計算を行い、最終的に最良の結果を生成します。具体的な手順は次のとおりです。
次の例を見てみましょう。 コード (js) を見てみましょう: var フロンティア = 新しい PriorityQueue(); frontier.put(開始); パス = 新しい配列(); //各頂点パスは cost_so_far = new Array() を消費します。 パス[開始] = 0; これまでのコスト[開始] = 0 フロンティアの長さが0を超える場合 現在の = frontier.get(); 現在の値 == 目標値の場合: 壊す //周囲のノードを検索 for(next in graph.neighbors(current)){ var notInVisited = visits.indexOf(next)==-1; var new_cost = cost_so_far[現在] + graph.cost(現在、次); //訪問されていないか、パスが近い if(notInVisited || new_cost < cost_so_far[next]) { これまでのコスト[次] = 新しいコスト; 優先度 = 新しいコスト; frontier.put(次、優先度); パス[次] = 現在のパス; } } } ダイクストラ アルゴリズムは幅優先探索よりも賢く、cost_so_far に基づいて長いルートやアクセスできないエリアを回避できますが、それでも盲目的に探索する傾向があることがわかります。マップでよくある状況は、ターゲットと開始点の間のパスを見つけることであり、これには一定の方向性があります。上の図からわかるように、ダイクストラ アルゴリズムは、開始点から子ノードまですべての方向に拡散します。 欠点:
盲目的に検索せずに検索の問題を解決するにはどうすればよいでしょうか?貪欲最良優先探索アルゴリズムを見てみましょう。 5. 貪欲な***最初の検索私はダイクストラのアルゴリズムの根本的な欠陥を発見しました。それは、検索が盲目であるということです。ここでは、この問題点にのみ焦点を当て、貪欲な優先探索を使用して解決します。どうすれば解決できるでしょうか?概念を少し変更する必要があります。ダイクストラ アルゴリズムでは、優先キューは開始頂点に対する各頂点の推定値を使用してソートします。貪欲な最初の検索では、 問題点を解決する:
どちらが速いですか?次の図を見てみましょう (左が幅優先、右が貪欲優先)。 上の図から、右側のアルゴリズム (貪欲な最優先検索) の方が左側よりも高速に検索していることがはっきりとわかります。そのパスは最適でも最短でもありませんが、障害物が最も少ない場合は十分に高速です。これは、完全な検索ではなく目標に基づいて検索する貪欲アルゴリズムの利点です。 アルゴリズムを見てみましょう (js): フロンティア = 新しい PriorityQueue(); フロンティア.put(開始, 0) came_from = 新しい配列(); came_from[開始] = 0; フロンティアの長さが0を超える場合 現在の = frontier.get() 現在の値 == 目標値の場合: 壊す for(graph.neighbors(current) の次の){ var notInVisited = visits.indexOf(next)==-1; // 訪問されていない if(notInVisited) { //ゴールまでの距離が近いほど、優先度が高くなります。priority = heuristic(goal, next); frontier.put(次、優先度); came_from[次] = 現在のもの; } } } 関数ヒューリスティック(a, b){ //ターゲットからの距離 return abs(ax - bx) + abs(ay - by) } 欠点:
最短経路を確保しながら、できるだけ少ない頂点を検索するにはどうすればよいでしょうか? A* アルゴリズムを見てみましょう。 6. A*アルゴリズム上記のアルゴリズムの進化により、最短経路と最小の検索頂点数を求める 2 つのソリューション、ダイクストラ アルゴリズムと貪欲な 1 次探索が徐々に見つかりました。では、両方のアルゴリズムの利点を活用して、経路探索アルゴリズムを高速かつ効率的にすることは可能でしょうか? 答えはイエスです。A* アルゴリズムはまさにそれを行います。ダイクストラ アルゴリズムの cost_so_far を利用し、各辺の長さに重みを設定し、各頂点から開始頂点までの距離を継続的に計算して最短経路を取得します。また、目標に向かって継続的に移動する貪欲な 1 次検索アルゴリズムの利点を活用し、各頂点からターゲット頂点までの距離を継続的に計算して、検索キューが目標に継続的に近づくように誘導します。これにより、検索する頂点の数が少なくなり、効率的な経路検索が維持されます。 問題点を解決する:
アルゴリズムを見てみましょう (js): var フロンティア = 新しい PriorityQueue(); frontier.put(開始); パス = 新しい配列(); cost_so_far = 新しい配列(); パス[開始] = 0; これまでのコスト[開始] = 0 フロンティアの長さが0を超える場合 現在の = frontier.get() 現在の値 == 目標値の場合: 壊す for(graph.neighbors(current) の次の){ var notInVisited = visits.indexOf(next)==-1; var new_cost = cost_so_far[現在] + graph.cost(現在、次); // 訪問されておらず、パスが近い if(notInVisited || new_cost < cost_so_far[next]) { これまでのコスト[次] = 新しいコスト //キューの優先度 = new_cost (頂点から開始頂点までの距離) + ヒューリスティック (頂点からターゲット頂点までの距離) 優先度 = 新しいコスト + ヒューリスティック(目標、次) frontier.put(次、優先度) パス[次] = 現在 } } } 関数ヒューリスティック(a, b){ //ターゲットからの距離 return abs(ax - bx) + abs(ay - by) } 以下は、ダイクストラ アルゴリズム、貪欲アルゴリズム、A* アルゴリズムの経路探索レーダー ダイアグラムです。番号の付いたグリッドが検索されています。3 つの効率を比較できます。 7. B*アルゴリズムB* アルゴリズムは A* アルゴリズムよりも効率的なアルゴリズムです。ゲーム内のモンスターの自動経路探索に適しています。その効率は A* アルゴリズムをはるかに上回ります。テストの結果、その効率は通常の A* アルゴリズムの数十倍から数百倍です。 B* アルゴリズムを紹介するつもりはありません。Google で検索してください。 上記のアルゴリズムの継続的な進化を通じて、各アルゴリズムの限界と、拡張された新しいアルゴリズムで出現する解決策がわかります。これにより、理解が促進されることを願っています。 |
<<: 見逃せない 7 つのディープ ニューラル ネットワーク可視化ツール
近年人気の技術である機械学習は、数多くの「人工知能」製品でよく知られているだけでなく、従来のインター...
[[411126]]この記事はWeChatの公開アカウント「Python Chinese Commu...
今週の金曜日、待望の NVIDIA 奨学金の受賞者リストが発表されました。 NVIDIA 大学院フェ...
[[187530]]人工知能 (AI) がどのように未来を予測し、職場を変え、さらには雇用を生み出...
[[248365]] 7月4日に開催された百度AI開発者会議で、ロビン・リー氏は「以前自慢していた...
この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...
IT Homeは10月12日、Microsoft Translatorが本日、12の新しい言語と方...
6月28日、Unityは開発者向けAIソフトウェアマーケット「AI Hub」を正式に立ち上げ、AIソ...
[[276827]]今日、インターネット サービスは根本的な変化を遂げており、徐々にインテリジェント...
[[423166]]対照学習(CV)比較学習は何をするのでしょうか?教師ありトレーニングの典型的な問...
[[255964]]人工知能(AI)の急速な進歩と発展により、その二重用途やセキュリティリスクについ...