1. 程式人生 > 其它 >Prime演算法生成迷宮

Prime演算法生成迷宮

技術標籤:寫著玩(前端)js演算法

prime迷宮生成

結果展示

在這裡插入圖片描述

演算法解析

參考連結

Prime迷宮生成演算法的原理:
(1)初始地圖所有位置均設為牆
(2)任意插入一個牆體進牆佇列
(3)判斷此時牆體是否可以設定為路(判斷依據在於上下左右四個位置是否只有一個位置是路)
(4)若設定為路,則將該位置周圍(上下左右)的所有牆插入佇列,接著執行(5);若無法設定為路,直接執行(5)
(5)從牆佇列中刪去當前位置所在節點
(6)若牆佇列不為空,則從佇列中隨機選取一面牆重新執行(3),直到牆佇列為空

實現程式碼

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>迷宮</title> <style> table { margin: 0 auto; border-collapse: collapse; border: 1px solid #ddd; } td { width
: 18px; height: 18px; box-sizing: border-box; border:1px solid #eee } td.wall { background: #eee; border: 1px solid #eee; } .now { background: #ffbd2a; } .now.success { background
: #05dd8c } .map{ width:100%; padding:20px; }
</style> </head> <body> <div class="map"></div> <br> <p style="text-align: center">控制檯輸入loadMap(10,10)初始化地圖</p> <script> let mapEl = document.querySelector('.map'); loadMap(20, 20);//初始化 /* *@param w :橫寬 *@param h :縱高 */ function loadMap(w, h) { let i, j, k; //1) 隨機二維陣列作為原始地圖,實際上迷宮的地圖要小一圈 let mapData = [],//原始地圖資料 wallQueue = [];//牆塊佇列 for (i = 0; i < h; i++) { mapData[i] = []; for (j = 0; j < w; j++) { k = i + '-' + j; mapData[i][j] = {x: j, y: i,k: k}; //除最外層均標記為牆 mapData[i][j].val = (i == 0 || i == h - 1 || j == 0 || j == w - 1)?1:0; } } //2)指定需要挖掉的牆作為入口,這裡均以左側牆上隨機隨機位置 let exitBlock = mapData[h - 2][2 + ~~(Math.random() * (w - 4))]; wallQueue.push(exitBlock); //3)開始挖路 let lastRoad,//最後一塊挖出的路 ri, wall; while (wallQueue.length > 0) { ri = ~~(Math.random() * wallQueue.length);//從牆佇列中隨機一個 wall = wallQueue[ri];//隨機牆 //檢測上下左右是否有路,true=>設定為路,移除;false=>移除 let mark = 0, y = wall.y,//檢測牆的縱座標 x = wall.x,//檢測牆的橫座標 //周圍需要檢測的點 //[[-1,0],[0,1],[1,0],[-1,0]] 上下左右 [y,x] relArr = [[(y - 1), x], [y, (x + 1)], [(y + 1), x], [y, (x - 1)]], relIndex, relBlock; for (i = 0; (relIndex = relArr[i]) != null; i++) { relBlock = mapData[relIndex[0]][relIndex[1]]; if (relBlock && relBlock.val == 1) { mark++ } } wallQueue.splice(ri, 1);//移除當前塊 if (mark == 1) { wall.val = 1; lastRoad = wall; //如果當前塊為路,將周圍塊加入佇列 for (i = 0; (relIndex = relArr[i]) != null; i++) { relBlock = mapData[relIndex[0]][relIndex[1]]; if (relBlock.val == 0) { wallQueue.push(relBlock); } } } } /* *設定出口,prime演算法只是在特定的地圖內挖出若干條線,但不會挖通地圖,因此可以有兩種模式: * 1)入口和出口,出口需要遍歷邊緣打通 * 2)唯一的缺口作為出口,最後一個打通的塊作為出發點 */ //4) 列印 let resultStr = ''; for (i = 0; i < h; i++) { resultStr += '<tr>'; for (j = 0; j < w; j++) { if (i > 0 && i < h - 1 && j > 0 && j < w - 1) { let b = mapData[i][j]; resultStr += '<td class="' + (b.val == 1 ? (lastRoad.k == b.k ? 'now' : '') : 'wall') + '" loc="' + b.k + '"></td>'; } } resultStr += '</tr>' } mapEl.innerHTML = '<table>' + resultStr + '</table>'; //移動 document.addEventListener('keyup', move); function move(e) { //w:87 a:65 s:83 d:68 let direct = { w: [-1, 0],//上移 d: [0, 1],//右移 s: [1, 0],//下移 a: [0, -1]//左移 }[e.key]; if (direct) { //獲取當前位置 let moveFlag = 0, locNow = document.querySelector('.now').getAttribute('loc').split('-'); locNow[0] = +locNow[0] + direct[0]; locNow[1] = +locNow[1] + direct[1]; if (locNow[0] == exitBlock.y && locNow[1] == exitBlock.x) { moveFlag = 1; document.removeEventListener('keyup', move); } else { if (locNow[0] > 1 && locNow[0] < h - 2 && locNow[1] > 1 && locNow[1] < w - 2) { moveFlag = 2; } } if (moveFlag) { //移動 if (mapData[locNow[0]][locNow[1]].val == 1) { let target = document.querySelector('[loc = "' + locNow[0] + '-' + locNow[1] + '"]'); document.querySelector('.now').classList.remove('now'); target.classList.add('now'); if (moveFlag == 1) { target.classList.add('now', 'success'); } } } } } } </script> </body> </html>