最近看了一些和圖形、算法可視化相關的文章和代碼,挺有意思,因而本身也學着作了些東西。html
迷宮小時候玩過,但歷來沒琢磨過迷宮是怎麼設計的,覺得就是有人慢慢畫出來的。看過網上這篇文章後,才知道,原來還能夠隨機生成:git
Maze Generation - Visualizing Algorithmsgithub
本身找了些資料參考,試着實現了幾種以後,才慢慢領會到其中的一些原理。算法
算法中討論的迷宮知足一個條件:迷宮中任意兩點間有且只有一條路徑。數組
要隨機生成知足這樣條件的迷宮,看起來很複雜啊。可是換個思路以後,就發現問題沒那麼複雜了。app
「樹」其實就知足這個條件:佈局
因此,生成隨機的迷宮的問題,就轉化爲生成隨機的樹的過程。進一步,能夠拆分爲如下過程:動畫
迷宮生成的不一樣算法,區別主要在兩點:spa
深度優先算法,也叫遞歸回溯算法。它會一直向隨機方向生長,直到沒法生成的位置,向後回退一格,繼續生長,直到全部網格被填充。設計
深度優先算法生成的迷宮,會有比較明顯的長路徑,這是由於樹在一開始生成的時候,空間比較充裕,會有一些長的枝條產生。
Prim 算法不會一直沿着一條路徑進行探索,而是不斷嘗試隨機的生長點。因此 Prim 算法生成的迷宮,分叉會比較多:
綜合以上兩種算法,我既不但願有過長的路徑,也不但願有太多的分叉,因此我採用的思路的嘗試沿着一條路徑延伸最多必定的長度,而後再隨機選擇生長點執行相同的過程。
下圖是在 40*40 的迷宮網格,每條枝幹最多生長15個網格的效果:
這是執行了一段時間以後,迷宮大部分區域已經走過:
這是最後的效果:
項目地址:luobotang/maze
在線DEMO:迷宮生成算法 - luobotang
上面例子中的迷宮生成算法過程,迷宮網格是經過 HTML 的 <table> 實現,相鄰網格的連通效果,則是藉助 CSS 的邊框樣式。
整個迷宮的全部網格由二維數組表示,每一個網格的狀態包含是否被訪問、與相鄰網格的連通狀況等。
算法的執行過程由定時器驅動,每次執行一步,從而有動畫的效果。
與圖相關的最短路徑算法,在生活中應該是有着普遍的應用了吧,從一個位置到另外一個位置,藉助已有的路網,計算最短的路徑。固然,還會由於路況、臨時障礙,以及用戶的我的偏好而產生不一樣結果。
對於「圖」上,基本要素就是:
Dijkstra 算法是用於計算最短路徑的比較著名的一種算法,早在1956年就發表了。
Dijkstra 算法若是看算法的詳細執行過程,有點複雜,可是其基本思路在作過以後會發現,貌似很簡單。
已肯定 A 到 B 的最短路徑,B 與 C 相連,且 A 到 B 的距離加上 B 到 C 的距離,小於當前 A 到 C 的距離,那麼 A 到 B 再到 C 就是 A 到 C 的最短路徑。
如上圖所示,最初從 A 來看,到 C 的最短路徑是 A -> C,距離是 4。但繼續探索到 B 後,發現 A -> B 加上 B -> C 距離只有 3,比 A -> C 的距離要小,因此 A 到 C 的最短路徑更新爲:A -> B -> C。
基本思路上面都介紹了,細節就是每次探索節點時,都選擇當前未探索過的到源點距離最短的節點,這樣能夠源點到當前點的路徑已是最短路徑。
圖的可視化比較複雜了,只是繪製出來其實不難,但要將節點、邊進行合理佈局就比較麻煩,是另外一個話題了。
我選擇用 vis.js 提供的 Network 來繪製圖形,而後經過逐步執行算法來更新圖形。
這是初始狀態:
執行過程當中,會記錄節點是否被訪問,以及當前的最短路徑和對應的距離:
所有執行完成後,就獲得了源點開始到圖中全部節點的最短路徑:
項目地址:luobotang/graph
DEMO:Dijkstra 算法 - luobotang
項目的 Github Pages 配置有點問題,只能下載到本地以後再打開頁面了。
其實上面這些實現起來並無特別困難,有不少現成的資料和代碼能夠利用。可是無論什麼飯,都得本身吃過、消化過纔是本身的。因此,我把本身吸取的「養分」記錄下來,若是你也有興趣,不妨本身上手一試。
最後,感謝閱讀!