【更新】算法
稍微將A*算法進行修正,使用BFS(按F值對open表排序),另外,新增評估函數,用來測量當前點到終點的線段上的隨機某一點是不是牆或已訪問結點,是的話返回1,不然返回0。框架
function path_add_barrial_tracing(state, pt1, pt2) local xabs, yabs = math.abs(pt1.x - pt2.x), math.abs(pt1.y - pt2.y) if xabs == 0 or yabs == 0 then return 0 end local xr, yr = math.ceil(math.random(1,xabs)), math.ceil(math.random(1,yabs)) local v = path_get_point(state, {x= xr, y= yr}) if v ~= 1 then return 1 else return 0 end end
效果圖:dom
-----------------------------------------------------函數
看到過相似的將尋路算法可視化的文章。spa
尋思着將它們整合進遊戲框架,整體上說,整合難度比較低。.net
先前實現了TableLayout,設定長寬,能夠均勻排布容器內各元素。題圖中的方格也是這樣的實現思路。code
只實現了廣度遍歷BFS和深度遍歷DFS,二者是經典的遍歷算法。blog
書上通常採用open和closed兩個表的方式,這裏爲了圖簡單,就用一張表實現了。圖的結構二維矩陣表示,1表示未訪問過,三、4表示起點和終點,2表示牆,6及以上表示訪問過。那麼每次訪問只要將矩陣中的值標記下便可。排序
兩種算法只是對於表的添加方式不一樣,DFS是添加到頭部,BFS是添加到尾部。遊戲
這裏主要的難點在於,方塊的顏色是漸變的,離起點(紅色)近的呈黑色,遠的呈天藍色。計算方式是求任意點到起點的距離,而後根據HSL轉換到RGB,HSL的色相是固定的,而亮度是能夠調整的,從而實現漸變效果。
-------------------------------------------------
下面實現(僞)A*算法。
BFS和DFS方法都有缺點:BFS能找到全局最優,然而它須要將全部位置都訪問一遍,耗時間;DFS快,但只是局部最優,且DFS如何挑選需展開的結點也沒有明確規定。
A*對上述方式有了改進。A*給出了一個評估函數F。F=G+H。G是當前移動量,H是評估的待移動距離,二者總和是當前結節的評估值,固然,值越小,走這條路的可能性越大。
解決方法很簡單:令G=累積的移動距離;令H=當前位置離終點的哈密頓距離。在展開結點的時候,對待選結點按F值排序,使F值最小的最早展開,從而節省時間。
A*的實現通常用open和closed表,它將open表中的結點按F排序,選代價最小的展開。也就是說,A*算法每一次將open表中的結點進行排序,而A*的展開方式相似於BFS。爲何是基於BFS?由於BFS產生的open表結點是當前已遍歷結點的輪廓,這有點像最小生成樹算法,從當前輪廓中挑選代價最小的結點進行展開。惟一影響A*效率的就是F的計算方法。
PS:因爲偷懶,實現A*與上面的不一樣!上面是將open進行排序,而我只將當前結點的相鄰結點進行排序,因此算法效果確定沒A*好。再者,本系列的目標是作GUI,算法可視化只是一個demo。
A*算法的關鍵是設立一個評估函數,就如同阿法狗對局面的估計同樣。它採用的其實相似於最小生成樹的方式(把格子想成上下左右相連的圖),只是最小生成樹的挑選規則是肯定的(路徑長度肯定),A*的挑選規則是不肯定的(評估函數不精準)。這致使最小生成樹產生最優解,而A*不必定能獲得最優解。