[Unity] 経路探索アルゴリズム: 幅優先、ダイクストラ、ヒューリスティック、A スター

以下は、このリンクを読んで私が得た簡単な理解と要約です (文章は非常に優れており、著者はさまざまなアルゴリズムの類似点と相違点を理解しやすくするためにいくつかの視覚的な操作も提供しています。これは強くお勧めします)。逸脱や間違いがある場合は、コメント欄で修正してください。


 

1.幅優先探索(幅優先アルゴリズム)

a. 制約なしで外側に拡張し、すべてのノードのソース ノードをトラバースして保存し、それらを Came_from ディクショナリに保存します。

frontier = Queue()
frontier.put(start )
came_from = dict() # path A->B is stored as came_from[B] == A
came_from[start] = None

while not frontier.empty():
   current = frontier.get()
   for next in graph.neighbors(current):
      if next not in came_from:
         frontier.put(next)
         came_from[next] = current

b. ゴール点ゴールから開始して、come_from で逆方向にスタート点を検索し、スタート点が見つからない場合は、スタート点が見つかるまでループを繰り返し、ゴール点を経路探索パスに追加しますそしてパスは逆になります:

current = goal
path = []

while current != start:
   path.append(current)
   current = came_from[current]

path.append(start) # optional
path.reverse() # optional

最適化. 上記 a. で、come_from を検索する際の判定条件を追加します。 目的のノードが見つかったら、ループから抜けます。

frontier = Queue()
frontier.put(start )
came_from = dict()
came_from[start] = None

while not frontier.empty():
   current = frontier.get()
   if current == goal:
      break           
   for next in graph.neighbors(current):
      if next not in came_from:
         frontier.put(next)
         came_from[next] = current

2.ダイクストラのアルゴリズム (ダイクストラのアルゴリズム)

場合によっては、各ステップの消費量 (時間、物理量など) が異なるため、開始位置から現在位置までに消費された合計コストを記録するために、新しいパラメーターcost_so_far を追加する必要があります。したがって、come_from ノードを追加する場合は、まずコストを比較し、最も消費量が少ないノードを見つけて、come_from に追加します。

frontier = PriorityQueue() #Queue(队列)->PriorityQueue(优先队列)
frontier.put(start, 0)
came_from = dict()
cost_so_far = dict()
came_from[start] = None
cost_so_far[start] = 0

while not frontier.empty():
   current = frontier.get()

   if current == goal:
      break
   
   for next in graph.neighbors(current):
      new_cost = cost_so_far[current] + graph.cost(current, next)
      if next not in cost_so_far or new_cost < cost_so_far[next]:
         cost_so_far[next] = new_cost
         priority = new_cost
         frontier.put(next, priority)
         came_from[next] = current

注: PriorityQueue はキュー内の最小値を最初に返す必要があります (Python の数値の場合、デフォルトで大きい値から小さい値の順に配置され、他の型はカスタマイズする必要があります)。

最小コストが必ずしも最短経路であるとは限らないため、次のヒューリスティック検索が使用されます。

3.ヒューリスティック検索(ヒューリスティック検索)

ほとんどの場合、どの方向にもパスを検索する必要はなく、ターゲット ポイントの方向にパスを検索するだけで済みます。したがって、Greedy Best First Searchでは優先キューとしてコストを考慮せず、常に次のノードと終点間の距離をキューに追加し、最短距離を見つけてこのノードを取り出し、そこから開始します。このノードを使用して次の A ノードを検索し、最後が見つかるまでループします。

frontier = PriorityQueue()
frontier.put(start, 0)
came_from = dict()
came_from[start] = None

while not frontier.empty():
   current = frontier.get()

   if current == goal:
      break
   
   for next in graph.neighbors(current):
      if next not in came_from:
         priority = heuristic(goal, next)
         frontier.put(next, priority)
         came_from[next] = current

利点: 地形が単純な場合、パスの検索が高速になります。 

短所: 図のように地形が複雑な場合...

アルゴリズムは目標点まで直進しましたが、経路が遮られていることがわかり、後戻りして大きく方向転換したため、見つかった経路は最短経路ではありませんでした。 

解決策: A スター アルゴリズム。

4.A*アルゴリズム(Aスターアルゴリズム)

ダイクストラのアルゴリズムは最短経路を見つけることができますが、時間の無駄です。Greedy Best First Search は比較的高速ですが、最短経路を見つけることができません。

A-starアルゴリズムは、ダイクストラ法を用いて始点から現在位置までの実際の消費距離を求めるだけでなく、現在距離から終点までの推定距離を判定値として使用し、加算した値を加算します。 2つの結果をプライオリティキューに入れ、最小値を次の移動目標点とする。

frontier = PriorityQueue()
frontier.put(start, 0)
came_from = dict()
cost_so_far = dict()
came_from[start] = None
cost_so_far[start] = 0

while not frontier.empty():
   current = frontier.get()

   if current == goal:
      break
   
   for next in graph.neighbors(current):
      new_cost = cost_so_far[current] + graph.cost(current, next)
      if next not in cost_so_far or new_cost < cost_so_far[next]:
         cost_so_far[next] = new_cost
         priority = new_cost + heuristic(goal, next)
         frontier.put(next, priority)
         came_from[next] = current

選び方

1. ゲームで包括的なパス検索が必要な場合は、幅優先検索またはダイクストラのアルゴリズムの使用を優先してください。各ステップのコストが同じ場合は幅優先探索を使用し、それ以外の場合はダイクストラのアルゴリズムを選択します。

2. 開始点から目標点までのパスを見つけるだけの場合は、最初に A-star アルゴリズムを使用します。

Python、C++、および C# での上記のアルゴリズムの実装例


これは Unity+C# を使用して私が実装したデモです。効果は次のとおりです。

リソースリンク

おすすめ

転載: blog.csdn.net/qq302756113/article/details/124858376