diff --git a/.gitignore b/.gitignore index ef5f69b3..977636cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.swp node_modules/ +lib/ diff --git a/Makefile b/Makefile index 45950ad3..2ba16351 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ TEST_TIMEOUT = 2000 TEST_REPORTER = spec lib/pathfinding-browser.js: $(SRC) + @mkdir -p lib @node utils/build.js test: diff --git a/lib/pathfinding-browser.js b/lib/pathfinding-browser.js deleted file mode 100644 index c6fc0386..00000000 --- a/lib/pathfinding-browser.js +++ /dev/null @@ -1,2055 +0,0 @@ -/** - * ____ _ _ _____ _ _ _ _ - * | _ \ __ _| |_| |__ | ___(_)_ __ __| (_)_ __ __ _ (_)___ - * | |_) / _` | __| '_ \| |_ | | '_ \ / _` | | '_ \ / _` | | / __| - * | __/ (_| | |_| | | | _| | | | | | (_| | | | | | (_| |_ | \__ \ - * |_| \__,_|\__|_| |_|_| |_|_| |_|\__,_|_|_| |_|\__, (_)/ |___/ - * |___/ |__/ - * https://github.com/qiao/PathFinding.js - */ -(function(e){if("function"==typeof bootstrap)bootstrap("pf",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makePF=e}else"undefined"!=typeof window?window.PF=e():global.PF=e()})(function(){var define,ses,bootstrap,module,exports; -return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s y) { - return 1; - } - return 0; - }; - - /* - Insert item x in list a, and keep it sorted assuming a is sorted. - - If x is already in a, insert it to the right of the rightmost x. - - Optional args lo (default 0) and hi (default a.length) bound the slice - of a to be searched. - */ - - - insort = function(a, x, lo, hi, cmp) { - var mid; - if (lo == null) { - lo = 0; - } - if (cmp == null) { - cmp = defaultCmp; - } - if (lo < 0) { - throw new Error('lo must be non-negative'); - } - if (hi == null) { - hi = a.length; - } - while (lo < hi) { - mid = floor((lo + hi) / 2); - if (cmp(x, a[mid]) < 0) { - hi = mid; - } else { - lo = mid + 1; - } - } - return ([].splice.apply(a, [lo, lo - lo].concat(x)), x); - }; - - /* - Push item onto heap, maintaining the heap invariant. - */ - - - heappush = function(array, item, cmp) { - if (cmp == null) { - cmp = defaultCmp; - } - array.push(item); - return _siftdown(array, 0, array.length - 1, cmp); - }; - - /* - Pop the smallest item off the heap, maintaining the heap invariant. - */ - - - heappop = function(array, cmp) { - var lastelt, returnitem; - if (cmp == null) { - cmp = defaultCmp; - } - lastelt = array.pop(); - if (array.length) { - returnitem = array[0]; - array[0] = lastelt; - _siftup(array, 0, cmp); - } else { - returnitem = lastelt; - } - return returnitem; - }; - - /* - Pop and return the current smallest value, and add the new item. - - This is more efficient than heappop() followed by heappush(), and can be - more appropriate when using a fixed size heap. Note that the value - returned may be larger than item! That constrains reasonable use of - this routine unless written as part of a conditional replacement: - if item > array[0] - item = heapreplace(array, item) - */ - - - heapreplace = function(array, item, cmp) { - var returnitem; - if (cmp == null) { - cmp = defaultCmp; - } - returnitem = array[0]; - array[0] = item; - _siftup(array, 0, cmp); - return returnitem; - }; - - /* - Fast version of a heappush followed by a heappop. - */ - - - heappushpop = function(array, item, cmp) { - var _ref; - if (cmp == null) { - cmp = defaultCmp; - } - if (array.length && cmp(array[0], item) < 0) { - _ref = [array[0], item], item = _ref[0], array[0] = _ref[1]; - _siftup(array, 0, cmp); - } - return item; - }; - - /* - Transform list into a heap, in-place, in O(array.length) time. - */ - - - heapify = function(array, cmp) { - var i, _i, _j, _len, _ref, _ref1, _results, _results1; - if (cmp == null) { - cmp = defaultCmp; - } - _ref1 = (function() { - _results1 = []; - for (var _j = 0, _ref = floor(array.length / 2); 0 <= _ref ? _j < _ref : _j > _ref; 0 <= _ref ? _j++ : _j--){ _results1.push(_j); } - return _results1; - }).apply(this).reverse(); - _results = []; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - i = _ref1[_i]; - _results.push(_siftup(array, i, cmp)); - } - return _results; - }; - - /* - Update the position of the given item in the heap. - This function should be called every time the item is being modified. - */ - - - updateItem = function(array, item, cmp) { - var pos; - if (cmp == null) { - cmp = defaultCmp; - } - pos = array.indexOf(item); - if (pos === -1) { - return; - } - _siftdown(array, 0, pos, cmp); - return _siftup(array, pos, cmp); - }; - - /* - Find the n largest elements in a dataset. - */ - - - nlargest = function(array, n, cmp) { - var elem, result, _i, _len, _ref; - if (cmp == null) { - cmp = defaultCmp; - } - result = array.slice(0, n); - if (!result.length) { - return result; - } - heapify(result, cmp); - _ref = array.slice(n); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - elem = _ref[_i]; - heappushpop(result, elem, cmp); - } - return result.sort(cmp).reverse(); - }; - - /* - Find the n smallest elements in a dataset. - */ - - - nsmallest = function(array, n, cmp) { - var elem, i, los, result, _i, _j, _len, _ref, _ref1, _results; - if (cmp == null) { - cmp = defaultCmp; - } - if (n * 10 <= array.length) { - result = array.slice(0, n).sort(cmp); - if (!result.length) { - return result; - } - los = result[result.length - 1]; - _ref = array.slice(n); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - elem = _ref[_i]; - if (cmp(elem, los) < 0) { - insort(result, elem, 0, null, cmp); - result.pop(); - los = result[result.length - 1]; - } - } - return result; - } - heapify(array, cmp); - _results = []; - for (i = _j = 0, _ref1 = min(n, array.length); 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) { - _results.push(heappop(array, cmp)); - } - return _results; - }; - - _siftdown = function(array, startpos, pos, cmp) { - var newitem, parent, parentpos; - if (cmp == null) { - cmp = defaultCmp; - } - newitem = array[pos]; - while (pos > startpos) { - parentpos = (pos - 1) >> 1; - parent = array[parentpos]; - if (cmp(newitem, parent) < 0) { - array[pos] = parent; - pos = parentpos; - continue; - } - break; - } - return array[pos] = newitem; - }; - - _siftup = function(array, pos, cmp) { - var childpos, endpos, newitem, rightpos, startpos; - if (cmp == null) { - cmp = defaultCmp; - } - endpos = array.length; - startpos = pos; - newitem = array[pos]; - childpos = 2 * pos + 1; - while (childpos < endpos) { - rightpos = childpos + 1; - if (rightpos < endpos && !(cmp(array[childpos], array[rightpos]) < 0)) { - childpos = rightpos; - } - array[pos] = array[childpos]; - pos = childpos; - childpos = 2 * pos + 1; - } - array[pos] = newitem; - return _siftdown(array, startpos, pos, cmp); - }; - - Heap = (function() { - Heap.push = heappush; - - Heap.pop = heappop; - - Heap.replace = heapreplace; - - Heap.pushpop = heappushpop; - - Heap.heapify = heapify; - - Heap.nlargest = nlargest; - - Heap.nsmallest = nsmallest; - - function Heap(cmp) { - this.cmp = cmp != null ? cmp : defaultCmp; - this.nodes = []; - } - - Heap.prototype.push = function(x) { - return heappush(this.nodes, x, this.cmp); - }; - - Heap.prototype.pop = function() { - return heappop(this.nodes, this.cmp); - }; - - Heap.prototype.peek = function() { - return this.nodes[0]; - }; - - Heap.prototype.contains = function(x) { - return this.nodes.indexOf(x) !== -1; - }; - - Heap.prototype.replace = function(x) { - return heapreplace(this.nodes, x, this.cmp); - }; - - Heap.prototype.pushpop = function(x) { - return heappushpop(this.nodes, x, this.cmp); - }; - - Heap.prototype.heapify = function() { - return heapify(this.nodes, this.cmp); - }; - - Heap.prototype.updateItem = function(x) { - return updateItem(this.nodes, x, this.cmp); - }; - - Heap.prototype.clear = function() { - return this.nodes = []; - }; - - Heap.prototype.empty = function() { - return this.nodes.length === 0; - }; - - Heap.prototype.size = function() { - return this.nodes.length; - }; - - Heap.prototype.clone = function() { - var heap; - heap = new Heap(); - heap.nodes = this.nodes.slice(0); - return heap; - }; - - Heap.prototype.toArray = function() { - return this.nodes.slice(0); - }; - - Heap.prototype.insert = Heap.prototype.push; - - Heap.prototype.remove = Heap.prototype.pop; - - Heap.prototype.top = Heap.prototype.peek; - - Heap.prototype.front = Heap.prototype.peek; - - Heap.prototype.has = Heap.prototype.contains; - - Heap.prototype.copy = Heap.prototype.clone; - - return Heap; - - })(); - - if (typeof module !== "undefined" && module !== null ? module.exports : void 0) { - module.exports = Heap; - } else { - window.Heap = Heap; - } - -}).call(this); - -},{}],3:[function(require,module,exports){ -module.exports = { - 'Heap' : require('heap'), - 'Node' : require('./core/Node'), - 'Grid' : require('./core/Grid'), - 'Util' : require('./core/Util'), - 'Heuristic' : require('./core/Heuristic'), - 'AStarFinder' : require('./finders/AStarFinder'), - 'BestFirstFinder' : require('./finders/BestFirstFinder'), - 'BreadthFirstFinder' : require('./finders/BreadthFirstFinder'), - 'DijkstraFinder' : require('./finders/DijkstraFinder'), - 'BiAStarFinder' : require('./finders/BiAStarFinder'), - 'BiBestFirstFinder' : require('./finders/BiBestFirstFinder'), - 'BiBreadthFirstFinder' : require('./finders/BiBreadthFirstFinder'), - 'BiDijkstraFinder' : require('./finders/BiDijkstraFinder'), - 'JumpPointFinder' : require('./finders/JumpPointFinder'), - 'IDAStarFinder' : require('./finders/IDAStarFinder'), - 'OrthogonalJumpPointFinder' : require('./finders/OrthogonalJumpPointFinder') -}; - -},{"./core/Grid":4,"./core/Heuristic":5,"./core/Node":6,"./core/Util":7,"./finders/AStarFinder":8,"./finders/BestFirstFinder":9,"./finders/BiAStarFinder":10,"./finders/BiBestFirstFinder":11,"./finders/BiBreadthFirstFinder":12,"./finders/BiDijkstraFinder":13,"./finders/BreadthFirstFinder":14,"./finders/DijkstraFinder":15,"./finders/IDAStarFinder":16,"./finders/JumpPointFinder":17,"./finders/OrthogonalJumpPointFinder":18,"heap":1}],4:[function(require,module,exports){ -var Node = require('./Node'); - -/** - * The Grid class, which serves as the encapsulation of the layout of the nodes. - * @constructor - * @param {number} width Number of columns of the grid. - * @param {number} height Number of rows of the grid. - * @param {Array.>} [matrix] - A 0-1 matrix - * representing the walkable status of the nodes(0 or false for walkable). - * If the matrix is not supplied, all the nodes will be walkable. */ -function Grid(width, height, matrix) { - /** - * The number of columns of the grid. - * @type number - */ - this.width = width; - /** - * The number of rows of the grid. - * @type number - */ - this.height = height; - - /** - * A 2D array of nodes. - */ - this.nodes = this._buildNodes(width, height, matrix); -} - -/** - * Build and return the nodes. - * @private - * @param {number} width - * @param {number} height - * @param {Array.>} [matrix] - A 0-1 matrix representing - * the walkable status of the nodes. - * @see Grid - */ -Grid.prototype._buildNodes = function(width, height, matrix) { - var i, j, - nodes = new Array(height), - row; - - for (i = 0; i < height; ++i) { - nodes[i] = new Array(width); - for (j = 0; j < width; ++j) { - nodes[i][j] = new Node(j, i); - } - } - - - if (matrix === undefined) { - return nodes; - } - - if (matrix.length !== height || matrix[0].length !== width) { - throw new Error('Matrix size does not fit'); - } - - for (i = 0; i < height; ++i) { - for (j = 0; j < width; ++j) { - if (matrix[i][j]) { - // 0, false, null will be walkable - // while others will be un-walkable - nodes[i][j].walkable = false; - } - } - } - - return nodes; -}; - - -Grid.prototype.getNodeAt = function(x, y) { - return this.nodes[y][x]; -}; - - -/** - * Determine whether the node at the given position is walkable. - * (Also returns false if the position is outside the grid.) - * @param {number} x - The x coordinate of the node. - * @param {number} y - The y coordinate of the node. - * @return {boolean} - The walkability of the node. - */ -Grid.prototype.isWalkableAt = function(x, y) { - return this.isInside(x, y) && this.nodes[y][x].walkable; -}; - - -/** - * Determine whether the position is inside the grid. - * XXX: `grid.isInside(x, y)` is wierd to read. - * It should be `(x, y) is inside grid`, but I failed to find a better - * name for this method. - * @param {number} x - * @param {number} y - * @return {boolean} - */ -Grid.prototype.isInside = function(x, y) { - return (x >= 0 && x < this.width) && (y >= 0 && y < this.height); -}; - - -/** - * Set whether the node on the given position is walkable. - * NOTE: throws exception if the coordinate is not inside the grid. - * @param {number} x - The x coordinate of the node. - * @param {number} y - The y coordinate of the node. - * @param {boolean} walkable - Whether the position is walkable. - */ -Grid.prototype.setWalkableAt = function(x, y, walkable) { - this.nodes[y][x].walkable = walkable; -}; - - -/** - * Get the neighbors of the given node. - * - * offsets diagonalOffsets: - * +---+---+---+ +---+---+---+ - * | | 0 | | | 0 | | 1 | - * +---+---+---+ +---+---+---+ - * | 3 | | 1 | | | | | - * +---+---+---+ +---+---+---+ - * | | 2 | | | 3 | | 2 | - * +---+---+---+ +---+---+---+ - * - * When allowDiagonal is true, if offsets[i] is valid, then - * diagonalOffsets[i] and - * diagonalOffsets[(i + 1) % 4] is valid. - * @param {Node} node - * @param {boolean} allowDiagonal - * @param {boolean} dontCrossCorners - */ -Grid.prototype.getNeighbors = function(node, allowDiagonal, dontCrossCorners) { - var x = node.x, - y = node.y, - neighbors = [], - s0 = false, d0 = false, - s1 = false, d1 = false, - s2 = false, d2 = false, - s3 = false, d3 = false, - nodes = this.nodes; - - // ↑ - if (this.isWalkableAt(x, y - 1)) { - neighbors.push(nodes[y - 1][x]); - s0 = true; - } - // → - if (this.isWalkableAt(x + 1, y)) { - neighbors.push(nodes[y][x + 1]); - s1 = true; - } - // ↓ - if (this.isWalkableAt(x, y + 1)) { - neighbors.push(nodes[y + 1][x]); - s2 = true; - } - // ← - if (this.isWalkableAt(x - 1, y)) { - neighbors.push(nodes[y][x - 1]); - s3 = true; - } - - if (!allowDiagonal) { - return neighbors; - } - - if (dontCrossCorners) { - d0 = s3 && s0; - d1 = s0 && s1; - d2 = s1 && s2; - d3 = s2 && s3; - } else { - d0 = s3 || s0; - d1 = s0 || s1; - d2 = s1 || s2; - d3 = s2 || s3; - } - - // ↖ - if (d0 && this.isWalkableAt(x - 1, y - 1)) { - neighbors.push(nodes[y - 1][x - 1]); - } - // ↗ - if (d1 && this.isWalkableAt(x + 1, y - 1)) { - neighbors.push(nodes[y - 1][x + 1]); - } - // ↘ - if (d2 && this.isWalkableAt(x + 1, y + 1)) { - neighbors.push(nodes[y + 1][x + 1]); - } - // ↙ - if (d3 && this.isWalkableAt(x - 1, y + 1)) { - neighbors.push(nodes[y + 1][x - 1]); - } - - return neighbors; -}; - - -/** - * Get a clone of this grid. - * @return {Grid} Cloned grid. - */ -Grid.prototype.clone = function() { - var i, j, - - width = this.width, - height = this.height, - thisNodes = this.nodes, - - newGrid = new Grid(width, height), - newNodes = new Array(height), - row; - - for (i = 0; i < height; ++i) { - newNodes[i] = new Array(width); - for (j = 0; j < width; ++j) { - newNodes[i][j] = new Node(j, i, thisNodes[i][j].walkable); - } - } - - newGrid.nodes = newNodes; - - return newGrid; -}; - -module.exports = Grid; - -},{"./Node":6}],5:[function(require,module,exports){ -/** - * @namespace PF.Heuristic - * @description A collection of heuristic functions. - */ -module.exports = { - - /** - * Manhattan distance. - * @param {number} dx - Difference in x. - * @param {number} dy - Difference in y. - * @return {number} dx + dy - */ - manhattan: function(dx, dy) { - return dx + dy; - }, - - /** - * Euclidean distance. - * @param {number} dx - Difference in x. - * @param {number} dy - Difference in y. - * @return {number} sqrt(dx * dx + dy * dy) - */ - euclidean: function(dx, dy) { - return Math.sqrt(dx * dx + dy * dy); - }, - - /** - * Chebyshev distance. - * @param {number} dx - Difference in x. - * @param {number} dy - Difference in y. - * @return {number} max(dx, dy) - */ - chebyshev: function(dx, dy) { - return Math.max(dx, dy); - } - -}; - -},{}],6:[function(require,module,exports){ -/** - * A node in grid. - * This class holds some basic information about a node and custom - * attributes may be added, depending on the algorithms' needs. - * @constructor - * @param {number} x - The x coordinate of the node on the grid. - * @param {number} y - The y coordinate of the node on the grid. - * @param {boolean} [walkable] - Whether this node is walkable. - */ -function Node(x, y, walkable) { - /** - * The x coordinate of the node on the grid. - * @type number - */ - this.x = x; - /** - * The y coordinate of the node on the grid. - * @type number - */ - this.y = y; - /** - * Whether this node can be walked through. - * @type boolean - */ - this.walkable = (walkable === undefined ? true : walkable); -}; - -module.exports = Node; - -},{}],7:[function(require,module,exports){ -/** - * Backtrace according to the parent records and return the path. - * (including both start and end nodes) - * @param {Node} node End node - * @return {Array.>} the path - */ -function backtrace(node) { - var path = [[node.x, node.y]]; - while (node.parent) { - node = node.parent; - path.push([node.x, node.y]); - } - return path.reverse(); -} -exports.backtrace = backtrace; - -/** - * Backtrace from start and end node, and return the path. - * (including both start and end nodes) - * @param {Node} - * @param {Node} - */ -function biBacktrace(nodeA, nodeB) { - var pathA = backtrace(nodeA), - pathB = backtrace(nodeB); - return pathA.concat(pathB.reverse()); -} -exports.biBacktrace = biBacktrace; - -/** - * Compute the length of the path. - * @param {Array.>} path The path - * @return {number} The length of the path - */ -function pathLength(path) { - var i, sum = 0, a, b, dx, dy; - for (i = 1; i < path.length; ++i) { - a = path[i - 1]; - b = path[i]; - dx = a[0] - b[0]; - dy = a[1] - b[1]; - sum += Math.sqrt(dx * dx + dy * dy); - } - return sum; -} -exports.pathLength = pathLength; - - -/** - * Given the start and end coordinates, return all the coordinates lying - * on the line formed by these coordinates, based on Bresenham's algorithm. - * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm#Simplification - * @param {number} x0 Start x coordinate - * @param {number} y0 Start y coordinate - * @param {number} x1 End x coordinate - * @param {number} y1 End y coordinate - * @return {Array.>} The coordinates on the line - */ -function interpolate(x0, y0, x1, y1) { - var abs = Math.abs, - line = [], - sx, sy, dx, dy, err, e2; - - dx = abs(x1 - x0); - dy = abs(y1 - y0); - - sx = (x0 < x1) ? 1 : -1; - sy = (y0 < y1) ? 1 : -1; - - err = dx - dy; - - while (true) { - line.push([x0, y0]); - - if (x0 === x1 && y0 === y1) { - break; - } - - e2 = 2 * err; - if (e2 > -dy) { - err = err - dy; - x0 = x0 + sx; - } - if (e2 < dx) { - err = err + dx; - y0 = y0 + sy; - } - } - - return line; -} -exports.interpolate = interpolate; - - -/** - * Given a compressed path, return a new path that has all the segments - * in it interpolated. - * @param {Array.>} path The path - * @return {Array.>} expanded path - */ -function expandPath(path) { - var expanded = [], - len = path.length, - coord0, coord1, - interpolated, - interpolatedLen, - i, j; - - if (len < 2) { - return expanded; - } - - for (i = 0; i < len - 1; ++i) { - coord0 = path[i]; - coord1 = path[i + 1]; - - interpolated = interpolate(coord0[0], coord0[1], coord1[0], coord1[1]); - interpolatedLen = interpolated.length; - for (j = 0; j < interpolatedLen - 1; ++j) { - expanded.push(interpolated[j]); - } - } - expanded.push(path[len - 1]); - - return expanded; -} -exports.expandPath = expandPath; - - -/** - * Smoothen the give path. - * The original path will not be modified; a new path will be returned. - * @param {PF.Grid} grid - * @param {Array.>} path The path - */ -function smoothenPath(grid, path) { - var len = path.length, - x0 = path[0][0], // path start x - y0 = path[0][1], // path start y - x1 = path[len - 1][0], // path end x - y1 = path[len - 1][1], // path end y - sx, sy, // current start coordinate - ex, ey, // current end coordinate - lx, ly, // last valid end coordinate - newPath, - i, j, coord, line, testCoord, blocked; - - sx = x0; - sy = y0; - lx = path[1][0]; - ly = path[1][1]; - newPath = [[sx, sy]]; - - for (i = 2; i < len; ++i) { - coord = path[i]; - ex = coord[0]; - ey = coord[1]; - line = interpolate(sx, sy, ex, ey); - - blocked = false; - for (j = 1; j < line.length; ++j) { - testCoord = line[j]; - - if (!grid.isWalkableAt(testCoord[0], testCoord[1])) { - blocked = true; - newPath.push([lx, ly]); - sx = lx; - sy = ly; - break; - } - } - if (!blocked) { - lx = ex; - ly = ey; - } - } - newPath.push([x1, y1]); - - return newPath; -} -exports.smoothenPath = smoothenPath; - - -/** - * Compress a path, remove redundant nodes without altering the shape - * The original path is not modified - * @param {Array.>} path The path - * @return {Array.>} The compressed path - */ -function compressPath(path) { - - // nothing to compress - if(path.length < 3) { - return path; - } - - var compressed = [], - sx = path[0][0], // start x - sy = path[0][1], // start y - px = path[1][0], // second point x - py = path[1][1], // second point y - dx = px - sx, // direction between the two points - dy = py - sy, // direction between the two points - lx, ly, - ldx, ldy, - sq, i; - - // normalize the direction - sq = Math.sqrt(dx*dx + dy*dy); - dx /= sq; - dy /= sq; - - // start the new path - compressed.push([sx,sy]); - - for(i = 2; i < path.length; i++) { - - // store the last point - lx = px; - ly = py; - - // store the last direction - ldx = dx; - ldy = dy; - - // next point - px = path[i][0]; - py = path[i][1]; - - // next direction - dx = px - lx; - dy = py - ly; - - // normalize - sq = Math.sqrt(dx*dx + dy*dy); - dx /= sq; - dy /= sq; - - // if the direction has changed, store the point - if ( dx !== ldx || dy !== ldy ) { - compressed.push([lx,ly]); - } - } - - // store the last point - compressed.push([px,py]); - - return compressed; -} -exports.compressPath = compressPath; - -},{}],8:[function(require,module,exports){ -var Heap = require('heap'); -var Util = require('../core/Util'); -var Heuristic = require('../core/Heuristic'); - -/** - * A* path-finder. - * based upon https://github.com/bgrins/javascript-astar - * @constructor - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - * @param {function} opt.heuristic Heuristic function to estimate the distance - * (defaults to manhattan). - * @param {integer} opt.weight Weight to apply to the heuristic to allow for suboptimal paths, - * in order to speed up the search. - */ -function AStarFinder(opt) { - opt = opt || {}; - this.allowDiagonal = opt.allowDiagonal; - this.dontCrossCorners = opt.dontCrossCorners; - this.heuristic = opt.heuristic || Heuristic.manhattan; - this.weight = opt.weight || 1; -} - -/** - * Find and return the the path. - * @return {Array.<[number, number]>} The path, including both start and - * end positions. - */ -AStarFinder.prototype.findPath = function(startX, startY, endX, endY, grid) { - var openList = new Heap(function(nodeA, nodeB) { - return nodeA.f - nodeB.f; - }), - startNode = grid.getNodeAt(startX, startY), - endNode = grid.getNodeAt(endX, endY), - heuristic = this.heuristic, - allowDiagonal = this.allowDiagonal, - dontCrossCorners = this.dontCrossCorners, - weight = this.weight, - abs = Math.abs, SQRT2 = Math.SQRT2, - node, neighbors, neighbor, i, l, x, y, ng; - - // set the `g` and `f` value of the start node to be 0 - startNode.g = 0; - startNode.f = 0; - - // push the start node into the open list - openList.push(startNode); - startNode.opened = true; - - // while the open list is not empty - while (!openList.empty()) { - // pop the position of node which has the minimum `f` value. - node = openList.pop(); - node.closed = true; - - // if reached the end position, construct the path and return it - if (node === endNode) { - return Util.backtrace(endNode); - } - - // get neigbours of the current node - neighbors = grid.getNeighbors(node, allowDiagonal, dontCrossCorners); - for (i = 0, l = neighbors.length; i < l; ++i) { - neighbor = neighbors[i]; - - if (neighbor.closed) { - continue; - } - - x = neighbor.x; - y = neighbor.y; - - // get the distance between current node and the neighbor - // and calculate the next g score - ng = node.g + ((x - node.x === 0 || y - node.y === 0) ? 1 : SQRT2); - - // check if the neighbor has not been inspected yet, or - // can be reached with smaller cost from the current node - if (!neighbor.opened || ng < neighbor.g) { - neighbor.g = ng; - neighbor.h = neighbor.h || weight * heuristic(abs(x - endX), abs(y - endY)); - neighbor.f = neighbor.g + neighbor.h; - neighbor.parent = node; - - if (!neighbor.opened) { - openList.push(neighbor); - neighbor.opened = true; - } else { - // the neighbor can be reached with smaller cost. - // Since its f value has been updated, we have to - // update its position in the open list - openList.updateItem(neighbor); - } - } - } // end for each neighbor - } // end while not open list empty - - // fail to find the path - return []; -}; - -module.exports = AStarFinder; - -},{"../core/Heuristic":5,"../core/Util":7,"heap":1}],9:[function(require,module,exports){ -var AStarFinder = require('./AStarFinder'); - -/** - * Best-First-Search path-finder. - * @constructor - * @extends AStarFinder - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - * @param {function} opt.heuristic Heuristic function to estimate the distance - * (defaults to manhattan). - */ -function BestFirstFinder(opt) { - AStarFinder.call(this, opt); - - var orig = this.heuristic; - this.heuristic = function(dx, dy) { - return orig(dx, dy) * 1000000; - }; -}; - -BestFirstFinder.prototype = new AStarFinder(); -BestFirstFinder.prototype.constructor = BestFirstFinder; - -module.exports = BestFirstFinder; - -},{"./AStarFinder":8}],10:[function(require,module,exports){ -var Heap = require('heap'); -var Util = require('../core/Util'); -var Heuristic = require('../core/Heuristic'); - -/** - * A* path-finder. - * based upon https://github.com/bgrins/javascript-astar - * @constructor - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - * @param {function} opt.heuristic Heuristic function to estimate the distance - * (defaults to manhattan). - * @param {integer} opt.weight Weight to apply to the heuristic to allow for suboptimal paths, - * in order to speed up the search. - */ -function BiAStarFinder(opt) { - opt = opt || {}; - this.allowDiagonal = opt.allowDiagonal; - this.dontCrossCorners = opt.dontCrossCorners; - this.heuristic = opt.heuristic || Heuristic.manhattan; - this.weight = opt.weight || 1; -} - -/** - * Find and return the the path. - * @return {Array.<[number, number]>} The path, including both start and - * end positions. - */ -BiAStarFinder.prototype.findPath = function(startX, startY, endX, endY, grid) { - var cmp = function(nodeA, nodeB) { - return nodeA.f - nodeB.f; - }, - startOpenList = new Heap(cmp), - endOpenList = new Heap(cmp), - startNode = grid.getNodeAt(startX, startY), - endNode = grid.getNodeAt(endX, endY), - heuristic = this.heuristic, - allowDiagonal = this.allowDiagonal, - dontCrossCorners = this.dontCrossCorners, - weight = this.weight, - abs = Math.abs, SQRT2 = Math.SQRT2, - node, neighbors, neighbor, i, l, x, y, ng, - BY_START = 1, BY_END = 2; - - // set the `g` and `f` value of the start node to be 0 - // and push it into the start open list - startNode.g = 0; - startNode.f = 0; - startOpenList.push(startNode); - startNode.opened = BY_START; - - // set the `g` and `f` value of the end node to be 0 - // and push it into the open open list - endNode.g = 0; - endNode.f = 0; - endOpenList.push(endNode); - endNode.opened = BY_END; - - // while both the open lists are not empty - while (!startOpenList.empty() && !endOpenList.empty()) { - - // pop the position of start node which has the minimum `f` value. - node = startOpenList.pop(); - node.closed = true; - - // get neigbours of the current node - neighbors = grid.getNeighbors(node, allowDiagonal, dontCrossCorners); - for (i = 0, l = neighbors.length; i < l; ++i) { - neighbor = neighbors[i]; - - if (neighbor.closed) { - continue; - } - if (neighbor.opened === BY_END) { - return Util.biBacktrace(node, neighbor); - } - - x = neighbor.x; - y = neighbor.y; - - // get the distance between current node and the neighbor - // and calculate the next g score - ng = node.g + ((x - node.x === 0 || y - node.y === 0) ? 1 : SQRT2); - - // check if the neighbor has not been inspected yet, or - // can be reached with smaller cost from the current node - if (!neighbor.opened || ng < neighbor.g) { - neighbor.g = ng; - neighbor.h = neighbor.h || weight * heuristic(abs(x - endX), abs(y - endY)); - neighbor.f = neighbor.g + neighbor.h; - neighbor.parent = node; - - if (!neighbor.opened) { - startOpenList.push(neighbor); - neighbor.opened = BY_START; - } else { - // the neighbor can be reached with smaller cost. - // Since its f value has been updated, we have to - // update its position in the open list - startOpenList.updateItem(neighbor); - } - } - } // end for each neighbor - - - // pop the position of end node which has the minimum `f` value. - node = endOpenList.pop(); - node.closed = true; - - // get neigbours of the current node - neighbors = grid.getNeighbors(node, allowDiagonal, dontCrossCorners); - for (i = 0, l = neighbors.length; i < l; ++i) { - neighbor = neighbors[i]; - - if (neighbor.closed) { - continue; - } - if (neighbor.opened === BY_START) { - return Util.biBacktrace(neighbor, node); - } - - x = neighbor.x; - y = neighbor.y; - - // get the distance between current node and the neighbor - // and calculate the next g score - ng = node.g + ((x - node.x === 0 || y - node.y === 0) ? 1 : SQRT2); - - // check if the neighbor has not been inspected yet, or - // can be reached with smaller cost from the current node - if (!neighbor.opened || ng < neighbor.g) { - neighbor.g = ng; - neighbor.h = neighbor.h || weight * heuristic(abs(x - startX), abs(y - startY)); - neighbor.f = neighbor.g + neighbor.h; - neighbor.parent = node; - - if (!neighbor.opened) { - endOpenList.push(neighbor); - neighbor.opened = BY_END; - } else { - // the neighbor can be reached with smaller cost. - // Since its f value has been updated, we have to - // update its position in the open list - endOpenList.updateItem(neighbor); - } - } - } // end for each neighbor - } // end while not open list empty - - // fail to find the path - return []; -}; - -module.exports = BiAStarFinder; - -},{"../core/Heuristic":5,"../core/Util":7,"heap":1}],11:[function(require,module,exports){ -var BiAStarFinder = require('./BiAStarFinder'); - -/** - * Bi-direcitional Best-First-Search path-finder. - * @constructor - * @extends BiAStarFinder - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - * @param {function} opt.heuristic Heuristic function to estimate the distance - * (defaults to manhattan). - */ -function BiBestFirstFinder(opt) { - BiAStarFinder.call(this, opt); - - var orig = this.heuristic; - this.heuristic = function(dx, dy) { - return orig(dx, dy) * 1000000; - }; -} - -BiBestFirstFinder.prototype = new BiAStarFinder(); -BiBestFirstFinder.prototype.constructor = BiBestFirstFinder; - -module.exports = BiBestFirstFinder; - -},{"./BiAStarFinder":10}],12:[function(require,module,exports){ -var Util = require('../core/Util'); - -/** - * Bi-directional Breadth-First-Search path finder. - * @constructor - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - */ -function BiBreadthFirstFinder(opt) { - opt = opt || {}; - this.allowDiagonal = opt.allowDiagonal; - this.dontCrossCorners = opt.dontCrossCorners; -} - - -/** - * Find and return the the path. - * @return {Array.<[number, 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, - allowDiagonal = this.allowDiagonal, - dontCrossCorners = this.dontCrossCorners, - BY_START = 0, BY_END = 1, - i, l; - - // push the start and end nodes into the queues - startOpenList.push(startNode); - startNode.opened = true; - startNode.by = BY_START; - - endOpenList.push(endNode); - endNode.opened = true; - endNode.by = BY_END; - - // while both the queues are not empty - while (startOpenList.length && endOpenList.length) { - - // expand start open list - - node = startOpenList.shift(); - node.closed = true; - - neighbors = grid.getNeighbors(node, allowDiagonal, dontCrossCorners); - 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); - } - continue; - } - startOpenList.push(neighbor); - neighbor.parent = node; - neighbor.opened = true; - neighbor.by = BY_START; - } - - // expand end open list - - node = endOpenList.shift(); - node.closed = true; - - neighbors = grid.getNeighbors(node, allowDiagonal, dontCrossCorners); - 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); - } - continue; - } - endOpenList.push(neighbor); - neighbor.parent = node; - neighbor.opened = true; - neighbor.by = BY_END; - } - } - - // fail to find the path - return []; -}; - -module.exports = BiBreadthFirstFinder; - -},{"../core/Util":7}],13:[function(require,module,exports){ -var BiAStarFinder = require('./BiAStarFinder'); - -/** - * Bi-directional Dijkstra path-finder. - * @constructor - * @extends BiAStarFinder - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - */ -function BiDijkstraFinder(opt) { - BiAStarFinder.call(this, opt); - this.heuristic = function(dx, dy) { - return 0; - }; -} - -BiDijkstraFinder.prototype = new BiAStarFinder(); -BiDijkstraFinder.prototype.constructor = BiDijkstraFinder; - -module.exports = BiDijkstraFinder; - -},{"./BiAStarFinder":10}],14:[function(require,module,exports){ -var Util = require('../core/Util'); - -/** - * Breadth-First-Search path finder. - * @constructor - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - */ -function BreadthFirstFinder(opt) { - opt = opt || {}; - this.allowDiagonal = opt.allowDiagonal; - this.dontCrossCorners = opt.dontCrossCorners; -} - -/** - * Find and return the the path. - * @return {Array.<[number, number]>} The path, including both start and - * end positions. - */ -BreadthFirstFinder.prototype.findPath = function(startX, startY, endX, endY, grid) { - var openList = [], - allowDiagonal = this.allowDiagonal, - dontCrossCorners = this.dontCrossCorners, - startNode = grid.getNodeAt(startX, startY), - endNode = grid.getNodeAt(endX, endY), - neighbors, neighbor, node, i, l; - - // push the start pos into the queue - openList.push(startNode); - startNode.opened = true; - - // while the queue is not empty - while (openList.length) { - // take the front node from the queue - node = openList.shift(); - node.closed = true; - - // reached the end position - if (node === endNode) { - return Util.backtrace(endNode); - } - - neighbors = grid.getNeighbors(node, allowDiagonal, dontCrossCorners); - for (i = 0, l = neighbors.length; i < l; ++i) { - neighbor = neighbors[i]; - - // skip this neighbor if it has been inspected before - if (neighbor.closed || neighbor.opened) { - continue; - } - - openList.push(neighbor); - neighbor.opened = true; - neighbor.parent = node; - } - } - - // fail to find the path - return []; -}; - -module.exports = BreadthFirstFinder; - -},{"../core/Util":7}],15:[function(require,module,exports){ -var AStarFinder = require('./AStarFinder'); - -/** - * Dijkstra path-finder. - * @constructor - * @extends AStarFinder - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - */ -function DijkstraFinder(opt) { - AStarFinder.call(this, opt); - this.heuristic = function(dx, dy) { - return 0; - }; -} - -DijkstraFinder.prototype = new AStarFinder(); -DijkstraFinder.prototype.constructor = DijkstraFinder; - -module.exports = DijkstraFinder; - -},{"./AStarFinder":8}],16:[function(require,module,exports){ -var Util = require('../core/Util'); -var Heuristic = require('../core/Heuristic'); -var Node = require('../core/Node'); - -/** - * Iterative Deeping A Star (IDA*) path-finder. - * - * Recursion based on: - * http://www.apl.jhu.edu/~hall/AI-Programming/IDA-Star.html - * - * Path retracing based on: - * V. Nageshwara Rao, Vipin Kumar and K. Ramesh - * "A Parallel Implementation of Iterative-Deeping-A*", January 1987. - * ftp://ftp.cs.utexas.edu/.snapshot/hourly.1/pub/AI-Lab/tech-reports/UT-AI-TR-87-46.pdf - * - * @author Gerard Meier (www.gerardmeier.com) - * - * @constructor - * @param {object} opt - * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed. - * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners. - * @param {function} opt.heuristic Heuristic function to estimate the distance - * (defaults to manhattan). - * @param {integer} opt.weight Weight to apply to the heuristic to allow for suboptimal paths, - * in order to speed up the search. - * @param {object} opt.trackRecursion Whether to track recursion for statistical purposes. - * @param {object} opt.timeLimit Maximum execution time. Use <= 0 for infinite. - */ - -function IDAStarFinder(opt) { - opt = opt || {}; - this.allowDiagonal = opt.allowDiagonal; - this.dontCrossCorners = opt.dontCrossCorners; - this.heuristic = opt.heuristic || Heuristic.manhattan; - this.weight = opt.weight || 1; - this.trackRecursion = opt.trackRecursion || false; - this.timeLimit = opt.timeLimit || Infinity; // Default: no time limit. -} - -/** - * Find and return the the path. When an empty array is returned, either - * no path is possible, or the maximum execution time is reached. - * - * @return {Array.<[number, number]>} The path, including both start and - * end positions. - */ -IDAStarFinder.prototype.findPath = function(startX, startY, endX, endY, grid) { - // Used for statistics: - var nodesVisited = 0; - - // Execution time limitation: - var startTime = new Date().getTime(); - - // Heuristic helper: - var h = function(a, b) { - return this.heuristic(Math.abs(b.x - a.x), Math.abs(b.y - a.y)); - }.bind(this); - - // Step cost from a to b: - var cost = function(a, b) { - return (a.x === b.x || a.y === b.y) ? 1 : Math.SQRT2; - }; - - /** - * IDA* search implementation. - * - * @param {Node} The node currently expanding from. - * @param {number} Cost to reach the given node. - * @param {number} Maximum search depth (cut-off value). - * @param {{Array.<[number, number]>}} The found route. - * @param {number} Recursion depth. - * - * @return {Object} either a number with the new optimal cut-off depth, - * or a valid node instance, in which case a path was found. - */ - var search = function(node, g, cutoff, route, depth) { - nodesVisited++; - - // Enforce timelimit: - if(this.timeLimit > 0 && new Date().getTime() - startTime > this.timeLimit * 1000) { - // Enforced as "path-not-found". - return Infinity; - } - - var f = g + h(node, end) * this.weight; - - // We've searched too deep for this iteration. - if(f > cutoff) { - return f; - } - - if(node == end) { - route[depth] = [node.x, node.y]; - return node; - } - - var min, t, k, neighbour; - - var neighbours = grid.getNeighbors(node, this.allowDiagonal, this.dontCrossCorners); - - // Sort the neighbours, gives nicer paths. But, this deviates - // from the original algorithm - so I left it out. - //neighbours.sort(function(a, b){ - // return h(a, end) - h(b, end); - //}); - - for(k = 0, min = Infinity; neighbour = neighbours[k]; ++k) { - - if(this.trackRecursion) { - // Retain a copy for visualisation. Due to recursion, this - // node may be part of other paths too. - neighbour.retainCount = neighbour.retainCount + 1 || 1; - - if(neighbour.tested !== true) { - neighbour.tested = true; - } - } - - t = search(neighbour, g + cost(node, neighbour), cutoff, route, depth + 1); - - if(t instanceof Node) { - route[depth] = [node.x, node.y]; - - // For a typical A* linked list, this would work: - // neighbour.parent = node; - return t; - } - - // Decrement count, then determine whether it's actually closed. - if(this.trackRecursion && (--neighbour.retainCount) === 0) { - neighbour.tested = false; - } - - if(t < min) { - min = t; - } - } - - return min; - - }.bind(this); - - // Node instance lookups: - var start = grid.getNodeAt(startX, startY); - var end = grid.getNodeAt(endX, endY); - - // Initial search depth, given the typical heuristic contraints, - // there should be no cheaper route possible. - var cutOff = h(start, end); - - var j, route, t; - - // With an overflow protection. - for(j = 0; true; ++j) { - //console.log("Iteration: " + j + ", search cut-off value: " + cutOff + ", nodes visited thus far: " + nodesVisited + "."); - - route = []; - - // Search till cut-off depth: - t = search(start, 0, cutOff, route, 0); - - // Route not possible, or not found in time limit. - if(t === Infinity) { - return []; - } - - // If t is a node, it's also the end node. Route is now - // populated with a valid path to the end node. - if(t instanceof Node) { - //console.log("Finished at iteration: " + j + ", search cut-off value: " + cutOff + ", nodes visited: " + nodesVisited + "."); - return route; - } - - // Try again, this time with a deeper cut-off. The t score - // is the closest we got to the end node. - cutOff = t; - } - - // This _should_ never to be reached. - return []; -}; - -module.exports = IDAStarFinder; - -},{"../core/Heuristic":5,"../core/Node":6,"../core/Util":7}],17:[function(require,module,exports){ -/** - * @author aniero / https://github.com/aniero - */ -var Heap = require('heap'); -var Util = require('../core/Util'); -var Heuristic = require('../core/Heuristic'); - -/** - * Path finder using the Jump Point Search algorithm - * @param {object} opt - * @param {function} opt.heuristic Heuristic function to estimate the distance - * (defaults to manhattan). - */ -function JumpPointFinder(opt) { - opt = opt || {}; - this.heuristic = opt.heuristic || Heuristic.manhattan; - this.trackJumpRecursion = opt.trackJumpRecursion || false; -} - -/** - * Find and return the path. - * @return {Array.<[number, number]>} The path, including both start and - * end positions. - */ -JumpPointFinder.prototype.findPath = function(startX, startY, endX, endY, grid) { - var openList = this.openList = new Heap(function(nodeA, nodeB) { - return nodeA.f - nodeB.f; - }), - startNode = this.startNode = grid.getNodeAt(startX, startY), - endNode = this.endNode = grid.getNodeAt(endX, endY), node; - - this.grid = grid; - - - // set the `g` and `f` value of the start node to be 0 - startNode.g = 0; - startNode.f = 0; - - // push the start node into the open list - openList.push(startNode); - startNode.opened = true; - - // while the open list is not empty - while (!openList.empty()) { - // pop the position of node which has the minimum `f` value. - node = openList.pop(); - node.closed = true; - - if (node === endNode) { - return Util.expandPath(Util.backtrace(endNode)); - } - - this._identifySuccessors(node); - } - - // fail to find the path - return []; -}; - -/** - * Identify successors for the given node. Runs a jump point search in the - * direction of each available neighbor, adding any points found to the open - * list. - * @protected - */ -JumpPointFinder.prototype._identifySuccessors = function(node) { - var grid = this.grid, - heuristic = this.heuristic, - openList = this.openList, - endX = this.endNode.x, - endY = this.endNode.y, - neighbors, neighbor, - jumpPoint, i, l, - x = node.x, y = node.y, - jx, jy, dx, dy, d, ng, jumpNode, - abs = Math.abs, max = Math.max; - - neighbors = this._findNeighbors(node); - for(i = 0, l = neighbors.length; i < l; ++i) { - neighbor = neighbors[i]; - jumpPoint = this._jump(neighbor[0], neighbor[1], x, y); - if (jumpPoint) { - - jx = jumpPoint[0]; - jy = jumpPoint[1]; - jumpNode = grid.getNodeAt(jx, jy); - - if (jumpNode.closed) { - continue; - } - - // include distance, as parent may not be immediately adjacent: - d = Heuristic.euclidean(abs(jx - x), abs(jy - y)); - ng = node.g + d; // next `g` value - - if (!jumpNode.opened || ng < jumpNode.g) { - jumpNode.g = ng; - jumpNode.h = jumpNode.h || heuristic(abs(jx - endX), abs(jy - endY)); - jumpNode.f = jumpNode.g + jumpNode.h; - jumpNode.parent = node; - - if (!jumpNode.opened) { - openList.push(jumpNode); - jumpNode.opened = true; - } else { - openList.updateItem(jumpNode); - } - } - } - } -}; - -/** - * Search recursively in the direction (parent -> child), stopping only when a - * jump point is found. - * @protected - * @return {Array.<[number, number]>} The x, y coordinate of the jump point - * found, or null if not found - */ -JumpPointFinder.prototype._jump = function(x, y, px, py) { - var grid = this.grid, - dx = x - px, dy = y - py; - - if (!grid.isWalkableAt(x, y)) { - return null; - } - - if(this.trackJumpRecursion === true) { - grid.getNodeAt(x, y).tested = true; - } - - if (grid.getNodeAt(x, y) === this.endNode) { - return [x, y]; - } - - // check for forced neighbors - // along the diagonal - if (dx !== 0 && dy !== 0) { - if ((grid.isWalkableAt(x - dx, y + dy) && !grid.isWalkableAt(x - dx, y)) || - (grid.isWalkableAt(x + dx, y - dy) && !grid.isWalkableAt(x, y - dy))) { - return [x, y]; - } - } - // horizontally/vertically - else { - if( dx !== 0 ) { // moving along x - if((grid.isWalkableAt(x + dx, y + 1) && !grid.isWalkableAt(x, y + 1)) || - (grid.isWalkableAt(x + dx, y - 1) && !grid.isWalkableAt(x, y - 1))) { - return [x, y]; - } - } - else { - if((grid.isWalkableAt(x + 1, y + dy) && !grid.isWalkableAt(x + 1, y)) || - (grid.isWalkableAt(x - 1, y + dy) && !grid.isWalkableAt(x - 1, y))) { - return [x, y]; - } - } - } - - // when moving diagonally, must check for vertical/horizontal jump points - if (dx !== 0 && dy !== 0) { - if (this._jump(x + dx, y, x, y) || this._jump(x, y + dy, x, y)) { - return [x, y]; - } - } - - // moving diagonally, must make sure one of the vertical/horizontal - // neighbors is open to allow the path - if (grid.isWalkableAt(x + dx, y) || grid.isWalkableAt(x, y + dy)) { - return this._jump(x + dx, y + dy, x, y); - } else { - return null; - } -}; - -/** - * Find the neighbors for the given node. If the node has a parent, - * prune the neighbors based on the jump point search algorithm, otherwise - * return all available neighbors. - * @return {Array.<[number, number]>} The neighbors found. - */ -JumpPointFinder.prototype._findNeighbors = function(node) { - var parent = node.parent, - x = node.x, y = node.y, - grid = this.grid, - px, py, nx, ny, dx, dy, - neighbors = [], neighborNodes, neighborNode, i, l; - - // directed pruning: can ignore most neighbors, unless forced. - if (parent) { - px = parent.x; - py = parent.y; - // get the normalized direction of travel - dx = (x - px) / Math.max(Math.abs(x - px), 1); - dy = (y - py) / Math.max(Math.abs(y - py), 1); - - // search diagonally - if (dx !== 0 && dy !== 0) { - if (grid.isWalkableAt(x, y + dy)) { - neighbors.push([x, y + dy]); - } - if (grid.isWalkableAt(x + dx, y)) { - neighbors.push([x + dx, y]); - } - if (grid.isWalkableAt(x, y + dy) || grid.isWalkableAt(x + dx, y)) { - neighbors.push([x + dx, y + dy]); - } - if (!grid.isWalkableAt(x - dx, y) && grid.isWalkableAt(x, y + dy)) { - neighbors.push([x - dx, y + dy]); - } - if (!grid.isWalkableAt(x, y - dy) && grid.isWalkableAt(x + dx, y)) { - neighbors.push([x + dx, y - dy]); - } - } - // search horizontally/vertically - else { - if(dx === 0) { - if (grid.isWalkableAt(x, y + dy)) { - neighbors.push([x, y + dy]); - if (!grid.isWalkableAt(x + 1, y)) { - neighbors.push([x + 1, y + dy]); - } - if (!grid.isWalkableAt(x - 1, y)) { - neighbors.push([x - 1, y + dy]); - } - } - } - else { - if (grid.isWalkableAt(x + dx, y)) { - neighbors.push([x + dx, y]); - if (!grid.isWalkableAt(x, y + 1)) { - neighbors.push([x + dx, y + 1]); - } - if (!grid.isWalkableAt(x, y - 1)) { - neighbors.push([x + dx, y - 1]); - } - } - } - } - } - // return all neighbors - else { - neighborNodes = grid.getNeighbors(node, true); - for (i = 0, l = neighborNodes.length; i < l; ++i) { - neighborNode = neighborNodes[i]; - neighbors.push([neighborNode.x, neighborNode.y]); - } - } - - return neighbors; -}; - -module.exports = JumpPointFinder; - -},{"../core/Heuristic":5,"../core/Util":7,"heap":1}],18:[function(require,module,exports){ -/** - * @author imor / https://github.com/imor - */ -var Heuristic = require('../core/Heuristic'); -var JumpPointFinder = require('./JumpPointFinder'); - -/** - * Path finder using the Jump Point Search algorithm allowing only horizontal - * or vertical movements. - * @param {object} opt - * @param {function} opt.heuristic Heuristic function to estimate the distance - * (defaults to manhattan). - */ -function OrthogonalJumpPointFinder(opt) { - JumpPointFinder.call(this, opt); - opt = opt || {}; - this.heuristic = opt.heuristic || Heuristic.manhattan; -} - -OrthogonalJumpPointFinder.prototype = new JumpPointFinder(); -OrthogonalJumpPointFinder.prototype.constructor = OrthogonalJumpPointFinder; - -/** - * Search recursively in the direction (parent -> child), stopping only when a - * jump point is found. - * @protected - * @return {Array.<[number, number]>} The x, y coordinate of the jump point - * found, or null if not found - */ -OrthogonalJumpPointFinder.prototype._jump = function(x, y, px, py) { - var grid = this.grid, - dx = x - px, dy = y - py; - - if (!grid.isWalkableAt(x, y)) { - return null; - } - - if(this.trackJumpRecursion === true) { - grid.getNodeAt(x, y).tested = true; - } - - if (grid.getNodeAt(x, y) === this.endNode) { - return [x, y]; - } - - if (dx !== 0) { - if ((grid.isWalkableAt(x, y - 1) && !grid.isWalkableAt(x - dx, y - 1)) || - (grid.isWalkableAt(x, y + 1) && !grid.isWalkableAt(x - dx, y + 1))) { - return [x, y]; - } - } - else if (dy !== 0) { - if ((grid.isWalkableAt(x - 1, y) && !grid.isWalkableAt(x - 1, y - dy)) || - (grid.isWalkableAt(x + 1, y) && !grid.isWalkableAt(x + 1, y - dy))) { - return [x, y]; - } - //When moving vertically, must check for horizontal jump points - if (this._jump(x + 1, y, x, y) || this._jump(x - 1, y, x, y)) { - return [x, y]; - } - } - else { - throw new Error("Only horizontal and vertical movements are allowed"); - } - - return this._jump(x + dx, y + dy, x, y); -}; - -/** - * Find the neighbors for the given node. If the node has a parent, - * prune the neighbors based on the jump point search algorithm, otherwise - * return all available neighbors. - * @return {Array.<[number, number]>} The neighbors found. - */ -OrthogonalJumpPointFinder.prototype._findNeighbors = function(node) { - var parent = node.parent, - x = node.x, y = node.y, - grid = this.grid, - px, py, nx, ny, dx, dy, - neighbors = [], neighborNodes, neighborNode, i, l; - - // directed pruning: can ignore most neighbors, unless forced. - if (parent) { - px = parent.x; - py = parent.y; - // get the normalized direction of travel - dx = (x - px) / Math.max(Math.abs(x - px), 1); - dy = (y - py) / Math.max(Math.abs(y - py), 1); - - if (dx !== 0) { - if (grid.isWalkableAt(x, y - 1)) { - neighbors.push([x, y - 1]); - } - if (grid.isWalkableAt(x, y + 1)) { - neighbors.push([x, y + 1]); - } - if (grid.isWalkableAt(x + dx, y)) { - neighbors.push([x + dx, y]); - } - } - else if (dy !== 0) { - if (grid.isWalkableAt(x - 1, y)) { - neighbors.push([x - 1, y]); - } - if (grid.isWalkableAt(x + 1, y)) { - neighbors.push([x + 1, y]); - } - if (grid.isWalkableAt(x, y + dy)) { - neighbors.push([x, y + dy]); - } - } - } - // return all neighbors - else { - neighborNodes = grid.getNeighbors(node, false); - for (i = 0, l = neighborNodes.length; i < l; ++i) { - neighborNode = neighborNodes[i]; - neighbors.push([neighborNode.x, neighborNode.y]); - } - } - - return neighbors; -}; - -module.exports = OrthogonalJumpPointFinder; - -},{"../core/Heuristic":5,"./JumpPointFinder":17}]},{},[3])(3) -}); -; \ No newline at end of file diff --git a/lib/pathfinding-browser.min.js b/lib/pathfinding-browser.min.js deleted file mode 100644 index 3b5a5052..00000000 --- a/lib/pathfinding-browser.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(t){if("function"==typeof bootstrap)bootstrap("pf",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makePF=t}else"undefined"!=typeof window?window.PF=t():global.PF=t()}(function(){return function(t,e,r){function i(r,o){if(!e[r]){if(!t[r]){var s="function"==typeof require&&require;if(!o&&s)return s(r,!0);if(n)return n(r,!0);throw new Error("Cannot find module '"+r+"'")}var a=e[r]={exports:{}};t[r][0].call(a.exports,function(e){var n=t[r][1][e];return i(n?n:e)},a,a.exports)}return e[r].exports}for(var n="function"==typeof require&&require,o=0;ot?-1:t>e?1:0},h=function(t,e,n,o,s){var a;if(null==n&&(n=0),null==s&&(s=r),0>n)throw new Error("lo must be non-negative");for(null==o&&(o=t.length);o>n;)a=i((n+o)/2),s(e,t[a])<0?o=a:n=a+1;return[].splice.apply(t,[n,n-n].concat(e)),e},s=function(t,e,i){return null==i&&(i=r),t.push(e),d(t,0,t.length-1,i)},o=function(t,e){var i,n;return null==e&&(e=r),i=t.pop(),t.length?(n=t[0],t[0]=i,g(t,0,e)):n=i,n},u=function(t,e,i){var n;return null==i&&(i=r),n=t[0],t[0]=e,g(t,0,i),n},a=function(t,e,i){var n;return null==i&&(i=r),t.length&&i(t[0],e)<0&&(n=[t[0],e],e=n[0],t[0]=n[1],g(t,0,i)),e},n=function(t,e){var n,o,s,a,u,h;for(null==e&&(e=r),a=function(){h=[];for(var e=0,r=i(t.length/2);r>=0?r>e:e>r;r>=0?e++:e--)h.push(e);return h}.apply(this).reverse(),u=[],o=0,s=a.length;s>o;o++)n=a[o],u.push(g(t,n,e));return u},f=function(t,e,i){var n;return null==i&&(i=r),n=t.indexOf(e),-1!==n?(d(t,0,n,i),g(t,n,i)):void 0},p=function(t,e,i){var o,s,u,h,l;if(null==i&&(i=r),s=t.slice(0,e),!s.length)return s;for(n(s,i),l=t.slice(e),u=0,h=l.length;h>u;u++)o=l[u],a(s,o,i);return s.sort(i).reverse()},c=function(t,e,i){var s,a,u,p,c,f,d,g,b,y;if(null==i&&(i=r),10*e<=t.length){if(p=t.slice(0,e).sort(i),!p.length)return p;for(u=p[p.length-1],g=t.slice(e),c=0,d=g.length;d>c;c++)s=g[c],i(s,u)<0&&(h(p,s,0,null,i),p.pop(),u=p[p.length-1]);return p}for(n(t,i),y=[],a=f=0,b=l(e,t.length);b>=0?b>f:f>b;a=b>=0?++f:--f)y.push(o(t,i));return y},d=function(t,e,i,n){var o,s,a;for(null==n&&(n=r),o=t[i];i>e&&(a=i-1>>1,s=t[a],n(o,s)<0);)t[i]=s,i=a;return t[i]=o},g=function(t,e,i){var n,o,s,a,u;for(null==i&&(i=r),o=t.length,u=e,s=t[e],n=2*e+1;o>n;)a=n+1,o>a&&!(i(t[n],t[a])<0)&&(n=a),t[e]=t[n],e=n,n=2*e+1;return t[e]=s,d(t,u,e,i)},t=function(){function t(t){this.cmp=null!=t?t:r,this.nodes=[]}return t.push=s,t.pop=o,t.replace=u,t.pushpop=a,t.heapify=n,t.nlargest=p,t.nsmallest=c,t.prototype.push=function(t){return s(this.nodes,t,this.cmp)},t.prototype.pop=function(){return o(this.nodes,this.cmp)},t.prototype.peek=function(){return this.nodes[0]},t.prototype.contains=function(t){return-1!==this.nodes.indexOf(t)},t.prototype.replace=function(t){return u(this.nodes,t,this.cmp)},t.prototype.pushpop=function(t){return a(this.nodes,t,this.cmp)},t.prototype.heapify=function(){return n(this.nodes,this.cmp)},t.prototype.updateItem=function(t){return f(this.nodes,t,this.cmp)},t.prototype.clear=function(){return this.nodes=[]},t.prototype.empty=function(){return 0===this.nodes.length},t.prototype.size=function(){return this.nodes.length},t.prototype.clone=function(){var e;return e=new t,e.nodes=this.nodes.slice(0),e},t.prototype.toArray=function(){return this.nodes.slice(0)},t.prototype.insert=t.prototype.push,t.prototype.remove=t.prototype.pop,t.prototype.top=t.prototype.peek,t.prototype.front=t.prototype.peek,t.prototype.has=t.prototype.contains,t.prototype.copy=t.prototype.clone,t}(),("undefined"!=typeof e&&null!==e?e.exports:void 0)?e.exports=t:window.Heap=t}.call(this)},{}],3:[function(t,e){e.exports={Heap:t("heap"),Node:t("./core/Node"),Grid:t("./core/Grid"),Util:t("./core/Util"),Heuristic:t("./core/Heuristic"),AStarFinder:t("./finders/AStarFinder"),BestFirstFinder:t("./finders/BestFirstFinder"),BreadthFirstFinder:t("./finders/BreadthFirstFinder"),DijkstraFinder:t("./finders/DijkstraFinder"),BiAStarFinder:t("./finders/BiAStarFinder"),BiBestFirstFinder:t("./finders/BiBestFirstFinder"),BiBreadthFirstFinder:t("./finders/BiBreadthFirstFinder"),BiDijkstraFinder:t("./finders/BiDijkstraFinder"),JumpPointFinder:t("./finders/JumpPointFinder"),IDAStarFinder:t("./finders/IDAStarFinder"),OrthogonalJumpPointFinder:t("./finders/OrthogonalJumpPointFinder")}},{"./core/Grid":4,"./core/Heuristic":5,"./core/Node":6,"./core/Util":7,"./finders/AStarFinder":8,"./finders/BestFirstFinder":9,"./finders/BiAStarFinder":10,"./finders/BiBestFirstFinder":11,"./finders/BiBreadthFirstFinder":12,"./finders/BiDijkstraFinder":13,"./finders/BreadthFirstFinder":14,"./finders/DijkstraFinder":15,"./finders/IDAStarFinder":16,"./finders/JumpPointFinder":17,"./finders/OrthogonalJumpPointFinder":18,heap:1}],4:[function(t,e){function r(t,e,r){this.width=t,this.height=e,this.nodes=this._buildNodes(t,e,r)}var i=t("./Node");r.prototype._buildNodes=function(t,e,r){var n,o,s=new Array(e);for(n=0;e>n;++n)for(s[n]=new Array(t),o=0;t>o;++o)s[n][o]=new i(o,n);if(void 0===r)return s;if(r.length!==e||r[0].length!==t)throw new Error("Matrix size does not fit");for(n=0;e>n;++n)for(o=0;t>o;++o)r[n][o]&&(s[n][o].walkable=!1);return s},r.prototype.getNodeAt=function(t,e){return this.nodes[e][t]},r.prototype.isWalkableAt=function(t,e){return this.isInside(t,e)&&this.nodes[e][t].walkable},r.prototype.isInside=function(t,e){return t>=0&&t=0&&et;++t)for(u[t]=new Array(n),e=0;n>e;++e)u[t][e]=new i(e,t,s[t][e].walkable);return a.nodes=u,a},e.exports=r},{"./Node":6}],5:[function(t,e){e.exports={manhattan:function(t,e){return t+e},euclidean:function(t,e){return Math.sqrt(t*t+e*e)},chebyshev:function(t,e){return Math.max(t,e)}}},{}],6:[function(t,e){function r(t,e,r){this.x=t,this.y=e,this.walkable=void 0===r?!0:r}e.exports=r},{}],7:[function(t,e,r){function i(t){for(var e=[[t.x,t.y]];t.parent;)t=t.parent,e.push([t.x,t.y]);return e.reverse()}function n(t,e){var r=i(t),n=i(e);return r.concat(n.reverse())}function o(t){var e,r,i,n,o,s=0;for(e=1;et?1:-1,o=i>e?1:-1,u=s-a;;){if(p.push([t,e]),t===r&&e===i)break;h=2*u,h>-a&&(u-=a,t+=n),s>h&&(u+=s,e+=o)}return p}function a(t){var e,r,i,n,o,a,u=[],h=t.length;if(2>h)return u;for(o=0;h-1>o;++o)for(e=t[o],r=t[o+1],i=s(e[0],e[1],r[0],r[1]),n=i.length,a=0;n-1>a;++a)u.push(i[a]);return u.push(t[h-1]),u}function u(t,e){var r,i,n,o,a,u,h,l,p,c,f,d,g,b=e.length,y=e[0][0],A=e[0][1],k=e[b-1][0],m=e[b-1][1];for(r=y,i=A,a=e[1][0],u=e[1][1],h=[[r,i]],l=2;b>l;++l){for(c=e[l],n=c[0],o=c[1],f=s(r,i,n,o),g=!1,p=1;pl;++l)h=u[l],h.closed||(c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:x),(!h.opened||dl;++l)if(h=u[l],!h.closed){if(h.opened===C)return n.biBacktrace(a,h);c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:W),(!h.opened||dl;++l)if(h=u[l],!h.closed){if(h.opened===N)return n.biBacktrace(h,a);c=h.x,f=h.y,d=a.g+(0===c-a.x||0===f-a.y?1:W),(!h.opened||dh;++h)if(a=s[h],!a.closed)if(a.opened){if(a.by===A)return i.biBacktrace(u,a)}else f.push(a),a.parent=u,a.opened=!0,a.by=y;for(u=d.shift(),u.closed=!0,s=o.getNeighbors(u,g,b),h=0,l=s.length;l>h;++h)if(a=s[h],!a.closed)if(a.opened){if(a.by===y)return i.biBacktrace(a,u)}else d.push(a),a.parent=u,a.opened=!0,a.by=A}return[]},e.exports=r},{"../core/Util":7}],13:[function(t,e){function r(t){i.call(this,t),this.heuristic=function(){return 0}}var i=t("./BiAStarFinder");r.prototype=new i,r.prototype.constructor=r,e.exports=r},{"./BiAStarFinder":10}],14:[function(t,e){function r(t){t=t||{},this.allowDiagonal=t.allowDiagonal,this.dontCrossCorners=t.dontCrossCorners}var i=t("../core/Util");r.prototype.findPath=function(t,e,r,n,o){var s,a,u,h,l,p=[],c=this.allowDiagonal,f=this.dontCrossCorners,d=o.getNodeAt(t,e),g=o.getNodeAt(r,n);for(p.push(d),d.opened=!0;p.length;){if(u=p.shift(),u.closed=!0,u===g)return i.backtrace(g);for(s=o.getNeighbors(u,c,f),h=0,l=s.length;l>h;++h)a=s[h],a.closed||a.opened||(p.push(a),a.opened=!0,a.parent=u)}return[]},e.exports=r},{"../core/Util":7}],15:[function(t,e){function r(t){i.call(this,t),this.heuristic=function(){return 0}}var i=t("./AStarFinder");r.prototype=new i,r.prototype.constructor=r,e.exports=r},{"./AStarFinder":8}],16:[function(t,e){function r(t){t=t||{},this.allowDiagonal=t.allowDiagonal,this.dontCrossCorners=t.dontCrossCorners,this.heuristic=t.heuristic||i.manhattan,this.weight=t.weight||1,this.trackRecursion=t.trackRecursion||!1,this.timeLimit=t.timeLimit||1/0}t("../core/Util");var i=t("../core/Heuristic"),n=t("../core/Node");r.prototype.findPath=function(t,e,r,i,o){var s,a,u,h=0,l=(new Date).getTime(),p=function(t,e){return this.heuristic(Math.abs(e.x-t.x),Math.abs(e.y-t.y))}.bind(this),c=function(t,e){return t.x===e.x||t.y===e.y?1:Math.SQRT2},f=function(t,e,r,i,s){if(h++,this.timeLimit>0&&(new Date).getTime()-l>1e3*this.timeLimit)return 1/0;var a=e+p(t,g)*this.weight;if(a>r)return a;if(t==g)return i[s]=[t.x,t.y],t;var u,d,b,y,A=o.getNeighbors(t,this.allowDiagonal,this.dontCrossCorners);for(b=0,u=1/0;y=A[b];++b){if(this.trackRecursion&&(y.retainCount=y.retainCount+1||1,y.tested!==!0&&(y.tested=!0)),d=f(y,e+c(t,y),r,i,s+1),d instanceof n)return i[s]=[t.x,t.y],d;this.trackRecursion&&0===--y.retainCount&&(y.tested=!1),u>d&&(u=d)}return u}.bind(this),d=o.getNodeAt(t,e),g=o.getNodeAt(r,i),b=p(d,g);for(s=0;!0;++s){if(a=[],u=f(d,0,b,a,0),1/0===u)return[];if(u instanceof n)return a;b=u}return[]},e.exports=r},{"../core/Heuristic":5,"../core/Node":6,"../core/Util":7}],17:[function(t,e){function r(t){t=t||{},this.heuristic=t.heuristic||o.manhattan,this.trackJumpRecursion=t.trackJumpRecursion||!1}var i=t("heap"),n=t("../core/Util"),o=t("../core/Heuristic");r.prototype.findPath=function(t,e,r,o,s){var a,u=this.openList=new i(function(t,e){return t.f-e.f}),h=this.startNode=s.getNodeAt(t,e),l=this.endNode=s.getNodeAt(r,o);for(this.grid=s,h.g=0,h.f=0,u.push(h),h.opened=!0;!u.empty();){if(a=u.pop(),a.closed=!0,a===l)return n.expandPath(n.backtrace(l));this._identifySuccessors(a)}return[]},r.prototype._identifySuccessors=function(t){var e,r,i,n,s,a,u,h,l,p,c=this.grid,f=this.heuristic,d=this.openList,g=this.endNode.x,b=this.endNode.y,y=t.x,A=t.y,k=Math.abs;for(Math.max,e=this._findNeighbors(t),n=0,s=e.length;s>n;++n)if(r=e[n],i=this._jump(r[0],r[1],y,A)){if(a=i[0],u=i[1],p=c.getNodeAt(a,u),p.closed)continue;h=o.euclidean(k(a-y),k(u-A)),l=t.g+h,(!p.opened||la;++a)s=o[a],f.push([s.x,s.y]);return f},e.exports=r},{"../core/Heuristic":5,"../core/Util":7,heap:1}],18:[function(t,e){function r(t){n.call(this,t),t=t||{},this.heuristic=t.heuristic||i.manhattan}var i=t("../core/Heuristic"),n=t("./JumpPointFinder");r.prototype=new n,r.prototype.constructor=r,r.prototype._jump=function(t,e,r,i){var n=this.grid,o=t-r,s=e-i;if(!n.isWalkableAt(t,e))return null;if(this.trackJumpRecursion===!0&&(n.getNodeAt(t,e).tested=!0),n.getNodeAt(t,e)===this.endNode)return[t,e];if(0!==o){if(n.isWalkableAt(t,e-1)&&!n.isWalkableAt(t-o,e-1)||n.isWalkableAt(t,e+1)&&!n.isWalkableAt(t-o,e+1))return[t,e]}else{if(0===s)throw new Error("Only horizontal and vertical movements are allowed");if(n.isWalkableAt(t-1,e)&&!n.isWalkableAt(t-1,e-s)||n.isWalkableAt(t+1,e)&&!n.isWalkableAt(t+1,e-s))return[t,e];if(this._jump(t+1,e,t,e)||this._jump(t-1,e,t,e))return[t,e]}return this._jump(t+o,e+s,t,e)},r.prototype._findNeighbors=function(t){var e,r,i,n,o,s,a,u,h=t.parent,l=t.x,p=t.y,c=this.grid,f=[];if(h)e=h.x,r=h.y,i=(l-e)/Math.max(Math.abs(l-e),1),n=(p-r)/Math.max(Math.abs(p-r),1),0!==i?(c.isWalkableAt(l,p-1)&&f.push([l,p-1]),c.isWalkableAt(l,p+1)&&f.push([l,p+1]),c.isWalkableAt(l+i,p)&&f.push([l+i,p])):0!==n&&(c.isWalkableAt(l-1,p)&&f.push([l-1,p]),c.isWalkableAt(l+1,p)&&f.push([l+1,p]),c.isWalkableAt(l,p+n)&&f.push([l,p+n]));else for(o=c.getNeighbors(t,!1),a=0,u=o.length;u>a;++a)s=o[a],f.push([s.x,s.y]);return f},e.exports=r},{"../core/Heuristic":5,"./JumpPointFinder":17}]},{},[3])(3)}); \ No newline at end of file