-
Notifications
You must be signed in to change notification settings - Fork 0
/
A_star.js
100 lines (88 loc) · 3.48 KB
/
A_star.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
export default function visualizeAStar(grid, startNode, finishNode) {
const visitedNodesInOrder = AStar(startNode, finishNode, grid)
const shortestPathInOrder = getShortestPathInOrder(finishNode)
animateAlgo(visitedNodesInOrder, shortestPathInOrder)
}
function AStar(startNode, finishNode, grid) {
const unvisitedNodes = grid.slice().flat()
unvisitedNodes.forEach(node => {
node.gScore = Infinity
node.hScore = Infinity
})
const visitedNodesInOrder = []
startNode.gScore = 0
startNode.hScore = Math.abs(startNode.row - finishNode.row) + Math.abs(startNode.col - finishNode.col)
while (unvisitedNodes.length) {
sortNodesByDistance(unvisitedNodes)
const closestNode = unvisitedNodes.shift()
if (!!closestNode.isWall) continue
if (closestNode.gScore === Infinity) return visitedNodesInOrder
closestNode.isVisited.astar = true
visitedNodesInOrder.push(closestNode)
if (closestNode === finishNode) return visitedNodesInOrder
updateNeighborNodes(grid, finishNode, closestNode)
}
}
function animateAlgo(visitedNodesInOrder, shortestPathInOrder) {
for (let i = 1; i <= visitedNodesInOrder.length; i++) {
if (i === visitedNodesInOrder.length) {
setTimeout(() => {
animateShortestPath(shortestPathInOrder)
}, 10 * i);
return
}
if (i === visitedNodesInOrder.length - 1) continue
if (visitedNodesInOrder[i] === undefined) console.log(i)
setTimeout(() => {
const node = visitedNodesInOrder[i]
document.getElementById(node.id).classList.add("visited-astar")
}, 10 * i);
}
}
function animateShortestPath(shortestPathInOrder) {
if (shortestPathInOrder.length === 1) {
alert("NO PATH FOUND")
return
}
for (let i = 1; i < shortestPathInOrder.length - 1; i++) {
setTimeout(() => {
if(i === 1) {
document.querySelector('.start').classList.add('animate')
}
else if(i === shortestPathInOrder.length-2) {
document.querySelector('.finish').classList.add('animate')
}
const node = shortestPathInOrder[i]
document.getElementById(node.id).classList.add("path-astar")
}, 10 * 5 * i);
}
}
function sortNodesByDistance(unvisitedNodes) {
unvisitedNodes.sort((nodeA, nodeB) => (nodeA.gScore + nodeA.hScore) - (nodeB.gScore + nodeB.hScore))
}
function updateNeighborNodes(grid, finishNode, node) {
const neighbors = getNeighbors(grid, node)
neighbors.forEach(neighbor => {
neighbor.gScore = node.gScore + 1
neighbor.hScore = Math.abs(neighbor.row - finishNode.row) + Math.abs(neighbor.col - finishNode.col)
neighbor.prevNode.astar = node
})
}
function getNeighbors(grid, node) {
const neighbors = []
const { row, col } = node
if (row > 0) neighbors.push(grid[row - 1][col])
if (col < grid[0].length - 1) neighbors.push(grid[row][col + 1])
if (row < grid.length - 1) neighbors.push(grid[row + 1][col])
if (col > 0) neighbors.push(grid[row][col - 1])
return neighbors.filter(neighbor => !neighbor.isVisited.astar)
}
function getShortestPathInOrder(finishNode) {
const shortestPathInOrder = []
let currentNode = finishNode
while (currentNode !== null) {
shortestPathInOrder.unshift(currentNode)
currentNode = currentNode.prevNode.astar
}
return shortestPathInOrder
}