-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathBiBreadthFirstFinder.js
150 lines (135 loc) · 4.36 KB
/
BiBreadthFirstFinder.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
var Util = require('../core/Util');
var DiagonalMovement = require('../core/DiagonalMovement');
/**
* Bi-directional Breadth-First-Search path finder.
* @constructor
* @param {object} opt
* @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
* Deprecated, use diagonalMovement instead.
* @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
* block corners. Deprecated, use diagonalMovement instead.
* @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
*/
function BiBreadthFirstFinder(opt) {
opt = opt || {};
this.allowDiagonal = opt.allowDiagonal;
this.dontCrossCorners = opt.dontCrossCorners;
this.diagonalMovement = opt.diagonalMovement;
if (!this.diagonalMovement) {
if (!this.allowDiagonal) {
this.diagonalMovement = DiagonalMovement.Never;
} else {
if (this.dontCrossCorners) {
this.diagonalMovement = DiagonalMovement.OnlyWhenNoObstacles;
} else {
this.diagonalMovement = DiagonalMovement.IfAtMostOneObstacle;
}
}
}
}
/**
* Find and return the the path.
* @return {Array<Array<number>>} The path, including both start and
* end positions.
*/
BiBreadthFirstFinder.prototype.findPath = function(startX, startY, endX, endY, grid) {
var startNode = grid.getNodeAt(startX, startY),
endNode = grid.getNodeAt(endX, endY),
startOpenList = [], endOpenList = [],
neighbors, neighbor, node,
diagonalMovement = this.diagonalMovement,
BY_START = 0, BY_END = 1,
i, l;
var operations = [];
// push the start and end nodes into the queues
startOpenList.push(startNode);
startNode.opened = true;
startNode.by = BY_START;
operations.push({
x: startNode.x,
y: startNode.y,
attr: 'opened',
value: true
});
endOpenList.push(endNode);
endNode.opened = true;
endNode.by = BY_END;
operations.push({
x: endNode.x,
y: endNode.y,
attr: 'opened',
value: true
});
// while both the queues are not empty
while (startOpenList.length && endOpenList.length) {
// expand start open list
node = startOpenList.shift();
node.closed = true;
operations.push({
x: node.x,
y: node.y,
attr: 'closed',
value: true
});
neighbors = grid.getNeighbors(node, diagonalMovement);
for (i = 0, l = neighbors.length; i < l; ++i) {
neighbor = neighbors[i];
if (neighbor.closed) {
continue;
}
if (neighbor.opened) {
// if this node has been inspected by the reversed search,
// then a path is found.
if (neighbor.by === BY_END) {
return Util.biBacktrace(node, neighbor, operations);
}
continue;
}
startOpenList.push(neighbor);
neighbor.parent = node;
neighbor.opened = true;
neighbor.by = BY_START;
operations.push({
x: neighbor.x,
y: neighbor.y,
attr: 'opened',
value: true
});
}
// expand end open list
node = endOpenList.shift();
node.closed = true;
operations.push({
x: node.x,
y: node.y,
attr: 'closed',
value: true
});
neighbors = grid.getNeighbors(node, diagonalMovement);
for (i = 0, l = neighbors.length; i < l; ++i) {
neighbor = neighbors[i];
if (neighbor.closed) {
continue;
}
if (neighbor.opened) {
if (neighbor.by === BY_START) {
return Util.biBacktrace(neighbor, node, operations);
}
continue;
}
endOpenList.push(neighbor);
neighbor.parent = node;
neighbor.opened = true;
neighbor.by = BY_END;
operations.push({
x: neighbor.x,
y: neighbor.y,
attr: 'opened',
value: true
});
}
}
// fail to find the path
return [];
};
module.exports = BiBreadthFirstFinder;