dijkstra and A* search 演算法心得及JS實現
dijkstra and A* search 演算法心得及JS實現
目錄
在BFS/DFS的基礎上二者補充了什麼?
二者增加了路徑開銷/距離這一概念,指從一點到另一點的邊的長度。
dijkstra在乎當前搜尋的節點離出發節點的距離,並且在進行遍歷鄰居節點時需要進行路徑的開銷(即為離起點的距離)判斷。如果鄰居節點中有節點已經被遍歷過,此時需要判斷路徑開銷,如果開銷大於當前節點當前開銷加上對應路徑開銷,則需要更新路徑開銷並更新父節點指向, 沒有遍歷過則直接new 新節點加入openList。在遍歷完所有鄰居後需要對openList中加入的節點根據節點路徑開銷進行排序後,取開銷最小的為下一個搜尋節點。而DFS/BFS則無這種操作。
A* 在dijkstra的基礎上略有補充,新增一個估計距離的概念。在對openList中節點進行排序時,根據總開銷 =(路徑開銷 + 估計距離);下面程式碼的估計距離可簡單表示為sqrt((x1-x2)^2 + (y1-y2)^2),可根據實際情況進行調整;
地圖生成(六邊形可能需要人工修改)
A*
dijkstra
A* 六邊形
JS程式碼實現
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>dijkstra search</title>
</head>
<body>
<button type="button" onclick="run()">start</button>
<button type="button" onclick="location.reload()">refresh</button>
<a id="iteration"></a>
<a id="panel" style="display: grid;"></a>
<script type="text/javascript">
const colors = ["black", "gray", "green", "yellow", "red", "purple"];
const pxSize = 20;
const timeStep = 10;
// 0 - obstacle; 1 - blank_1; 2 - start; 4 - goal; blank_3 = 3; blank_5 = 5;
const start = 2, goal = 4, obstacle = 0, blank_1 = 1; blank_3 = 3; blank_5 = 5;
const pathCost = [null, 1, 0, 3, 0, 5];
const map = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 3, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 5, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1], [1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 5, 5, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1], [1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 3, 1, 1, 0, 1, 3, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 3, 1, 1, 0, 1, 3, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1], [1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 3, 3, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 5, 5, 5, 5, 5, 0, 1, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1], [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1], [3, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 5, 5, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1], [1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 5, 5, 5, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1], [1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 5, 5, 5, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 3, 3, 1, 1, 1, 3, 3, 1, 1, 1, 1, 0, 1, 1, 5, 5, 1, 1, 1, 1, 1, 1, 1, 0, 3, 3, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1], [2, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], [4, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 5, 5, 0, 0, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 3, 3, 3, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 3, 3, 1, 1, 0, 1, 1, 3, 1, 1], [0, 0, 1, 1, 5, 5, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 3, 3, 3, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 3, 3, 1, 1, 0, 1, 1, 3, 1, 1], [0, 0, 1, 1, 5, 5, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 3, 1, 1, 0, 1, 1, 3, 1, 1], [0, 0, 1, 1, 5, 5, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 3, 3, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 5, 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1], [1, 5, 5, 5, 5, 5, 5, 5, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]];
const row = map.length;
const col = map[0].length;
document.getElementById("panel").style.gridTemplateColumns = (pxSize + "px ").repeat(col);
document.getElementById("panel").style.gridTemplateRows = (pxSize + "px ").repeat(row);
//add grid - num at row * col
var addGridStringText = "<canvas id='myCanvas' width=" + pxSize * col + " height=" + pxSize * row + " style='position:absolute; solid #000000;'></canvas>" + "<canvas id='myCanvasForFinalPath' width=" + pxSize * col + " height=" + pxSize * row + " style='position:absolute; solid #000000;'></canvas>";
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++)
addGridStringText += "<div row='" + i + "' col='" + j + "' id='" + i + "_" + j + "' style=\"border:1px solid white; background-color:" + colors[map[i][j]] + "\"></div>";
}
document.getElementById("panel").innerHTML = addGridStringText;
function drawLine(from, to) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.lineWidth = 5;
ctx.moveTo(pxSize * (from.colAt + 0.5), pxSize * (from.rowAt + 0.5));
ctx.lineTo(pxSize * (to.colAt + 0.5), pxSize * (to.rowAt + 0.5));
ctx.stroke();
}
function drawFinalPathLine(from, to) {
var c = document.getElementById("myCanvasForFinalPath");
var ctx = c.getContext("2d");
ctx.strokeStyle = '#cc0000';
ctx.lineWidth = 5;
ctx.moveTo(pxSize * (from.colAt + 0.5), pxSize * (from.rowAt + 0.5));
ctx.lineTo(pxSize * (to.colAt + 0.5), pxSize * (to.rowAt + 0.5));
ctx.stroke();
}
function Node(parent, rowat, colat, totalCost) {
this.parent = parent;
this.rowAt = rowat;
this.colAt = colat;
this.totalCost = totalCost;
if (parent != null) drawLine(parent, this);
this.getMapValue = function () {
return map[this.rowAt][this.colAt];
}
this.setParent = function (p) {
this.parent = p;
}
this.setTotalCost = function (cost) {
this.totalCost = cost;
}
this.set
//from left top and normal clock order
this.addNeightBor = function () {
rowAt = this.rowAt;
colAt = this.colAt;
// rightTop = [rowAt - 1, colAt + 1];
// if (rightTop[1] < col && rightTop[0] >= 0 && map[rightTop[0]][rightTop[1]] != obstacle) {
// if (getNodeFromClosed(rightTop) != null) {
// node = getNodeFromClosed(rightTop);
// costPos = map[rightTop[0]][rightTop[1]];
// if (node.totalCost > this.totalCost + costPos) {
// node.setTotalCost(this.totalCost + costPos);
// node.setParent(this);
// }
// } else {
// node = new Node(this, rightTop[0], rightTop[1], this.totalCost + pathCost[map[rightTop[0]][rightTop[1]]]);
// openList.push(node);
// createdList.push(node);
// }
// }
right = [rowAt, colAt + 1];
if (right[1] < col && map[right[0]][right[1]] != obstacle) {
if (getNodeFromClosed(right) != null) {
node = getNodeFromClosed(right);
costPos = map[right[0]][right[1]];
if (node.totalCost > this.totalCost + pathCost[costPos]) {
node.setTotalCost(this.totalCost + pathCost[costPos]);
node.setParent(this);
}
} else {
node = new Node(this, right[0], right[1], this.totalCost + pathCost[map[right[0]][right[1]]]);
openList.push(node);
createdList.push(node);
}
}
// rightBott = [rowAt + 1, colAt + 1];
// if (rightBott[0] < row && rightBott[1] < col && map[rightBott[0]][rightBott[1]] != obstacle) {
// if (getNodeFromClosed(rightBott) != null) {
// node = getNodeFromClosed(rightBott);
// costPos = map[rightBott[0]][rightBott[1]];
// if (node.totalCost > this.totalCost + costPos) {
// node.setTotalCost(this.totalCost + costPos);
// node.setParent(this);
// }
// } else {
// node = new Node(this, rightBott[0], rightBott[1], this.totalCost + pathCost[map[rightBott[0]][rightBott[1]]]);
// openList.push(node);
// createdList.push(node);
// }
// }
bott = [rowAt + 1, colAt];
if (bott[0] < row && map[bott[0]][bott[1]] != obstacle) {
if (getNodeFromClosed(bott) != null) {
node = getNodeFromClosed(bott);
costPos = map[bott[0]][bott[1]];
if (node.totalCost > this.totalCost + pathCost[costPos]) {
node.setTotalCost(this.totalCost + pathCost[costPos]);
node.setParent(this);
}
} else {
node = new Node(this, bott[0], bott[1], this.totalCost + pathCost[map[bott[0]][bott[1]]]);
openList.push(node);
createdList.push(node);
}
}
// leftBott = [rowAt + 1, colAt - 1];
// if (leftBott[1] >= 0 && leftBott[0] < row && map[leftBott[0]][leftBott[1]] != obstacle) {
// if (getNodeFromClosed(leftBott) != null) {
// node = getNodeFromClosed(leftBott);
// costPos = map[leftBott[0]][leftBott[1]];
// if (node.totalCost > this.totalCost + costPos) {
// node.setTotalCost(this.totalCost + costPos);
// node.setParent(this);
// }
// } else {
// node = new Node(this, leftBott[0], leftBott[1], this.totalCost + pathCost[map[leftBott[0]][leftBott[1]]]);
// openList.push(node);
// createdList.push(node);
// }
// }
left = [rowAt, colAt - 1];
if (left[1] >= 0 && map[left[0]][left[1]] != obstacle) {
if (getNodeFromClosed(left) != null) {
node = getNodeFromClosed(left);
costPos = map[left[0]][left[1]];
if (node.totalCost > this.totalCost + pathCost[costPos]) {
node.setTotalCost(this.totalCost + pathCost[costPos]);
node.setParent(this);
}
} else {
node = new Node(this, left[0], left[1], this.totalCost + pathCost[map[left[0]][left[1]]]);
openList.push(node);
createdList.push(node);
}
}
// leftTop = [rowAt - 1, colAt - 1];
// if (leftTop[0] >= 0 && leftTop[1] >= 0 && map[leftTop[0]][leftTop[1]] != obstacle) {
// if (getNodeFromClosed(leftTop) != null) {
// node = getNodeFromClosed(leftTop);
// costPos = map[leftTop[0]][leftTop[1]];
// if (node.totalCost > this.totalCost + costPos) {
// node.setTotalCost(this.totalCost + costPos);
// node.setParent(this);
// }
// } else {
// node = new Node(this, leftTop[0], leftTop[1], this.totalCost + pathCost[map[leftTop[0]][leftTop[1]]]);
// openList.push(node);
// createdList.push(node);
// }
// }
//can not use top, top is already defined as window class in JS
topNode = [rowAt - 1, colAt];
if (topNode[0] >= 0 && map[topNode[0]][topNode[1]] != obstacle) {
if (getNodeFromClosed(topNode) != null) {
node = getNodeFromClosed(topNode);
costPos = map[topNode[0]][topNode[1]];
if (node.totalCost > this.totalCost + pathCost[costPos]) {
node.setTotalCost(this.totalCost + pathCost[costPos]);
node.setParent(this);
}
} else {
node = new Node(this, topNode[0], topNode[1], this.totalCost + pathCost[map[topNode[0]][topNode[1]]]);
openList.push(node);
createdList.push(node);
}
}
}
}
function getNodeFromClosed(testNode) {
for (i = 0; i < createdList.length; i++) {
if (createdList[i].rowAt == testNode[0] && createdList[i].colAt == testNode[1]) return createdList[i];
}
return null;
}
var openList;
var closedList;
var createdList;
var startNode;
var searchNode;
var currentNode;
function run() {
startNode = getStartNode();
searchNode = startNode;
openList = [];
openList.push(startNode);
createdList = [];
createdList.push(startNode);
closedList = [];
iterationTime = 0;
//start iteration procedure
if (openList.length != 0) {
iteration();
}
}
function iteration() {
//remove highlight of currentNode
if (currentNode != null) document.getElementById(currentNode.rowAt + "_" + currentNode.colAt).style.border = "1px solid white";
currentNode = openList.pop();
//highlight currentNode
document.getElementById(currentNode.rowAt + "_" + currentNode.colAt).style.border = "1px solid red";
document.getElementById("iteration").innerText = "iteration:" + ++iterationTime;
if (currentNode.getMapValue() == goal) {
closedList.push(currentNode);
//find path through closedList
var node = closedList[closedList.length - 1]; //goal node
var path = new Array(node);
while (node.getMapValue != startNode.getMapValue) {
node = node.parent;
path.unshift(node);
}
for (i = path.length - 1; i > 0; i--) {
drawFinalPathLine(path[i], path[i].parent);
// console.log(path[i].rowAt + " " + path[i].colAt);
}
return;
} else setTimeout(() => {
currentNode.addNeightBor();
closedList.push(currentNode);
var i = 1;
for (; i < openList.length; i++) {
var k = i;
for (; k > 0; k--) {
if (parseInt(openList[k].totalCost) > parseInt(openList[k - 1].totalCost)) {
temp = openList[k];
openList[k] = openList[k - 1];
openList[k - 1] = temp;
}
}
}
iteration();
}, timeStep);
}
function getStartNode() {
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
if (map[i][j] == start)
return new Node(null, i, j, 0);
}
}
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>A* search</title>
</head>
<body>
<button type="button" onclick="run()">start</button>
<button type="button" onclick="location.reload()">refresh</button>
<a id="iteration"></a>
<a id="panel" style="display: grid;"></a>
<script type="text/javascript">
const colors = ["black", "gray", "green", "yellow", "red", "purple"];
const pxSize = 20;
const timeStep = 10;
// 0 - obstacle; 1 - blank_1; 2 - start; 4 - goal; blank_3 = 3; blank_5 = 5;
const start = 2, goal = 4, obstacle = 0, blank_1 = 1; blank_3 = 3; blank_5 = 5;
const pathCost = [null, 1, 0, 3, 0, 5];
const map = [[1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,3,1,0,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,5,5,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,1,1,1,0,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,5,5,1,1,1,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0],[1,0,0,0,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,1,1,1,0,1,1,0,0,0,0,0,1,1,1,0,1,1,1,0,1,3,1,1,0,1,3,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,3,1,1,1,1,1,1,1,0,1,1,0,1,1,1],[1,1,0,1,0,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,3,1,1,0,1,3,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,3,1,1,1,1,1,1,1,0,1,1,0,1,1,1],[1,1,0,1,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1],[1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,3,3,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,1,1,1,0,5,5,5,5,5,0,1,1,1,1,1,1],[0,0,0,1,1,1,1,3,1,1,1,1,1,1,1,1,3,3,3,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1],[1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,3,3,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,5,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1],[3,1,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,3,3,0,1,1,1,1,0,1,1,1,1,0,1,5,5,1,1,5,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1],[1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,5,5,5,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1],[1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,1,5,5,5,0,1,1,0,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,0,1,1,1,3,3,1,1,1,3,3,1,1,1,1,0,1,1,5,5,1,1,1,1,1,1,1,0,3,3,1,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1],[2,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,3,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1],[4,1,1,1,1,5,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,5,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,3,3,3,3,0,0,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,1,5,1,1,1,1,5,1,1,1,1,0,0,0,0,0,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,0,5,5,0,0,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[1,1,1,0,0,0,0,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,0,1,1,5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,3,3,3,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,3,3,3,1,1,0,0,0,0,1,1,1,0,0,0,1,3,3,1,1,0,1,1,3,1,1],[0,0,1,1,5,5,1,1,1,3,3,3,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,3,3,3,1,1,0,0,0,0,1,1,1,0,0,0,1,3,3,1,1,0,1,1,3,1,1],[0,0,1,1,5,5,1,1,1,3,3,3,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,0,0,0,1,3,3,1,1,0,1,1,3,1,1],[0,0,1,1,5,5,1,1,1,3,3,3,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,1,1,1,1,1,5,5,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3,3,3,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,1,1,1,1,1,5,5,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,5,5,5,5,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1],[1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,0,1,1,5,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,3,3,3,1,1,1,1],[1,5,5,5,5,5,5,5,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,5,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,5,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,5,1,1,1,0,0,1,1,1,1,1],[1,1,1,1,1,0,0,1,1,1,1,1,1,5,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,0,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1],[1,1,1,1,1,0,0,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1]];
const row = map.length;
const col = map[0].length;
document.getElementById("panel").style.gridTemplateColumns = (pxSize + "px ").repeat(col);
document.getElementById("panel").style.gridTemplateRows = (pxSize + "px ").repeat(row);
//add grid - num at row * col
var addGridStringText = "<canvas id='myCanvas' width=" + pxSize * col + " height=" + pxSize * row + " style='position:absolute; solid #000000;'></canvas>" + "<canvas id='myCanvasForFinalPath' width=" + pxSize * col + " height=" + pxSize * row + " style='position:absolute; solid #000000;'></canvas>";
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++)
addGridStringText += "<div row='" + i + "' col='" + j + "' id='" + i + "_" + j + "' style=\"border:1px solid white; background-color:" + colors[map[i][j]] + "\"></div>";
}
document.getElementById("panel").innerHTML = addGridStringText;
function drawLine(from, to) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.lineWidth = 5;
ctx.moveTo(pxSize * (from.colAt + 0.5), pxSize * (from.rowAt + 0.5));
ctx.lineTo(pxSize * (to.colAt + 0.5), pxSize * (to.rowAt + 0.5));
ctx.stroke();
}
function drawFinalPathLine(from, to) {
var c = document.getElementById("myCanvasForFinalPath");
var ctx = c.getContext("2d");
ctx.strokeStyle = '#cc0000';
ctx.lineWidth = 5;
ctx.moveTo(pxSize * (from.colAt + 0.5), pxSize * (from.rowAt + 0.5));
ctx.lineTo(pxSize * (to.colAt + 0.5), pxSize * (to.rowAt + 0.5));
ctx.stroke();
}
function Node(parent, rowat, colat, realCost) {
this.parent = parent;
this.rowAt = rowat;
this.colAt = colat;
this.realCost = realCost;
this.totalCost = Math.floor(Math.sqrt(Math.pow(goalNodePos[0] - this.rowAt, 2) + Math.pow(goalNodePos[1] - this.colAt, 2))) + this.realCost;
if (parent != null) drawLine(parent, this);
this.getMapValue = function () {
return map[this.rowAt][this.colAt];
}
this.getTotalCost = function () {
return this.totalCost;
}
this.setParent = function (p) {
this.parent = p;
}
this.setRealCost = function (cost) {
this.realCost = cost;
this.totalCost = Math.floor(Math.sqrt(Math.pow(goalNodePos[0] - this.rowAt, 2) + Math.pow(goalNodePos[1] - this.colAt, 2))) + this.realCost;
}
//from left top and normal clock order
this.addNeightBor = function () {
rowAt = this.rowAt;
colAt = this.colAt;
// rightTop = [rowAt - 1, colAt + 1];
// if (rightTop[1] < col && rightTop[0] >= 0 && map[rightTop[0]][rightTop[1]] != obstacle) {
// if (getNodeFromClosed(rightTop) != null) {
// node = getNodeFromClosed(rightTop);
// costPos = map[rightTop[0]][rightTop[1]];
// if (node.realCost > this.realCost + costPos) {
// node.setRealCost(this.realCost + costPos);
// node.setParent(this);
// }
// } else {
// node = new Node(this, rightTop[0], rightTop[1], this.realCost + pathCost[map[rightTop[0]][rightTop[1]]]);
// openList.push(node);
// createdList.push(node);
// }
// }
right = [rowAt, colAt + 1];
if (right[1] < col && map[right[0]][right[1]] != obstacle) {
if (getNodeFromClosed(right) != null) {
node = getNodeFromClosed(right);
costPos = map[right[0]][right[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setParent(this);
}
} else {
node = new Node(this, right[0], right[1], this.realCost + pathCost[map[right[0]][right[1]]]);
openList.push(node);
createdList.push(node);
}
}
// rightBott = [rowAt + 1, colAt + 1];
// if (rightBott[0] < row && rightBott[1] < col && map[rightBott[0]][rightBott[1]] != obstacle) {
// if (getNodeFromClosed(rightBott) != null) {
// node = getNodeFromClosed(rightBott);
// costPos = map[rightBott[0]][rightBott[1]];
// if (node.realCost > this.realCost + costPos) {
// node.setRealCost(this.realCost + costPos);
// node.setParent(this);
// }
// } else {
// node = new Node(this, rightBott[0], rightBott[1], this.realCost + pathCost[map[rightBott[0]][rightBott[1]]]);
// openList.push(node);
// createdList.push(node);
// }
// }
bott = [rowAt + 1, colAt];
if (bott[0] < row && map[bott[0]][bott[1]] != obstacle) {
if (getNodeFromClosed(bott) != null) {
node = getNodeFromClosed(bott);
costPos = map[bott[0]][bott[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setParent(this);
}
} else {
node = new Node(this, bott[0], bott[1], this.realCost + pathCost[map[bott[0]][bott[1]]]);
openList.push(node);
createdList.push(node);
}
}
// leftBott = [rowAt + 1, colAt - 1];
// if (leftBott[1] >= 0 && leftBott[0] < row && map[leftBott[0]][leftBott[1]] != obstacle) {
// if (getNodeFromClosed(leftBott) != null) {
// node = getNodeFromClosed(leftBott);
// costPos = map[leftBott[0]][leftBott[1]];
// if (node.realCost > this.realCost + costPos) {
// node.setRealCost(this.realCost + costPos);
// node.setParent(this);
// }
// } else {
// node = new Node(this, leftBott[0], leftBott[1], this.realCost + pathCost[map[leftBott[0]][leftBott[1]]]);
// openList.push(node);
// createdList.push(node);
// }
// }
left = [rowAt, colAt - 1];
if (left[1] >= 0 && map[left[0]][left[1]] != obstacle) {
if (getNodeFromClosed(left) != null) {
node = getNodeFromClosed(left);
costPos = map[left[0]][left[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setParent(this);
}
} else {
node = new Node(this, left[0], left[1], this.realCost + pathCost[map[left[0]][left[1]]]);
openList.push(node);
createdList.push(node);
}
}
// leftTop = [rowAt - 1, colAt - 1];
// if (leftTop[0] >= 0 && leftTop[1] >= 0 && map[leftTop[0]][leftTop[1]] != obstacle) {
// if (getNodeFromClosed(leftTop) != null) {
// node = getNodeFromClosed(leftTop);
// costPos = map[leftTop[0]][leftTop[1]];
// if (node.realCost > this.realCost + costPos) {
// node.setRealCost(this.realCost + costPos);
// node.setParent(this);
// }
// } else {
// node = new Node(this, leftTop[0], leftTop[1], this.realCost + pathCost[map[leftTop[0]][leftTop[1]]]);
// openList.push(node);
// createdList.push(node);
// }
// }
//can not use top, top is already defined as window class in JS
topNode = [rowAt - 1, colAt];
if (topNode[0] >= 0 && map[topNode[0]][topNode[1]] != obstacle) {
if (getNodeFromClosed(topNode) != null) {
node = getNodeFromClosed(topNode);
costPos = map[topNode[0]][topNode[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setParent(this);
}
} else {
node = new Node(this, topNode[0], topNode[1], this.realCost + pathCost[map[topNode[0]][topNode[1]]]);
openList.push(node);
createdList.push(node);
}
}
}
}
function getNodeFromClosed(testNode) {
for (i = 0; i < createdList.length; i++) {
if (createdList[i].rowAt == testNode[0] && createdList[i].colAt == testNode[1]) return createdList[i];
}
return null;
}
var openList;
var closedList;
var createdList;
var startNode;
var goalNode;
var currentNode;
function run() {
goalNodePos = getGoalNodePosition();
startNode = getStartNode();
openList = [];
openList.push(startNode);
createdList = [];
createdList.push(startNode);
closedList = [];
iterationTime = 0;
//start iteration procedure
if (openList.length != 0) {
iteration();
}
}
function iteration() {
//after 2s, remove highlight of currentNode
if (currentNode != null) document.getElementById(currentNode.rowAt + "_" + currentNode.colAt).style.border = "1px solid white";
currentNode = openList.pop();
//highlight currentNode
document.getElementById(currentNode.rowAt + "_" + currentNode.colAt).style.border = "1px solid red";
document.getElementById("iteration").innerText = "iteration:" + ++iterationTime;
if (currentNode.getMapValue() == goal) {
closedList.push(currentNode);
//find path through closedList
var node = closedList[closedList.length - 1]; //goal node
var path = new Array(node);
while (node.getMapValue != startNode.getMapValue) {
node = node.parent;
path.unshift(node);
}
for (i = path.length - 1; i > 0; i--) {
drawFinalPathLine(path[i], path[i].parent);
// console.log(path[i].rowAt + " " + path[i].colAt);
}
return;
} else setTimeout(() => {
currentNode.addNeightBor();
closedList.push(currentNode);
var i = 1;
for (; i < openList.length; i++) {
var k = i;
for (; k > 0; k--) {
if (openList[k].getTotalCost() > openList[k - 1].getTotalCost()) {
temp = openList[k];
openList[k] = openList[k - 1];
openList[k - 1] = temp;
}
}
}
iteration();
}, timeStep);
}
function getStartNode() {
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
if (map[i][j] == start)
return new Node(null, i, j, 0);
}
}
}
function getGoalNodePosition() {
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
if (map[i][j] == goal)
return [i, j];
}
}
}
</script>
</body>
</html>
六邊形地圖A*實現
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>A*_forHexShape</title>
</head>
<body>
<button type="button" onclick="run()">start</button>
<button type="button" onclick="location.reload()">refresh</button>
<a id="iteration"></a><br>
<a id="panel"></a>
<script type="text/javascript">
const colors = ["black", "gray", "green", "yellow", "red", "purple"];
const start = 2, goal = 4, obstacle = 0, blank_1 = 1; blank_3 = 3; blank_5 = 5;
const timeStep = 10;
const edgeLength = 15;
const pathCost = [null, 1, 0, 3, 0, 5];
// const map = [[2, 1, 0], [1, 1, 0], [0, 1, 4]];
const map = [[1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,3,1,0,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,5,5,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,1,1,1,0,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,5,5,1,1,1,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0],[1,0,0,0,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,1,1,1,0,1,1,0,0,0,0,0,1,1,1,0,1,1,1,0,1,3,1,1,0,1,3,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,3,1,1,1,1,1,1,1,0,1,1,0,1,1,1],[1,1,0,1,0,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,3,1,1,0,1,3,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,3,1,1,1,1,1,1,1,0,1,1,0,1,1,1],[1,1,0,1,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1],[1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,3,3,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,1,1,1,0,5,5,5,5,5,0,1,1,1,1,1,1],[0,0,0,1,1,1,1,3,1,1,1,1,1,1,1,1,3,3,3,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1],[1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,3,3,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,5,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1],[3,1,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,3,3,0,1,1,1,1,0,1,1,1,1,0,1,5,5,1,1,5,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1],[1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,5,5,5,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1],[1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,1,5,5,5,0,1,1,0,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,0,1,1,1,3,3,1,1,1,3,3,1,1,1,1,0,1,1,5,5,1,1,1,1,1,1,1,0,3,3,1,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1],[2,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,3,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1],[4,1,1,1,1,5,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,5,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,3,3,3,3,0,0,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,1,5,1,1,1,1,5,1,1,1,1,0,0,0,0,0,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,0,5,5,0,0,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[1,1,1,0,0,0,0,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,0,1,1,5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,5,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,3,3,3,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,3,3,3,1,1,0,0,0,0,1,1,1,0,0,0,1,3,3,1,1,0,1,1,3,1,1],[0,0,1,1,5,5,1,1,1,3,3,3,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,3,3,3,1,1,0,0,0,0,1,1,1,0,0,0,1,3,3,1,1,0,1,1,3,1,1],[0,0,1,1,5,5,1,1,1,3,3,3,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,0,0,0,1,3,3,1,1,0,1,1,3,1,1],[0,0,1,1,5,5,1,1,1,3,3,3,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,1,1,1,1,1,5,5,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3,3,3,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,1,1,1,1,1,5,5,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,5,5,5,5,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1],[1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,0,1,1,5,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,3,3,3,1,1,1,1],[1,5,5,5,5,5,5,5,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,5,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,5,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,5,1,1,1,0,0,1,1,1,1,1],[1,1,1,1,1,0,0,1,1,1,1,1,1,5,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,0,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1],[1,1,1,1,1,0,0,1,1,1,1,1,1,5,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1]];
const row = map.length;
const col = map[0].length;
const sqrt_3divide2 = Math.sqrt(3) / 2;
const canvas_width = Math.round(sqrt_3divide2 * 2 * edgeLength * (col + 0.5));
const canvas_height = Math.round(edgeLength / 2 * (3 * row + 1));
document.getElementById("panel").innerHTML = "<canvas id='drawHexShape' width=" + canvas_width + " height=" + canvas_height + " style='position:absolute;'></canvas>" +
"<canvas id='drawPath' width=" + canvas_width + " height=" + canvas_height + " style='position:absolute;'></canvas>" +
"<canvas id='drawFinalPath' width=" + canvas_width + " height=" + canvas_height + " style='position:absolute;'></canvas>";
var position_information = new Array();
for (i = 0; i < row; i++) {
temp = new Array();
for (j = 0; j < col; j++) {
temp.push([Math.sqrt(3) * edgeLength * (j + (1 + i % 2) / 2), edgeLength * (1 + 3 * i / 2)]);
}
position_information.push(temp);
}
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
drawSixEdges(i, j, null);
}
}
function drawSixEdges(i, j, color) {
x = position_information[i][j][0], y = position_information[i][j][1];
c = document.getElementById("drawHexShape");
ctx = c.getContext("2d");
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(x + edgeLength * sqrt_3divide2, y - edgeLength / 2);
ctx.lineTo(x + edgeLength * sqrt_3divide2, y + edgeLength / 2);
ctx.lineTo(x, y + edgeLength);
ctx.lineTo(x - edgeLength * sqrt_3divide2, y + edgeLength / 2);
ctx.lineTo(x - edgeLength * sqrt_3divide2, y - edgeLength / 2);
ctx.lineTo(x, y - edgeLength);
ctx.lineTo(x + edgeLength * sqrt_3divide2, y - edgeLength / 2);
ctx.stroke();
if(color == null) ctx.fillStyle = colors[map[i][j]];
else ctx.fillStyle = color;
ctx.fill();
}
function drawLine(nodeP, node) {
x_from = position_information[nodeP.rowAt][nodeP.colAt][0], y_from = position_information[nodeP.rowAt][nodeP.colAt][1];
x_to = position_information[node.rowAt][node.colAt][0], y_to = position_information[node.rowAt][node.colAt][1];
c = document.getElementById("drawPath");
ctx = c.getContext("2d");
ctx.lineWidth = 2;
ctx.moveTo(x_from, y_from);
ctx.lineTo(x_to, y_to);
ctx.stroke();
}
function drawFinalPathLine(nodeP, node) {
x_from = position_information[nodeP.rowAt][nodeP.colAt][0], y_from = position_information[nodeP.rowAt][nodeP.colAt][1];
x_to = position_information[node.rowAt][node.colAt][0], y_to = position_information[node.rowAt][node.colAt][1];
c = document.getElementById("drawFinalPath");
ctx = c.getContext("2d");
ctx.lineWidth = 2;
ctx.strokeStyle = '#cc0000';
ctx.moveTo(x_from, y_from);
ctx.lineTo(x_to, y_to);
ctx.stroke();
}
function Node(parent, rowat, colat, realCost) {
this.parent = parent;
this.rowAt = rowat;
this.colAt = colat;
this.realCost = realCost;
this.totalCost = Math.floor(Math.sqrt(Math.pow((goalNodePos[0] - position_information[this.rowAt][this.colAt][0]) / edgeLength, 2) + Math.pow((goalNodePos[1] - position_information[this.rowAt][this.colAt][0]) / edgeLength, 2))) + this.realCost;
if (parent != null) drawLine(parent, this);
this.getMapValue = function () {
return map[this.rowAt][this.colAt];
}
this.setTotalCost = function() {
this.totalCost = Math.floor(Math.sqrt(Math.pow((goalNodePos[0] - position_information[this.rowAt][this.colAt][0]) / edgeLength, 2) + Math.pow((goalNodePos[1] - position_information[this.rowAt][this.colAt][0]) / edgeLength, 2))) + this.realCost;
}
this.setParent = function (p) {
this.parent = p;
}
this.setRealCost = function (cost) {
this.realCost = cost;
}
//from left top and normal clock order
this.addNeightBor = function () {
rowAt = this.rowAt;
colAt = this.colAt;
if (rowAt % 2 == 0) {
//top, lefttop, left, leftbott, bott, right
right = [rowAt, colAt + 1];
if (right[1] < col && map[right[0]][right[1]] != obstacle) {
if (getNodeFromCreated(right) != null) {
node = getNodeFromCreated(right);
costPos = map[right[0]][right[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, right[0], right[1], this.realCost + pathCost[map[right[0]][right[1]]]);
openList.push(node);
createdList.push(node);
}
}
bott = [rowAt + 1, colAt];
if (bott[0] < row && map[bott[0]][bott[1]] != obstacle) {
if (getNodeFromCreated(bott) != null) {
node = getNodeFromCreated(bott);
costPos = map[bott[0]][bott[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, bott[0], bott[1], this.realCost + pathCost[map[bott[0]][bott[1]]]);
openList.push(node);
createdList.push(node);
}
}
leftBott = [rowAt + 1, colAt - 1];
if (leftBott[1] >= 0 && leftBott[0] < row && map[leftBott[0]][leftBott[1]] != obstacle) {
if (getNodeFromCreated(leftBott) != null) {
node = getNodeFromCreated(leftBott);
costPos = map[leftBott[0]][leftBott[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, leftBott[0], leftBott[1], this.realCost + pathCost[map[leftBott[0]][leftBott[1]]]);
openList.push(node);
createdList.push(node);
}
}
left = [rowAt, colAt - 1];
if (left[1] >= 0 && map[left[0]][left[1]] != obstacle) {
if (getNodeFromCreated(left) != null) {
node = getNodeFromCreated(left);
costPos = map[left[0]][left[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, left[0], left[1], this.realCost + pathCost[map[left[0]][left[1]]]);
openList.push(node);
createdList.push(node);
}
}
leftTop = [rowAt - 1, colAt - 1];
if (leftTop[0] >= 0 && leftTop[1] >= 0 && map[leftTop[0]][leftTop[1]] != obstacle) {
if (getNodeFromCreated(leftTop) != null) {
node = getNodeFromCreated(leftTop);
costPos = map[leftTop[0]][leftTop[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, leftTop[0], leftTop[1], this.realCost + pathCost[map[leftTop[0]][leftTop[1]]]);
openList.push(node);
createdList.push(node);
}
}
//can not use top, top is already defined as window class in JS
topNode = [rowAt - 1, colAt];
if (topNode[0] >= 0 && map[topNode[0]][topNode[1]] != obstacle) {
if (getNodeFromCreated(topNode) != null) {
node = getNodeFromCreated(topNode);
costPos = map[topNode[0]][topNode[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, topNode[0], topNode[1], this.realCost + pathCost[map[topNode[0]][topNode[1]]]);
openList.push(node);
createdList.push(node);
}
}
}
if (rowAt % 2 == 1) {
//top, righttop, right, rtightbott, bott, left
rightTop = [rowAt - 1, colAt + 1];
if (rightTop[1] < col && rightTop[0] >= 0 && map[rightTop[0]][rightTop[1]] != obstacle) {
if (getNodeFromCreated(rightTop) != null) {
node = getNodeFromCreated(rightTop);
costPos = map[rightTop[0]][rightTop[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, rightTop[0], rightTop[1], this.realCost + pathCost[map[rightTop[0]][rightTop[1]]]);
openList.push(node);
createdList.push(node);
}
}
right = [rowAt, colAt + 1];
if (right[1] < col && map[right[0]][right[1]] != obstacle) {
if (getNodeFromCreated(right) != null) {
node = getNodeFromCreated(right);
costPos = map[right[0]][right[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, right[0], right[1], this.realCost + pathCost[map[right[0]][right[1]]]);
openList.push(node);
createdList.push(node);
}
}
rightBott = [rowAt + 1, colAt + 1];
if (rightBott[0] < row && rightBott[1] < col && map[rightBott[0]][rightBott[1]] != obstacle) {
if (getNodeFromCreated(rightBott) != null) {
node = getNodeFromCreated(rightBott);
costPos = map[rightBott[0]][rightBott[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, rightBott[0], rightBott[1], this.realCost + pathCost[map[rightBott[0]][rightBott[1]]]);
openList.push(node);
createdList.push(node);
}
}
bott = [rowAt + 1, colAt];
if (bott[0] < row && map[bott[0]][bott[1]] != obstacle) {
if (getNodeFromCreated(bott) != null) {
node = getNodeFromCreated(bott);
costPos = map[bott[0]][bott[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, bott[0], bott[1], this.realCost + pathCost[map[bott[0]][bott[1]]]);
openList.push(node);
createdList.push(node);
}
}
left = [rowAt, colAt - 1];
if (left[1] >= 0 && map[left[0]][left[1]] != obstacle) {
if (getNodeFromCreated(left) != null) {
node = getNodeFromCreated(left);
costPos = map[left[0]][left[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, left[0], left[1], this.realCost + pathCost[map[left[0]][left[1]]]);
openList.push(node);
createdList.push(node);
}
}
//can not use top, top is already defined as window class in JS
topNode = [rowAt - 1, colAt];
if (topNode[0] >= 0 && map[topNode[0]][topNode[1]] != obstacle) {
if (getNodeFromCreated(topNode) != null) {
node = getNodeFromCreated(topNode);
costPos = map[topNode[0]][topNode[1]];
if (node.realCost > this.realCost + pathCost[costPos]) {
node.setRealCost(this.realCost + pathCost[costPos]);
node.setTotalCost();
node.setParent(this);
}
} else {
node = new Node(this, topNode[0], topNode[1], this.realCost + pathCost[map[topNode[0]][topNode[1]]]);
openList.push(node);
createdList.push(node);
}
}
}
}
}
function getNodeFromCreated(testNode) {
for (i = 0; i < createdList.length; i++) {
if (createdList[i].rowAt == testNode[0] && createdList[i].colAt == testNode[1]) return createdList[i];
}
return null;
}
var openList;
var closedList;
var createdList;
var startNode;
var goalNode;
var currentNode;
function run() {
goalNodePos = getGoalNodePosition();
startNode = getStartNode();
openList = [];
openList.push(startNode);
createdList = [];
createdList.push(startNode);
closedList = [];
iterationTime = 0;
//start iteration procedure
if (openList.length != 0) {
iteration();
}
}
function iteration() {
//remove highlight of currentNode
if (currentNode != null) drawSixEdges(currentNode.rowAt, currentNode.colAt, null);
currentNode = openList.pop();
//highlight currentNode
drawSixEdges(currentNode.rowAt, currentNode.colAt, "#D81B60");
document.getElementById("iteration").innerText = "iteration:" + ++iterationTime;
if (currentNode.getMapValue() == goal) {
closedList.push(currentNode);
//find path through closedList
var node = closedList[closedList.length - 1]; //goal node
var path = new Array(node);
while (node.getMapValue != startNode.getMapValue) {
node = node.parent;
path.unshift(node);
}
for (i = path.length - 1; i > 0; i--) {
drawFinalPathLine(path[i], path[i].parent);
}
return;
} else setTimeout(() => {
currentNode.addNeightBor();
closedList.push(currentNode);
var i = 1;
for (; i < openList.length; i++) {
var k = i;
for (; k > 0; k--) {
if (openList[k].totalCost > openList[k - 1].totalCost) {
temp = openList[k];
openList[k] = openList[k - 1];
openList[k - 1] = temp;
}
}
}
iteration();
}, timeStep);
}
function getStartNode() {
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
if (map[i][j] == start)
return new Node(null, i, j, 0);
}
}
}
function getGoalNodePosition() {
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
if (map[i][j] == goal)
return position_information[i][j];
}
}
}
</script>
</body>
</html>
相關文章
- 10行實現最短路演算法——Dijkstra演算法
- 圖解Dijkstra演算法+程式碼實現圖解演算法
- JS-BFA演算法及ui實現JS演算法UI
- Dijkstra演算法及正確性分析演算法
- 如何在 Java 中實現 Dijkstra 最短路演算法Java演算法
- python實現Dijkstra演算法之 最短路徑問題Python演算法
- js實現資料結構及演算法之排序演算法JS資料結構演算法排序
- 常見排序演算法原理及JS程式碼實現排序演算法JS
- Dijkstra演算法演算法
- dijkstra演算法筆記(C語言實現,顯示路徑)演算法筆記C語言
- **超詳細的**10種排序演算法原理及 JS 實現排序演算法JS
- js實現資料結構及演算法之雜湊表(Hashtable)JS資料結構演算法
- 最短路dijkstra演算法演算法
- 最短路 - Dijkstra 演算法演算法
- 貪心演算法Dijkstra演算法
- Svm演算法原理及實現演算法
- 最短路演算法之:Dijkstra 演算法演算法
- JS 實現快取演算法(FIFO/LRU)JS快取演算法
- js實現敏感詞過濾演算法JS演算法
- Node.js 流的使用及實現Node.js
- sku演算法介紹及實現演算法
- 最短路-樸素版Dijkstra演算法&堆優化版的Dijkstra演算法優化
- 【JAVA演算法】圖論演算法 -- Dijkstra演算法Java演算法圖論
- 最短路徑之Dijkstra演算法演算法
- Dijkstra 演算法的手動分析演算法
- 排序演算法分析總結(附js實現)排序演算法JS
- 蟻群演算法原理及Matlab實現演算法Matlab
- CRC演算法原理、推導及實現演算法
- 最短路徑——Dijkstra演算法和Floyd演算法演算法
- 最短路徑問題 (dijkstra演算法)演算法
- dijkstra最短路演算法模板(雙源)演算法
- 單源最短路徑-Dijkstra演算法演算法
- 深析filemap.js——關於JS的演算法及優化的實踐JS演算法優化
- 實現前後端分離的心得後端
- 0016:單源最短路徑(dijkstra演算法)演算法
- JS實現動態瀑布流及放大切換圖片效果(js案例)JS
- Dijkstra演算法和Prim演算法有什麼區別?演算法
- Node.js Stream 流的使用及實現總結Node.js