A*演算法

A* 演算法是一種常見於路徑搜索的演算法。它可以在圖或網格中找到從起點到終點的最短路徑。相較於前一章的洪水演算法,A* 演算法更加高效。常見於2D網格遊戲的路徑運算中。

1. 準備好網格內容、牆和加入鄰居

image-20230518102159875

因為前一章已經做過一個差不多一模一樣的介面和程序,這裡就不一一講解了,有興趣或問題可以看上一章。

2. 準備好每個spot的cost和顯示介面

image-20230518103332453

A* 演算法,每個節點(或網格)的計分方法,都是由兩個cost去組成,gCost是指由目標(goal)到現在這一格的距離,而hCost是指由起始點到這一格共行了多少距離。最後這兩個cost相加就叫做fCost,這個cost就是我們想要的分數。

首先在Spot class,加入上文所說的cost。

 

接著在最上方加入openSet = []closeSet = []。A* 演算法會有一個叫openSet用來紀錄待計算的格,有點像上一章的等候列,另外經過計算的格會由openSet落入closeSet中不會再重覆計算。這部分下一節會詳談和實現。

 

接著在setup()的最後,開始演算法前第一步是將start1 放入openSet和計定startgCost02

 

最後返回Spotclass,將三個相關的cost都顯示出來。

 

3. 更新每一個格的cost

image-20230518111208045

 

A* 演算法會有一個openSetcloseSet,第一步是將起點加入到openSet,之後的每一步,

  1. 首先要找到全部openSet中,分數(fCost)最低的格,設定這一格做current

  2. 將這一格current移出openSet

  3. 將這一格current移入closeSet

  4. 找出這一格current的所有neighbors

    1. 計算基於current鄰居的gCost

    2. 如果鄰居本身就是openSet,就對比基於current鄰居計算的gCost是否少於它的gCost

    3. 如果是不在openSet的新一格,就更新它的gCost

    4. 計算每個鄰居的hCostfCost

    5. 更新這個鄰居是從哪裡來

 

之後就為openSetcloseSet加入不同的顏色方便觀察。

 

最後就是加入計算hCost的函數。gCost是一路走出累加了多少步,需要考慮中途遇到的障礙物,而 hCost是預估到終點還有多少步,這個預估是不需要理會障礙物的,就當是完全沒有障礙物,只計算步數。由於我們的計算是只有上、下、左和右,沒有打斜走的,所以由一格到另一格要走的最短路程,就是兩格的i的差和j的差之和。

4. 加入如果沒有答案或已找到路徑

image-20230518113239435

加入兩個考量,如果openSet是空的話,而又有未答案的話,即沒有答案。

 

如果找到end的話,即找到答案。如果目前所處的位置是終點,就找到了一條路徑。當找到路徑後,程式會列印出「找到路徑」的訊息,並建立一個包含當前位置的列表,接著使用一個暫存變數來追蹤前一個位置,並將前一個位置加入到路徑列表中。直到追蹤到起點,也就是前一個位置沒有「previous」屬性時,迴圈才會停止。最後,程式會列印出「已找到路徑!」的訊息,並退出所有迴圈。

考考你

AStar1

試著將程式美化到我這個效果,我是將所有closeSet的顏色,用map將其變成color(map(spots[i][j].gCost, 0, cols + rows, 0, 255),記得要在setup將顏色先設定成colorMode(HSB, 255)


1 一般路徑演算法都是剛好相反由終點找回起點的,會為方便解說和理解,我終一改為由起點找到終點
2 理論上是一併計算hCostfCost的,但不計算也不會對結果有影響