最近作到一道題,題目以下:php
有 A、B 兩點,中間有一堆障礙物,求出A點到B的可行的路徑,寫出一個 DEMO 並可用任何語言實現(要求能夠任意設置 A、B 點和障礙物的位置,須要作UI)。html
首先,理解一下題意,須要求出 A、B 兩點的可行路線,要注意的是能夠任意設置 A、B 兩點位置以及障礙物的位置且須要作 UI。題目需一句話帶過,但須要作很多的工做。嗯,很明顯,這是一道考算法邏輯還有 UI 的題目。git
如今咱們將主要工做放在如何去求出 A、B 兩點的可行的路徑呢?github
估計看到題目,不少人都會無從下手。但再認真想一想,其實這道題目就相似咱們平常用的導航,尋找起點和終點可行的最短路線。那麼,咱們可使用搜尋算法解決這一道題目。搜尋算法有不少種,如:最佳優先搜索算法 (Best-First Search)、戴克斯特拉算法(Dijkstra)、A 搜尋算法和迭代加深 A 算法(IDA* )等等。web
先來了解一下 A* 搜尋算法:算法
A* 算法綜合了 最佳優先搜索算法 (Best-First Search) 和 戴克斯特拉算法(Dijkstra)的優勢:在進行啓發式搜索提升算法效率的同時,能夠保證找到一條最優路徑(基於評估函數) 維基百科數組
A* 搜尋算法的估算函數:函數
f(n) = g(n) + h(n)
g(n) 表示起點到任意點 n 的距離,h(n) 表示任意點 n 到目標點的距離,f(n) 則表示任意點 n 到起點以及目標點的和。f(n) 越小時,那麼起點到目標點的可行路徑越小。post
接下來咱們使用圖文來講明一下咱們該如何計算:優化
咱們能夠將全部格子看做一個二維數組,裏面分爲可行以及不可行(即障礙物)。咱們將起始點標記爲 A 以及目標點(終點)標記爲 B,此處咱們忽略可斜走的狀況(由於須要作各類限制,略麻煩),本文 Open List
存放全部 A 附近可行的方格,Close List
存放已行的不須要再關注的方格。
(圖一)
可見圖一,起點 A 上下左右有四個方格,右邊格子爲障礙物,再次咱們則忽略它,那麼起點 A 相鄰可行的格子有上左下這三個。咱們設置一個 Open List
用於存放可行的方格,以及一個 Close List
用於記錄已行方格。首先將起點 A 放進 Open List
中,而後搜尋起點 A 附近可行方格放到 Open List
中做記錄。
從上面 A 搜尋算法的簡單瞭解,咱們可知 A 搜尋算法的估算函數是:f(n) = g(n) + h(n)
。
A 相鄰的長方形 f(n) 越小,則 A 到達 B 的可行路徑最短,所以咱們須要選擇最小 f(n) 的長方形行走。接下來看看咱們如何去計算 f(n) 的值。
爲了方便計算,咱們將方格的長寬設置爲 1 ,若是可斜走那麼每個的斜線爲 。固然爲了方便計算可以使用長寬爲 10,斜線爲 14 的比例來計算。
(圖二)
如圖二,起點 A 有三塊可行的方格,咱們標記爲粉紅色,那麼首先咱們計算這三個方格的 g 值。起點 A 的上左下的方格分別離 A 點距離 g(n) 爲 1 ,因此標記粉紅色的上左下的方格 g(n) 值爲 1。
那麼接下來計算 h(n) 值,計算 h(n) 值時忽略障礙物,即全部方格可行的狀況下計算(若是可行斜線狀況下,那麼在計算 h(n) 值的時候不計算斜走的狀況,只計算任意點直行到終點距離)。那麼可計算出起點 A 下方的方格 h(n) 等於 7,左方 h(n) 等於 9,上方 h(n) 等於 9。那麼得出上左下三個方格的 f(n) 值:
起點 A 上方:f(n) = g(n) + h(n) = 1 + 9 = 10
起點 A 左方:f(n) = g(n) + h(n) = 1 + 9 = 10
起點 A 下方:f(n) = g(n) + h(n) = 1 + 7 = 8
由上面的計算可得出起點 A 下方的 f(n) 值爲最小,那麼咱們第一步走到起點 A 下方的方格。那麼將起點 A 下方的方格存到 Close List
,且同時從 Open List
中移除。
(圖三)
如圖三,咱們走了第一步後 A 點去到了起點的下方一個,那個繼續去計算,因爲上面起點已經存在於 Close List
以及已存在於 Open List
的格子咱們不須要再關注,那麼圖上可看到 A 點接着可行點只有左右兩點,那麼計算 A 點到左邊格子 g(n) 爲 2,h(n) 爲 8,右邊格子 g(n) 爲 2,h(n) 爲 6。那麼 A 點左邊格子 f(n) 等於 10,右邊格子 f(n) 等於 8,所以咱們第二步走 A 點右邊格子,將格子從 Open List
移除,存進 Close List
(如圖四)。
(圖四)
以此類推,咱們最終可得出的路徑(如圖五)。
(圖五)
如圖五,綠色路徑爲可行的最短路徑,紅色標誌的則是已存在於 Open List
的方格。
基本原理就是如此,代碼我就不一一列出來,我會放到 Github 或者看看 Jsfiddle 上面,有興趣的能夠看一下,對應方法也有對應的註釋。能夠看一下最終實現的 效果
動畫演示各類算法地址:http://www.webhek.com/post/pathfinding.html
新手一枚,若是有什麼寫錯的或者很差的地方,請各位大大指點探討一下,我會不斷優化提高。
哦,最近本人在找工做,期待工做地區廣州、深圳、佛山,若有好工做或者內推等能夠私聊一下我。