Skip to content

Commit 802fb04

Browse files
committed
move all functionality into a single file
1 parent 27b9a01 commit 802fb04

File tree

9 files changed

+198
-528
lines changed

9 files changed

+198
-528
lines changed

Gruntfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = function(grunt) {
1616
globals: {
1717
}
1818
},
19-
all: ['graph.js', 'astar.js']
19+
all: ['astar.js']
2020
}
2121
});
2222

README.md

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,10 @@
44

55
See a demo at http://www.briangrinstead.com/files/astar/
66

7-
### astar.js
8-
9-
The newest version of the algorithm using a Binary Heap. It is quite faster than the original.
10-
http://www.briangrinstead.com/blog/astar-search-algorithm-in-javascript-updated
11-
Binary Heap taken from http://eloquentjavascript.net/appendix2.html (license: http://creativecommons.org/licenses/by/3.0/)
12-
13-
### original-implementation/astar-list.js:
14-
15-
The original version of the algorithm based off the original blog post at: http://www.briangrinstead.com/blog/astar-search-algorithm-in-javascript
16-
I left it in because it may be a little easier for some people to understand, but if you are planning on actually using this, I would strongly recommend using astar.js instead.
17-
187
## Sample Usage
198

209
If you want just the A* search code (not the demo visualization), use code like this http://gist.github.com/581352
2110

22-
<script type='text/javascript' src='graph.js'></script>
2311
<script type='text/javascript' src='astar.js'></script>
2412
<script type='text/javascript'>
2513
var graph = new Graph([
@@ -48,6 +36,15 @@ If you want just the A* search code (not the demo visualization), use code like
4836
// resultWithWeight is an array containing the shortest path taking into account the weight of a node
4937
</script>
5038

39+
### Original (slower) implementation
40+
41+
The original version of the algorithm used a list, and was a bit clearer but much slower. It was based off the [original blog post](http://www.briangrinstead.com/blog/astar-search-algorithm-in-javascript). The code is available at: https://github.com/bgrins/javascript-astar/tree/0.0.1/original-implementation.
42+
43+
The newest version of the algorithm using a Binary Heap. It is quite faster than the original.
44+
http://www.briangrinstead.com/blog/astar-search-algorithm-in-javascript-updated
45+
Binary Heap taken from http://eloquentjavascript.net/appendix2.html (license: http://creativecommons.org/licenses/by/3.0/)
46+
47+
5148
## Running the test suite
5249

5350
If you don't have grunt installed, follow the [grunt getting started guide](http://gruntjs.com/getting-started) first.

astar.js

Lines changed: 183 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
// javascript-astar
1+
// javascript-astar 0.0.1
22
// http://github.com/bgrins/javascript-astar
33
// Freely distributable under the MIT License.
4-
// Implements the astar search algorithm in javascript using a binary heap.
5-
4+
// Implements the astar search algorithm in javascript using a Binary Heap.
5+
// Includes Binary Heap (with modifications) from Marijn Haverbeke.
6+
// http://eloquentjavascript.net/appendix2.html
67

78
(function(definition) {
89
if(typeof exports === 'object') {
910
module.exports = definition();
1011
} else if(typeof define === 'function' && define.amd) {
1112
define([], definition);
1213
} else {
13-
window.astar = definition();
14+
var exports = definition();
15+
window.astar = exports.astar;
16+
window.Graph = exports.Graph;
1417
}
1518
})(function() {
1619

@@ -162,6 +165,181 @@ var astar = {
162165
}
163166
};
164167

165-
return astar;
168+
function Graph(grid) {
169+
var nodes = [];
170+
171+
for (var x = 0; x < grid.length; x++) {
172+
nodes[x] = [];
173+
174+
for (var y = 0, row = grid[x]; y < row.length; y++) {
175+
nodes[x][y] = new GraphNode(x, y, row[y]);
176+
}
177+
}
178+
179+
this.input = grid;
180+
this.nodes = nodes;
181+
}
182+
183+
Graph.prototype.toString = function() {
184+
var graphString = "\n";
185+
var nodes = this.nodes;
186+
var rowDebug, row, y, l;
187+
for (var x = 0, len = nodes.length; x < len; x++) {
188+
rowDebug = "";
189+
row = nodes[x];
190+
for (y = 0, l = row.length; y < l; y++) {
191+
rowDebug += row[y].type + " ";
192+
}
193+
graphString = graphString + rowDebug + "\n";
194+
}
195+
return graphString;
196+
};
197+
198+
function GraphNode(x,y,type) {
199+
this.data = { };
200+
this.x = x;
201+
this.y = y;
202+
this.pos = {
203+
x: x,
204+
y: y
205+
};
206+
this.type = type;
207+
}
208+
209+
GraphNode.prototype.toString = function() {
210+
return "[" + this.x + " " + this.y + "]";
211+
};
212+
213+
GraphNode.prototype.isWall = function() {
214+
return this.type === 0;
215+
};
216+
217+
function BinaryHeap(scoreFunction){
218+
this.content = [];
219+
this.scoreFunction = scoreFunction;
220+
}
221+
222+
BinaryHeap.prototype = {
223+
push: function(element) {
224+
// Add the new element to the end of the array.
225+
this.content.push(element);
226+
227+
// Allow it to sink down.
228+
this.sinkDown(this.content.length - 1);
229+
},
230+
pop: function() {
231+
// Store the first element so we can return it later.
232+
var result = this.content[0];
233+
// Get the element at the end of the array.
234+
var end = this.content.pop();
235+
// If there are any elements left, put the end element at the
236+
// start, and let it bubble up.
237+
if (this.content.length > 0) {
238+
this.content[0] = end;
239+
this.bubbleUp(0);
240+
}
241+
return result;
242+
},
243+
remove: function(node) {
244+
var i = this.content.indexOf(node);
245+
246+
// When it is found, the process seen in 'pop' is repeated
247+
// to fill up the hole.
248+
var end = this.content.pop();
249+
250+
if (i !== this.content.length - 1) {
251+
this.content[i] = end;
252+
253+
if (this.scoreFunction(end) < this.scoreFunction(node)) {
254+
this.sinkDown(i);
255+
}
256+
else {
257+
this.bubbleUp(i);
258+
}
259+
}
260+
},
261+
size: function() {
262+
return this.content.length;
263+
},
264+
rescoreElement: function(node) {
265+
this.sinkDown(this.content.indexOf(node));
266+
},
267+
sinkDown: function(n) {
268+
// Fetch the element that has to be sunk.
269+
var element = this.content[n];
270+
271+
// When at 0, an element can not sink any further.
272+
while (n > 0) {
273+
274+
// Compute the parent element's index, and fetch it.
275+
var parentN = ((n + 1) >> 1) - 1,
276+
parent = this.content[parentN];
277+
// Swap the elements if the parent is greater.
278+
if (this.scoreFunction(element) < this.scoreFunction(parent)) {
279+
this.content[parentN] = element;
280+
this.content[n] = parent;
281+
// Update 'n' to continue at the new position.
282+
n = parentN;
283+
}
284+
285+
// Found a parent that is less, no need to sink any further.
286+
else {
287+
break;
288+
}
289+
}
290+
},
291+
bubbleUp: function(n) {
292+
// Look up the target element and its score.
293+
var length = this.content.length,
294+
element = this.content[n],
295+
elemScore = this.scoreFunction(element);
296+
297+
while(true) {
298+
// Compute the indices of the child elements.
299+
var child2N = (n + 1) << 1, child1N = child2N - 1;
300+
// This is used to store the new position of the element,
301+
// if any.
302+
var swap = null;
303+
var child1Score;
304+
// If the first child exists (is inside the array)...
305+
if (child1N < length) {
306+
// Look it up and compute its score.
307+
var child1 = this.content[child1N];
308+
child1Score = this.scoreFunction(child1);
309+
310+
// If the score is less than our element's, we need to swap.
311+
if (child1Score < elemScore){
312+
swap = child1N;
313+
}
314+
}
315+
316+
// Do the same checks for the other child.
317+
if (child2N < length) {
318+
var child2 = this.content[child2N],
319+
child2Score = this.scoreFunction(child2);
320+
if (child2Score < (swap === null ? elemScore : child1Score)) {
321+
swap = child2N;
322+
}
323+
}
324+
325+
// If the element needs to be moved, swap it, and continue.
326+
if (swap !== null) {
327+
this.content[n] = this.content[swap];
328+
this.content[swap] = element;
329+
n = swap;
330+
}
331+
332+
// Otherwise, we are done.
333+
else {
334+
break;
335+
}
336+
}
337+
}
338+
};
339+
340+
return {
341+
astar: astar,
342+
Graph: Graph
343+
};
166344

167345
});

benchmark/index.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
<link rel="stylesheet" type="text/css" href="../demo/demo.css" />
88
<script type='text/javascript' src='../demo/jquery-1.7.1.min.js'></script>
9-
<script type='text/javascript' src='../graph.js'></script>
109
<script type='text/javascript' src='../astar.js'></script>
1110
<script type='text/javascript' src='grid_150x150.js'></script>
1211
<script type='text/javascript' src='benchmark.js'></script>

demo/demo.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ window.log = function(){
1010
}
1111
};
1212

13+
var WALL = 0;
14+
var OPEN = 1;
1315

1416
var generateRandom = function (width, height, wallFrequency) {
1517

@@ -23,10 +25,10 @@ var generateRandom = function (width, height, wallFrequency) {
2325

2426
var isWall = Math.floor(Math.random()*(1/wallFrequency));
2527
if(isWall == 0) {
26-
nodeRow.push(Graph.GraphNodeType.WALL);
28+
nodeRow.push(WALL);
2729
}
2830
else {
29-
nodeRow.push(Graph.GraphNodeType.OPEN);
31+
nodeRow.push(OPEN);
3032
}
3133
}
3234
nodes.push(nodeRow);
@@ -127,7 +129,7 @@ GraphSearch.prototype.initialize = function() {
127129

128130
var isWall = Math.floor(Math.random()*(1/self.opts.wallFrequency));
129131
if(isWall == 0) {
130-
nodeRow.push(Graph.GraphNodeType.WALL);
132+
nodeRow.push(WALL);
131133
$cell.addClass(css.wall);
132134
}
133135
else {

demo/index.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ <h2>Demonstration</h2>
8484
<div id="footer"></div>
8585

8686
<script type='text/javascript' src='jquery-1.7.1.min.js'></script>
87-
<script type='text/javascript' src='../graph.js'></script>
8887
<script type='text/javascript' src='../astar.js'></script>
8988
<!--<script type='text/javascript' src='../dist/astar-concat.js'></script>-->
9089
<script type='text/javascript' src='demo.js'></script>

0 commit comments

Comments
 (0)