anythingpls

Untitled

Mar 22nd, 2019
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 80.63 KB | None | 0 0
  1. /**
  2. * ____ _ _ _____ _ _ _ _
  3. * | _ \ __ _| |_| |__ | ___(_)_ __ __| (_)_ __ __ _ (_)___
  4. * | |_) / _` | __| '_ \| |_ | | '_ \ / _` | | '_ \ / _` | | / __|
  5. * | __/ (_| | |_| | | | _| | | | | | (_| | | | | | (_| |_ | \__ \
  6. * |_| \__,_|\__|_| |_|_| |_|_| |_|\__,_|_|_| |_|\__, (_)/ |___/
  7. * |___/ |__/
  8. * https://github.com/qiao/PathFinding.js
  9. */
  10.  
  11. !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.PF=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
  12. module.exports = _dereq_('./lib/heap');
  13.  
  14. },{"./lib/heap":2}],2:[function(_dereq_,module,exports){
  15. // Generated by CoffeeScript 1.8.0
  16. (function() {
  17. var Heap, defaultCmp, floor, heapify, heappop, heappush, heappushpop, heapreplace, insort, min, nlargest, nsmallest, updateItem, _siftdown, _siftup;
  18.  
  19. floor = Math.floor, min = Math.min;
  20.  
  21.  
  22. /*
  23. Default comparison function to be used
  24. */
  25.  
  26. defaultCmp = function(x, y) {
  27. if (x < y) {
  28. return -1;
  29. }
  30. if (x > y) {
  31. return 1;
  32. }
  33. return 0;
  34. };
  35.  
  36.  
  37. /*
  38. Insert item x in list a, and keep it sorted assuming a is sorted.
  39.  
  40. If x is already in a, insert it to the right of the rightmost x.
  41.  
  42. Optional args lo (default 0) and hi (default a.length) bound the slice
  43. of a to be searched.
  44. */
  45.  
  46. insort = function(a, x, lo, hi, cmp) {
  47. var mid;
  48. if (lo == null) {
  49. lo = 0;
  50. }
  51. if (cmp == null) {
  52. cmp = defaultCmp;
  53. }
  54. if (lo < 0) {
  55. throw new Error('lo must be non-negative');
  56. }
  57. if (hi == null) {
  58. hi = a.length;
  59. }
  60. while (lo < hi) {
  61. mid = floor((lo + hi) / 2);
  62. if (cmp(x, a[mid]) < 0) {
  63. hi = mid;
  64. } else {
  65. lo = mid + 1;
  66. }
  67. }
  68. return ([].splice.apply(a, [lo, lo - lo].concat(x)), x);
  69. };
  70.  
  71.  
  72. /*
  73. Push item onto heap, maintaining the heap invariant.
  74. */
  75.  
  76. heappush = function(array, item, cmp) {
  77. if (cmp == null) {
  78. cmp = defaultCmp;
  79. }
  80. array.push(item);
  81. return _siftdown(array, 0, array.length - 1, cmp);
  82. };
  83.  
  84.  
  85. /*
  86. Pop the smallest item off the heap, maintaining the heap invariant.
  87. */
  88.  
  89. heappop = function(array, cmp) {
  90. var lastelt, returnitem;
  91. if (cmp == null) {
  92. cmp = defaultCmp;
  93. }
  94. lastelt = array.pop();
  95. if (array.length) {
  96. returnitem = array[0];
  97. array[0] = lastelt;
  98. _siftup(array, 0, cmp);
  99. } else {
  100. returnitem = lastelt;
  101. }
  102. return returnitem;
  103. };
  104.  
  105.  
  106. /*
  107. Pop and return the current smallest value, and add the new item.
  108.  
  109. This is more efficient than heappop() followed by heappush(), and can be
  110. more appropriate when using a fixed size heap. Note that the value
  111. returned may be larger than item! That constrains reasonable use of
  112. this routine unless written as part of a conditional replacement:
  113. if item > array[0]
  114. item = heapreplace(array, item)
  115. */
  116.  
  117. heapreplace = function(array, item, cmp) {
  118. var returnitem;
  119. if (cmp == null) {
  120. cmp = defaultCmp;
  121. }
  122. returnitem = array[0];
  123. array[0] = item;
  124. _siftup(array, 0, cmp);
  125. return returnitem;
  126. };
  127.  
  128.  
  129. /*
  130. Fast version of a heappush followed by a heappop.
  131. */
  132.  
  133. heappushpop = function(array, item, cmp) {
  134. var _ref;
  135. if (cmp == null) {
  136. cmp = defaultCmp;
  137. }
  138. if (array.length && cmp(array[0], item) < 0) {
  139. _ref = [array[0], item], item = _ref[0], array[0] = _ref[1];
  140. _siftup(array, 0, cmp);
  141. }
  142. return item;
  143. };
  144.  
  145.  
  146. /*
  147. Transform list into a heap, in-place, in O(array.length) time.
  148. */
  149.  
  150. heapify = function(array, cmp) {
  151. var i, _i, _j, _len, _ref, _ref1, _results, _results1;
  152. if (cmp == null) {
  153. cmp = defaultCmp;
  154. }
  155. _ref1 = (function() {
  156. _results1 = [];
  157. for (var _j = 0, _ref = floor(array.length / 2); 0 <= _ref ? _j < _ref : _j > _ref; 0 <= _ref ? _j++ : _j--){ _results1.push(_j); }
  158. return _results1;
  159. }).apply(this).reverse();
  160. _results = [];
  161. for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
  162. i = _ref1[_i];
  163. _results.push(_siftup(array, i, cmp));
  164. }
  165. return _results;
  166. };
  167.  
  168.  
  169. /*
  170. Update the position of the given item in the heap.
  171. This function should be called every time the item is being modified.
  172. */
  173.  
  174. updateItem = function(array, item, cmp) {
  175. var pos;
  176. if (cmp == null) {
  177. cmp = defaultCmp;
  178. }
  179. pos = array.indexOf(item);
  180. if (pos === -1) {
  181. return;
  182. }
  183. _siftdown(array, 0, pos, cmp);
  184. return _siftup(array, pos, cmp);
  185. };
  186.  
  187.  
  188. /*
  189. Find the n largest elements in a dataset.
  190. */
  191.  
  192. nlargest = function(array, n, cmp) {
  193. var elem, result, _i, _len, _ref;
  194. if (cmp == null) {
  195. cmp = defaultCmp;
  196. }
  197. result = array.slice(0, n);
  198. if (!result.length) {
  199. return result;
  200. }
  201. heapify(result, cmp);
  202. _ref = array.slice(n);
  203. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  204. elem = _ref[_i];
  205. heappushpop(result, elem, cmp);
  206. }
  207. return result.sort(cmp).reverse();
  208. };
  209.  
  210.  
  211. /*
  212. Find the n smallest elements in a dataset.
  213. */
  214.  
  215. nsmallest = function(array, n, cmp) {
  216. var elem, i, los, result, _i, _j, _len, _ref, _ref1, _results;
  217. if (cmp == null) {
  218. cmp = defaultCmp;
  219. }
  220. if (n * 10 <= array.length) {
  221. result = array.slice(0, n).sort(cmp);
  222. if (!result.length) {
  223. return result;
  224. }
  225. los = result[result.length - 1];
  226. _ref = array.slice(n);
  227. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  228. elem = _ref[_i];
  229. if (cmp(elem, los) < 0) {
  230. insort(result, elem, 0, null, cmp);
  231. result.pop();
  232. los = result[result.length - 1];
  233. }
  234. }
  235. return result;
  236. }
  237. heapify(array, cmp);
  238. _results = [];
  239. for (i = _j = 0, _ref1 = min(n, array.length); 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
  240. _results.push(heappop(array, cmp));
  241. }
  242. return _results;
  243. };
  244.  
  245. _siftdown = function(array, startpos, pos, cmp) {
  246. var newitem, parent, parentpos;
  247. if (cmp == null) {
  248. cmp = defaultCmp;
  249. }
  250. newitem = array[pos];
  251. while (pos > startpos) {
  252. parentpos = (pos - 1) >> 1;
  253. parent = array[parentpos];
  254. if (cmp(newitem, parent) < 0) {
  255. array[pos] = parent;
  256. pos = parentpos;
  257. continue;
  258. }
  259. break;
  260. }
  261. return array[pos] = newitem;
  262. };
  263.  
  264. _siftup = function(array, pos, cmp) {
  265. var childpos, endpos, newitem, rightpos, startpos;
  266. if (cmp == null) {
  267. cmp = defaultCmp;
  268. }
  269. endpos = array.length;
  270. startpos = pos;
  271. newitem = array[pos];
  272. childpos = 2 * pos + 1;
  273. while (childpos < endpos) {
  274. rightpos = childpos + 1;
  275. if (rightpos < endpos && !(cmp(array[childpos], array[rightpos]) < 0)) {
  276. childpos = rightpos;
  277. }
  278. array[pos] = array[childpos];
  279. pos = childpos;
  280. childpos = 2 * pos + 1;
  281. }
  282. array[pos] = newitem;
  283. return _siftdown(array, startpos, pos, cmp);
  284. };
  285.  
  286. Heap = (function() {
  287. Heap.push = heappush;
  288.  
  289. Heap.pop = heappop;
  290.  
  291. Heap.replace = heapreplace;
  292.  
  293. Heap.pushpop = heappushpop;
  294.  
  295. Heap.heapify = heapify;
  296.  
  297. Heap.updateItem = updateItem;
  298.  
  299. Heap.nlargest = nlargest;
  300.  
  301. Heap.nsmallest = nsmallest;
  302.  
  303. function Heap(cmp) {
  304. this.cmp = cmp != null ? cmp : defaultCmp;
  305. this.nodes = [];
  306. }
  307.  
  308. Heap.prototype.push = function(x) {
  309. return heappush(this.nodes, x, this.cmp);
  310. };
  311.  
  312. Heap.prototype.pop = function() {
  313. return heappop(this.nodes, this.cmp);
  314. };
  315.  
  316. Heap.prototype.peek = function() {
  317. return this.nodes[0];
  318. };
  319.  
  320. Heap.prototype.contains = function(x) {
  321. return this.nodes.indexOf(x) !== -1;
  322. };
  323.  
  324. Heap.prototype.replace = function(x) {
  325. return heapreplace(this.nodes, x, this.cmp);
  326. };
  327.  
  328. Heap.prototype.pushpop = function(x) {
  329. return heappushpop(this.nodes, x, this.cmp);
  330. };
  331.  
  332. Heap.prototype.heapify = function() {
  333. return heapify(this.nodes, this.cmp);
  334. };
  335.  
  336. Heap.prototype.updateItem = function(x) {
  337. return updateItem(this.nodes, x, this.cmp);
  338. };
  339.  
  340. Heap.prototype.clear = function() {
  341. return this.nodes = [];
  342. };
  343.  
  344. Heap.prototype.empty = function() {
  345. return this.nodes.length === 0;
  346. };
  347.  
  348. Heap.prototype.size = function() {
  349. return this.nodes.length;
  350. };
  351.  
  352. Heap.prototype.clone = function() {
  353. var heap;
  354. heap = new Heap();
  355. heap.nodes = this.nodes.slice(0);
  356. return heap;
  357. };
  358.  
  359. Heap.prototype.toArray = function() {
  360. return this.nodes.slice(0);
  361. };
  362.  
  363. Heap.prototype.insert = Heap.prototype.push;
  364.  
  365. Heap.prototype.top = Heap.prototype.peek;
  366.  
  367. Heap.prototype.front = Heap.prototype.peek;
  368.  
  369. Heap.prototype.has = Heap.prototype.contains;
  370.  
  371. Heap.prototype.copy = Heap.prototype.clone;
  372.  
  373. return Heap;
  374.  
  375. })();
  376.  
  377. if (typeof module !== "undefined" && module !== null ? module.exports : void 0) {
  378. module.exports = Heap;
  379. } else {
  380. window.Heap = Heap;
  381. }
  382.  
  383. }).call(this);
  384.  
  385. },{}],3:[function(_dereq_,module,exports){
  386. var DiagonalMovement = {
  387. Always: 1,
  388. Never: 2,
  389. IfAtMostOneObstacle: 3,
  390. OnlyWhenNoObstacles: 4
  391. };
  392.  
  393. module.exports = DiagonalMovement;
  394. },{}],4:[function(_dereq_,module,exports){
  395. var Node = _dereq_('./Node');
  396. var DiagonalMovement = _dereq_('./DiagonalMovement');
  397.  
  398. /**
  399. * The Grid class, which serves as the encapsulation of the layout of the nodes.
  400. * @constructor
  401. * @param {number|Array<Array<(number|boolean)>>} width_or_matrix Number of columns of the grid, or matrix
  402. * @param {number} height Number of rows of the grid.
  403. * @param {Array<Array<(number|boolean)>>} [matrix] - A 0-1 matrix
  404. * representing the walkable status of the nodes(0 or false for walkable).
  405. * If the matrix is not supplied, all the nodes will be walkable. */
  406. function Grid(width_or_matrix, height, matrix) {
  407. var width;
  408.  
  409. if (typeof width_or_matrix !== 'object') {
  410. width = width_or_matrix;
  411. } else {
  412. height = width_or_matrix.length;
  413. width = width_or_matrix[0].length;
  414. matrix = width_or_matrix;
  415. }
  416.  
  417. /**
  418. * The number of columns of the grid.
  419. * @type number
  420. */
  421. this.width = width;
  422. /**
  423. * The number of rows of the grid.
  424. * @type number
  425. */
  426. this.height = height;
  427.  
  428. /**
  429. * A 2D array of nodes.
  430. */
  431. this.nodes = this._buildNodes(width, height, matrix);
  432. }
  433.  
  434. /**
  435. * Build and return the nodes.
  436. * @private
  437. * @param {number} width
  438. * @param {number} height
  439. * @param {Array<Array<number|boolean>>} [matrix] - A 0-1 matrix representing
  440. * the walkable status of the nodes.
  441. * @see Grid
  442. */
  443. Grid.prototype._buildNodes = function(width, height, matrix) {
  444. var i, j,
  445. nodes = new Array(height);
  446.  
  447. for (i = 0; i < height; ++i) {
  448. nodes[i] = new Array(width);
  449. for (j = 0; j < width; ++j) {
  450. nodes[i][j] = new Node(j, i);
  451. }
  452. }
  453.  
  454.  
  455. if (matrix === undefined) {
  456. return nodes;
  457. }
  458.  
  459. if (matrix.length !== height || matrix[0].length !== width) {
  460. throw new Error('Matrix size does not fit');
  461. }
  462.  
  463. for (i = 0; i < height; ++i) {
  464. for (j = 0; j < width; ++j) {
  465. if (matrix[i][j]) {
  466. // 0, false, null will be walkable
  467. // while others will be un-walkable
  468. nodes[i][j].walkable = false;
  469. }
  470. }
  471. }
  472.  
  473. return nodes;
  474. };
  475.  
  476.  
  477. Grid.prototype.getNodeAt = function(x, y) {
  478. return this.nodes[y][x];
  479. };
  480.  
  481.  
  482. /**
  483. * Determine whether the node at the given position is walkable.
  484. * (Also returns false if the position is outside the grid.)
  485. * @param {number} x - The x coordinate of the node.
  486. * @param {number} y - The y coordinate of the node.
  487. * @return {boolean} - The walkability of the node.
  488. */
  489. Grid.prototype.isWalkableAt = function(x, y) {
  490. return this.isInside(x, y) && this.nodes[y][x].walkable;
  491. };
  492.  
  493.  
  494. /**
  495. * Determine whether the position is inside the grid.
  496. * XXX: `grid.isInside(x, y)` is wierd to read.
  497. * It should be `(x, y) is inside grid`, but I failed to find a better
  498. * name for this method.
  499. * @param {number} x
  500. * @param {number} y
  501. * @return {boolean}
  502. */
  503. Grid.prototype.isInside = function(x, y) {
  504. return (x >= 0 && x < this.width) && (y >= 0 && y < this.height);
  505. };
  506.  
  507.  
  508. /**
  509. * Set whether the node on the given position is walkable.
  510. * NOTE: throws exception if the coordinate is not inside the grid.
  511. * @param {number} x - The x coordinate of the node.
  512. * @param {number} y - The y coordinate of the node.
  513. * @param {boolean} walkable - Whether the position is walkable.
  514. */
  515. Grid.prototype.setWalkableAt = function(x, y, walkable) {
  516. this.nodes[y][x].walkable = walkable;
  517. };
  518.  
  519.  
  520. /**
  521. * Get the neighbors of the given node.
  522. *
  523. * offsets diagonalOffsets:
  524. * +---+---+---+ +---+---+---+
  525. * | | 0 | | | 0 | | 1 |
  526. * +---+---+---+ +---+---+---+
  527. * | 3 | | 1 | | | | |
  528. * +---+---+---+ +---+---+---+
  529. * | | 2 | | | 3 | | 2 |
  530. * +---+---+---+ +---+---+---+
  531. *
  532. * When allowDiagonal is true, if offsets[i] is valid, then
  533. * diagonalOffsets[i] and
  534. * diagonalOffsets[(i + 1) % 4] is valid.
  535. * @param {Node} node
  536. * @param {DiagonalMovement} diagonalMovement
  537. */
  538. Grid.prototype.getNeighbors = function(node, diagonalMovement) {
  539. var x = node.x,
  540. y = node.y,
  541. neighbors = [],
  542. s0 = false, d0 = false,
  543. s1 = false, d1 = false,
  544. s2 = false, d2 = false,
  545. s3 = false, d3 = false,
  546. nodes = this.nodes;
  547.  
  548. // ↑
  549. if (this.isWalkableAt(x, y - 1)) {
  550. neighbors.push(nodes[y - 1][x]);
  551. s0 = true;
  552. }
  553. // →
  554. if (this.isWalkableAt(x + 1, y)) {
  555. neighbors.push(nodes[y][x + 1]);
  556. s1 = true;
  557. }
  558. // ↓
  559. if (this.isWalkableAt(x, y + 1)) {
  560. neighbors.push(nodes[y + 1][x]);
  561. s2 = true;
  562. }
  563. // ←
  564. if (this.isWalkableAt(x - 1, y)) {
  565. neighbors.push(nodes[y][x - 1]);
  566. s3 = true;
  567. }
  568.  
  569. if (diagonalMovement === DiagonalMovement.Never) {
  570. return neighbors;
  571. }
  572.  
  573. if (diagonalMovement === DiagonalMovement.OnlyWhenNoObstacles) {
  574. d0 = s3 && s0;
  575. d1 = s0 && s1;
  576. d2 = s1 && s2;
  577. d3 = s2 && s3;
  578. } else if (diagonalMovement === DiagonalMovement.IfAtMostOneObstacle) {
  579. d0 = s3 || s0;
  580. d1 = s0 || s1;
  581. d2 = s1 || s2;
  582. d3 = s2 || s3;
  583. } else if (diagonalMovement === DiagonalMovement.Always) {
  584. d0 = true;
  585. d1 = true;
  586. d2 = true;
  587. d3 = true;
  588. } else {
  589. throw new Error('Incorrect value of diagonalMovement');
  590. }
  591.  
  592. // ↖
  593. if (d0 && this.isWalkableAt(x - 1, y - 1)) {
  594. neighbors.push(nodes[y - 1][x - 1]);
  595. }
  596. // ↗
  597. if (d1 && this.isWalkableAt(x + 1, y - 1)) {
  598. neighbors.push(nodes[y - 1][x + 1]);
  599. }
  600. // ↘
  601. if (d2 && this.isWalkableAt(x + 1, y + 1)) {
  602. neighbors.push(nodes[y + 1][x + 1]);
  603. }
  604. // ↙
  605. if (d3 && this.isWalkableAt(x - 1, y + 1)) {
  606. neighbors.push(nodes[y + 1][x - 1]);
  607. }
  608.  
  609. return neighbors;
  610. };
  611.  
  612.  
  613. /**
  614. * Get a clone of this grid.
  615. * @return {Grid} Cloned grid.
  616. */
  617. Grid.prototype.clone = function() {
  618. var i, j,
  619.  
  620. width = this.width,
  621. height = this.height,
  622. thisNodes = this.nodes,
  623.  
  624. newGrid = new Grid(width, height),
  625. newNodes = new Array(height);
  626.  
  627. for (i = 0; i < height; ++i) {
  628. newNodes[i] = new Array(width);
  629. for (j = 0; j < width; ++j) {
  630. newNodes[i][j] = new Node(j, i, thisNodes[i][j].walkable);
  631. }
  632. }
  633.  
  634. newGrid.nodes = newNodes;
  635.  
  636. return newGrid;
  637. };
  638.  
  639. module.exports = Grid;
  640.  
  641. },{"./DiagonalMovement":3,"./Node":6}],5:[function(_dereq_,module,exports){
  642. /**
  643. * @namespace PF.Heuristic
  644. * @description A collection of heuristic functions.
  645. */
  646. module.exports = {
  647.  
  648. /**
  649. * Manhattan distance.
  650. * @param {number} dx - Difference in x.
  651. * @param {number} dy - Difference in y.
  652. * @return {number} dx + dy
  653. */
  654. manhattan: function(dx, dy) {
  655. return dx + dy;
  656. },
  657.  
  658. /**
  659. * Euclidean distance.
  660. * @param {number} dx - Difference in x.
  661. * @param {number} dy - Difference in y.
  662. * @return {number} sqrt(dx * dx + dy * dy)
  663. */
  664. euclidean: function(dx, dy) {
  665. return Math.sqrt(dx * dx + dy * dy);
  666. },
  667.  
  668. /**
  669. * Octile distance.
  670. * @param {number} dx - Difference in x.
  671. * @param {number} dy - Difference in y.
  672. * @return {number} sqrt(dx * dx + dy * dy) for grids
  673. */
  674. octile: function(dx, dy) {
  675. var F = Math.SQRT2 - 1;
  676. return (dx < dy) ? F * dx + dy : F * dy + dx;
  677. },
  678.  
  679. /**
  680. * Chebyshev distance.
  681. * @param {number} dx - Difference in x.
  682. * @param {number} dy - Difference in y.
  683. * @return {number} max(dx, dy)
  684. */
  685. chebyshev: function(dx, dy) {
  686. return Math.max(dx, dy);
  687. }
  688.  
  689. };
  690.  
  691. },{}],6:[function(_dereq_,module,exports){
  692. /**
  693. * A node in grid.
  694. * This class holds some basic information about a node and custom
  695. * attributes may be added, depending on the algorithms' needs.
  696. * @constructor
  697. * @param {number} x - The x coordinate of the node on the grid.
  698. * @param {number} y - The y coordinate of the node on the grid.
  699. * @param {boolean} [walkable] - Whether this node is walkable.
  700. */
  701. function Node(x, y, walkable) {
  702. /**
  703. * The x coordinate of the node on the grid.
  704. * @type number
  705. */
  706. this.x = x;
  707. /**
  708. * The y coordinate of the node on the grid.
  709. * @type number
  710. */
  711. this.y = y;
  712. /**
  713. * Whether this node can be walked through.
  714. * @type boolean
  715. */
  716. this.walkable = (walkable === undefined ? true : walkable);
  717. }
  718.  
  719. module.exports = Node;
  720.  
  721. },{}],7:[function(_dereq_,module,exports){
  722. /**
  723. * Backtrace according to the parent records and return the path.
  724. * (including both start and end nodes)
  725. * @param {Node} node End node
  726. * @return {Array<Array<number>>} the path
  727. */
  728. function backtrace(node) {
  729. var path = [[node.x, node.y]];
  730. while (node.parent) {
  731. node = node.parent;
  732. path.push([node.x, node.y]);
  733. }
  734. return path.reverse();
  735. }
  736. exports.backtrace = backtrace;
  737.  
  738. /**
  739. * Backtrace from start and end node, and return the path.
  740. * (including both start and end nodes)
  741. * @param {Node}
  742. * @param {Node}
  743. */
  744. function biBacktrace(nodeA, nodeB) {
  745. var pathA = backtrace(nodeA),
  746. pathB = backtrace(nodeB);
  747. return pathA.concat(pathB.reverse());
  748. }
  749. exports.biBacktrace = biBacktrace;
  750.  
  751. /**
  752. * Compute the length of the path.
  753. * @param {Array<Array<number>>} path The path
  754. * @return {number} The length of the path
  755. */
  756. function pathLength(path) {
  757. var i, sum = 0, a, b, dx, dy;
  758. for (i = 1; i < path.length; ++i) {
  759. a = path[i - 1];
  760. b = path[i];
  761. dx = a[0] - b[0];
  762. dy = a[1] - b[1];
  763. sum += Math.sqrt(dx * dx + dy * dy);
  764. }
  765. return sum;
  766. }
  767. exports.pathLength = pathLength;
  768.  
  769.  
  770. /**
  771. * Given the start and end coordinates, return all the coordinates lying
  772. * on the line formed by these coordinates, based on Bresenham's algorithm.
  773. * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm#Simplification
  774. * @param {number} x0 Start x coordinate
  775. * @param {number} y0 Start y coordinate
  776. * @param {number} x1 End x coordinate
  777. * @param {number} y1 End y coordinate
  778. * @return {Array<Array<number>>} The coordinates on the line
  779. */
  780. function interpolate(x0, y0, x1, y1) {
  781. var abs = Math.abs,
  782. line = [],
  783. sx, sy, dx, dy, err, e2;
  784.  
  785. dx = abs(x1 - x0);
  786. dy = abs(y1 - y0);
  787.  
  788. sx = (x0 < x1) ? 1 : -1;
  789. sy = (y0 < y1) ? 1 : -1;
  790.  
  791. err = dx - dy;
  792.  
  793. while (true) {
  794. line.push([x0, y0]);
  795.  
  796. if (x0 === x1 && y0 === y1) {
  797. break;
  798. }
  799.  
  800. e2 = 2 * err;
  801. if (e2 > -dy) {
  802. err = err - dy;
  803. x0 = x0 + sx;
  804. }
  805. if (e2 < dx) {
  806. err = err + dx;
  807. y0 = y0 + sy;
  808. }
  809. }
  810.  
  811. return line;
  812. }
  813. exports.interpolate = interpolate;
  814.  
  815.  
  816. /**
  817. * Given a compressed path, return a new path that has all the segments
  818. * in it interpolated.
  819. * @param {Array<Array<number>>} path The path
  820. * @return {Array<Array<number>>} expanded path
  821. */
  822. function expandPath(path) {
  823. var expanded = [],
  824. len = path.length,
  825. coord0, coord1,
  826. interpolated,
  827. interpolatedLen,
  828. i, j;
  829.  
  830. if (len < 2) {
  831. return expanded;
  832. }
  833.  
  834. for (i = 0; i < len - 1; ++i) {
  835. coord0 = path[i];
  836. coord1 = path[i + 1];
  837.  
  838. interpolated = interpolate(coord0[0], coord0[1], coord1[0], coord1[1]);
  839. interpolatedLen = interpolated.length;
  840. for (j = 0; j < interpolatedLen - 1; ++j) {
  841. expanded.push(interpolated[j]);
  842. }
  843. }
  844. expanded.push(path[len - 1]);
  845.  
  846. return expanded;
  847. }
  848. exports.expandPath = expandPath;
  849.  
  850.  
  851. /**
  852. * Smoothen the give path.
  853. * The original path will not be modified; a new path will be returned.
  854. * @param {PF.Grid} grid
  855. * @param {Array<Array<number>>} path The path
  856. */
  857. function smoothenPath(grid, path) {
  858. var len = path.length,
  859. x0 = path[0][0], // path start x
  860. y0 = path[0][1], // path start y
  861. x1 = path[len - 1][0], // path end x
  862. y1 = path[len - 1][1], // path end y
  863. sx, sy, // current start coordinate
  864. ex, ey, // current end coordinate
  865. newPath,
  866. i, j, coord, line, testCoord, blocked;
  867.  
  868. sx = x0;
  869. sy = y0;
  870. newPath = [[sx, sy]];
  871.  
  872. for (i = 2; i < len; ++i) {
  873. coord = path[i];
  874. ex = coord[0];
  875. ey = coord[1];
  876. line = interpolate(sx, sy, ex, ey);
  877.  
  878. blocked = false;
  879. for (j = 1; j < line.length; ++j) {
  880. testCoord = line[j];
  881.  
  882. if (!grid.isWalkableAt(testCoord[0], testCoord[1])) {
  883. blocked = true;
  884. break;
  885. }
  886. }
  887. if (blocked) {
  888. lastValidCoord = path[i - 1];
  889. newPath.push(lastValidCoord);
  890. sx = lastValidCoord[0];
  891. sy = lastValidCoord[1];
  892. }
  893. }
  894. newPath.push([x1, y1]);
  895.  
  896. return newPath;
  897. }
  898. exports.smoothenPath = smoothenPath;
  899.  
  900.  
  901. /**
  902. * Compress a path, remove redundant nodes without altering the shape
  903. * The original path is not modified
  904. * @param {Array<Array<number>>} path The path
  905. * @return {Array<Array<number>>} The compressed path
  906. */
  907. function compressPath(path) {
  908.  
  909. // nothing to compress
  910. if(path.length < 3) {
  911. return path;
  912. }
  913.  
  914. var compressed = [],
  915. sx = path[0][0], // start x
  916. sy = path[0][1], // start y
  917. px = path[1][0], // second point x
  918. py = path[1][1], // second point y
  919. dx = px - sx, // direction between the two points
  920. dy = py - sy, // direction between the two points
  921. lx, ly,
  922. ldx, ldy,
  923. sq, i;
  924.  
  925. // normalize the direction
  926. sq = Math.sqrt(dx*dx + dy*dy);
  927. dx /= sq;
  928. dy /= sq;
  929.  
  930. // start the new path
  931. compressed.push([sx,sy]);
  932.  
  933. for(i = 2; i < path.length; i++) {
  934.  
  935. // store the last point
  936. lx = px;
  937. ly = py;
  938.  
  939. // store the last direction
  940. ldx = dx;
  941. ldy = dy;
  942.  
  943. // next point
  944. px = path[i][0];
  945. py = path[i][1];
  946.  
  947. // next direction
  948. dx = px - lx;
  949. dy = py - ly;
  950.  
  951. // normalize
  952. sq = Math.sqrt(dx*dx + dy*dy);
  953. dx /= sq;
  954. dy /= sq;
  955.  
  956. // if the direction has changed, store the point
  957. if ( dx !== ldx || dy !== ldy ) {
  958. compressed.push([lx,ly]);
  959. }
  960. }
  961.  
  962. // store the last point
  963. compressed.push([px,py]);
  964.  
  965. return compressed;
  966. }
  967. exports.compressPath = compressPath;
  968.  
  969. },{}],8:[function(_dereq_,module,exports){
  970. module.exports = {
  971. 'Heap' : _dereq_('heap'),
  972. 'Node' : _dereq_('./core/Node'),
  973. 'Grid' : _dereq_('./core/Grid'),
  974. 'Util' : _dereq_('./core/Util'),
  975. 'DiagonalMovement' : _dereq_('./core/DiagonalMovement'),
  976. 'Heuristic' : _dereq_('./core/Heuristic'),
  977. 'AStarFinder' : _dereq_('./finders/AStarFinder'),
  978. 'BestFirstFinder' : _dereq_('./finders/BestFirstFinder'),
  979. 'BreadthFirstFinder' : _dereq_('./finders/BreadthFirstFinder'),
  980. 'DijkstraFinder' : _dereq_('./finders/DijkstraFinder'),
  981. 'BiAStarFinder' : _dereq_('./finders/BiAStarFinder'),
  982. 'BiBestFirstFinder' : _dereq_('./finders/BiBestFirstFinder'),
  983. 'BiBreadthFirstFinder' : _dereq_('./finders/BiBreadthFirstFinder'),
  984. 'BiDijkstraFinder' : _dereq_('./finders/BiDijkstraFinder'),
  985. 'IDAStarFinder' : _dereq_('./finders/IDAStarFinder'),
  986. 'JumpPointFinder' : _dereq_('./finders/JumpPointFinder'),
  987. };
  988.  
  989. },{"./core/DiagonalMovement":3,"./core/Grid":4,"./core/Heuristic":5,"./core/Node":6,"./core/Util":7,"./finders/AStarFinder":9,"./finders/BestFirstFinder":10,"./finders/BiAStarFinder":11,"./finders/BiBestFirstFinder":12,"./finders/BiBreadthFirstFinder":13,"./finders/BiDijkstraFinder":14,"./finders/BreadthFirstFinder":15,"./finders/DijkstraFinder":16,"./finders/IDAStarFinder":17,"./finders/JumpPointFinder":22,"heap":1}],9:[function(_dereq_,module,exports){
  990. var Heap = _dereq_('heap');
  991. var Util = _dereq_('../core/Util');
  992. var Heuristic = _dereq_('../core/Heuristic');
  993. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  994.  
  995. /**
  996. * A* path-finder. Based upon https://github.com/bgrins/javascript-astar
  997. * @constructor
  998. * @param {Object} opt
  999. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1000. * Deprecated, use diagonalMovement instead.
  1001. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1002. * block corners. Deprecated, use diagonalMovement instead.
  1003. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1004. * @param {function} opt.heuristic Heuristic function to estimate the distance
  1005. * (defaults to manhattan).
  1006. * @param {number} opt.weight Weight to apply to the heuristic to allow for
  1007. * suboptimal paths, in order to speed up the search.
  1008. */
  1009. function AStarFinder(opt) {
  1010. opt = opt || {};
  1011. this.allowDiagonal = opt.allowDiagonal;
  1012. this.dontCrossCorners = opt.dontCrossCorners;
  1013. this.heuristic = opt.heuristic || Heuristic.manhattan;
  1014. this.weight = opt.weight || 1;
  1015. this.diagonalMovement = opt.diagonalMovement;
  1016.  
  1017. if (!this.diagonalMovement) {
  1018. if (!this.allowDiagonal) {
  1019. this.diagonalMovement = DiagonalMovement.Never;
  1020. } else {
  1021. if (this.dontCrossCorners) {
  1022. this.diagonalMovement = DiagonalMovement.OnlyWhenNoObstacles;
  1023. } else {
  1024. this.diagonalMovement = DiagonalMovement.IfAtMostOneObstacle;
  1025. }
  1026. }
  1027. }
  1028.  
  1029. // When diagonal movement is allowed the manhattan heuristic is not
  1030. //admissible. It should be octile instead
  1031. if (this.diagonalMovement === DiagonalMovement.Never) {
  1032. this.heuristic = opt.heuristic || Heuristic.manhattan;
  1033. } else {
  1034. this.heuristic = opt.heuristic || Heuristic.octile;
  1035. }
  1036. }
  1037.  
  1038. /**
  1039. * Find and return the the path.
  1040. * @return {Array<Array<number>>} The path, including both start and
  1041. * end positions.
  1042. */
  1043. AStarFinder.prototype.findPath = function(startX, startY, endX, endY, grid) {
  1044. var openList = new Heap(function(nodeA, nodeB) {
  1045. return nodeA.f - nodeB.f;
  1046. }),
  1047. startNode = grid.getNodeAt(startX, startY),
  1048. endNode = grid.getNodeAt(endX, endY),
  1049. heuristic = this.heuristic,
  1050. diagonalMovement = this.diagonalMovement,
  1051. weight = this.weight,
  1052. abs = Math.abs, SQRT2 = Math.SQRT2,
  1053. node, neighbors, neighbor, i, l, x, y, ng;
  1054.  
  1055. // set the `g` and `f` value of the start node to be 0
  1056. startNode.g = 0;
  1057. startNode.f = 0;
  1058.  
  1059. // push the start node into the open list
  1060. openList.push(startNode);
  1061. startNode.opened = true;
  1062.  
  1063. // while the open list is not empty
  1064. while (!openList.empty()) {
  1065. // pop the position of node which has the minimum `f` value.
  1066. node = openList.pop();
  1067. node.closed = true;
  1068.  
  1069. // if reached the end position, construct the path and return it
  1070. if (node === endNode) {
  1071. return Util.backtrace(endNode);
  1072. }
  1073.  
  1074. // get neigbours of the current node
  1075. neighbors = grid.getNeighbors(node, diagonalMovement);
  1076. for (i = 0, l = neighbors.length; i < l; ++i) {
  1077. neighbor = neighbors[i];
  1078.  
  1079. if (neighbor.closed) {
  1080. continue;
  1081. }
  1082.  
  1083. x = neighbor.x;
  1084. y = neighbor.y;
  1085.  
  1086. // get the distance between current node and the neighbor
  1087. // and calculate the next g score
  1088. ng = node.g + ((x - node.x === 0 || y - node.y === 0) ? 1 : SQRT2);
  1089.  
  1090. // check if the neighbor has not been inspected yet, or
  1091. // can be reached with smaller cost from the current node
  1092. if (!neighbor.opened || ng < neighbor.g) {
  1093. neighbor.g = ng;
  1094. neighbor.h = neighbor.h || weight * heuristic(abs(x - endX), abs(y - endY));
  1095. neighbor.f = neighbor.g + neighbor.h;
  1096. neighbor.parent = node;
  1097.  
  1098. if (!neighbor.opened) {
  1099. openList.push(neighbor);
  1100. neighbor.opened = true;
  1101. } else {
  1102. // the neighbor can be reached with smaller cost.
  1103. // Since its f value has been updated, we have to
  1104. // update its position in the open list
  1105. openList.updateItem(neighbor);
  1106. }
  1107. }
  1108. } // end for each neighbor
  1109. } // end while not open list empty
  1110.  
  1111. // fail to find the path
  1112. return [];
  1113. };
  1114.  
  1115. module.exports = AStarFinder;
  1116.  
  1117. },{"../core/DiagonalMovement":3,"../core/Heuristic":5,"../core/Util":7,"heap":1}],10:[function(_dereq_,module,exports){
  1118. var AStarFinder = _dereq_('./AStarFinder');
  1119.  
  1120. /**
  1121. * Best-First-Search path-finder.
  1122. * @constructor
  1123. * @extends AStarFinder
  1124. * @param {Object} opt
  1125. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1126. * Deprecated, use diagonalMovement instead.
  1127. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1128. * block corners. Deprecated, use diagonalMovement instead.
  1129. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1130. * @param {function} opt.heuristic Heuristic function to estimate the distance
  1131. * (defaults to manhattan).
  1132. */
  1133. function BestFirstFinder(opt) {
  1134. AStarFinder.call(this, opt);
  1135.  
  1136. var orig = this.heuristic;
  1137. this.heuristic = function(dx, dy) {
  1138. return orig(dx, dy) * 1000000;
  1139. };
  1140. }
  1141.  
  1142. BestFirstFinder.prototype = new AStarFinder();
  1143. BestFirstFinder.prototype.constructor = BestFirstFinder;
  1144.  
  1145. module.exports = BestFirstFinder;
  1146.  
  1147. },{"./AStarFinder":9}],11:[function(_dereq_,module,exports){
  1148. var Heap = _dereq_('heap');
  1149. var Util = _dereq_('../core/Util');
  1150. var Heuristic = _dereq_('../core/Heuristic');
  1151. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  1152.  
  1153. /**
  1154. * A* path-finder.
  1155. * based upon https://github.com/bgrins/javascript-astar
  1156. * @constructor
  1157. * @param {Object} opt
  1158. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1159. * Deprecated, use diagonalMovement instead.
  1160. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1161. * block corners. Deprecated, use diagonalMovement instead.
  1162. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1163. * @param {function} opt.heuristic Heuristic function to estimate the distance
  1164. * (defaults to manhattan).
  1165. * @param {number} opt.weight Weight to apply to the heuristic to allow for
  1166. * suboptimal paths, in order to speed up the search.
  1167. */
  1168. function BiAStarFinder(opt) {
  1169. opt = opt || {};
  1170. this.allowDiagonal = opt.allowDiagonal;
  1171. this.dontCrossCorners = opt.dontCrossCorners;
  1172. this.diagonalMovement = opt.diagonalMovement;
  1173. this.heuristic = opt.heuristic || Heuristic.manhattan;
  1174. this.weight = opt.weight || 1;
  1175.  
  1176. if (!this.diagonalMovement) {
  1177. if (!this.allowDiagonal) {
  1178. this.diagonalMovement = DiagonalMovement.Never;
  1179. } else {
  1180. if (this.dontCrossCorners) {
  1181. this.diagonalMovement = DiagonalMovement.OnlyWhenNoObstacles;
  1182. } else {
  1183. this.diagonalMovement = DiagonalMovement.IfAtMostOneObstacle;
  1184. }
  1185. }
  1186. }
  1187.  
  1188. //When diagonal movement is allowed the manhattan heuristic is not admissible
  1189. //It should be octile instead
  1190. if (this.diagonalMovement === DiagonalMovement.Never) {
  1191. this.heuristic = opt.heuristic || Heuristic.manhattan;
  1192. } else {
  1193. this.heuristic = opt.heuristic || Heuristic.octile;
  1194. }
  1195. }
  1196.  
  1197. /**
  1198. * Find and return the the path.
  1199. * @return {Array<Array<number>>} The path, including both start and
  1200. * end positions.
  1201. */
  1202. BiAStarFinder.prototype.findPath = function(startX, startY, endX, endY, grid) {
  1203. var cmp = function(nodeA, nodeB) {
  1204. return nodeA.f - nodeB.f;
  1205. },
  1206. startOpenList = new Heap(cmp),
  1207. endOpenList = new Heap(cmp),
  1208. startNode = grid.getNodeAt(startX, startY),
  1209. endNode = grid.getNodeAt(endX, endY),
  1210. heuristic = this.heuristic,
  1211. diagonalMovement = this.diagonalMovement,
  1212. weight = this.weight,
  1213. abs = Math.abs, SQRT2 = Math.SQRT2,
  1214. node, neighbors, neighbor, i, l, x, y, ng,
  1215. BY_START = 1, BY_END = 2;
  1216.  
  1217. // set the `g` and `f` value of the start node to be 0
  1218. // and push it into the start open list
  1219. startNode.g = 0;
  1220. startNode.f = 0;
  1221. startOpenList.push(startNode);
  1222. startNode.opened = BY_START;
  1223.  
  1224. // set the `g` and `f` value of the end node to be 0
  1225. // and push it into the open open list
  1226. endNode.g = 0;
  1227. endNode.f = 0;
  1228. endOpenList.push(endNode);
  1229. endNode.opened = BY_END;
  1230.  
  1231. // while both the open lists are not empty
  1232. while (!startOpenList.empty() && !endOpenList.empty()) {
  1233.  
  1234. // pop the position of start node which has the minimum `f` value.
  1235. node = startOpenList.pop();
  1236. node.closed = true;
  1237.  
  1238. // get neigbours of the current node
  1239. neighbors = grid.getNeighbors(node, diagonalMovement);
  1240. for (i = 0, l = neighbors.length; i < l; ++i) {
  1241. neighbor = neighbors[i];
  1242.  
  1243. if (neighbor.closed) {
  1244. continue;
  1245. }
  1246. if (neighbor.opened === BY_END) {
  1247. return Util.biBacktrace(node, neighbor);
  1248. }
  1249.  
  1250. x = neighbor.x;
  1251. y = neighbor.y;
  1252.  
  1253. // get the distance between current node and the neighbor
  1254. // and calculate the next g score
  1255. ng = node.g + ((x - node.x === 0 || y - node.y === 0) ? 1 : SQRT2);
  1256.  
  1257. // check if the neighbor has not been inspected yet, or
  1258. // can be reached with smaller cost from the current node
  1259. if (!neighbor.opened || ng < neighbor.g) {
  1260. neighbor.g = ng;
  1261. neighbor.h = neighbor.h ||
  1262. weight * heuristic(abs(x - endX), abs(y - endY));
  1263. neighbor.f = neighbor.g + neighbor.h;
  1264. neighbor.parent = node;
  1265.  
  1266. if (!neighbor.opened) {
  1267. startOpenList.push(neighbor);
  1268. neighbor.opened = BY_START;
  1269. } else {
  1270. // the neighbor can be reached with smaller cost.
  1271. // Since its f value has been updated, we have to
  1272. // update its position in the open list
  1273. startOpenList.updateItem(neighbor);
  1274. }
  1275. }
  1276. } // end for each neighbor
  1277.  
  1278.  
  1279. // pop the position of end node which has the minimum `f` value.
  1280. node = endOpenList.pop();
  1281. node.closed = true;
  1282.  
  1283. // get neigbours of the current node
  1284. neighbors = grid.getNeighbors(node, diagonalMovement);
  1285. for (i = 0, l = neighbors.length; i < l; ++i) {
  1286. neighbor = neighbors[i];
  1287.  
  1288. if (neighbor.closed) {
  1289. continue;
  1290. }
  1291. if (neighbor.opened === BY_START) {
  1292. return Util.biBacktrace(neighbor, node);
  1293. }
  1294.  
  1295. x = neighbor.x;
  1296. y = neighbor.y;
  1297.  
  1298. // get the distance between current node and the neighbor
  1299. // and calculate the next g score
  1300. ng = node.g + ((x - node.x === 0 || y - node.y === 0) ? 1 : SQRT2);
  1301.  
  1302. // check if the neighbor has not been inspected yet, or
  1303. // can be reached with smaller cost from the current node
  1304. if (!neighbor.opened || ng < neighbor.g) {
  1305. neighbor.g = ng;
  1306. neighbor.h = neighbor.h ||
  1307. weight * heuristic(abs(x - startX), abs(y - startY));
  1308. neighbor.f = neighbor.g + neighbor.h;
  1309. neighbor.parent = node;
  1310.  
  1311. if (!neighbor.opened) {
  1312. endOpenList.push(neighbor);
  1313. neighbor.opened = BY_END;
  1314. } else {
  1315. // the neighbor can be reached with smaller cost.
  1316. // Since its f value has been updated, we have to
  1317. // update its position in the open list
  1318. endOpenList.updateItem(neighbor);
  1319. }
  1320. }
  1321. } // end for each neighbor
  1322. } // end while not open list empty
  1323.  
  1324. // fail to find the path
  1325. return [];
  1326. };
  1327.  
  1328. module.exports = BiAStarFinder;
  1329.  
  1330. },{"../core/DiagonalMovement":3,"../core/Heuristic":5,"../core/Util":7,"heap":1}],12:[function(_dereq_,module,exports){
  1331. var BiAStarFinder = _dereq_('./BiAStarFinder');
  1332.  
  1333. /**
  1334. * Bi-direcitional Best-First-Search path-finder.
  1335. * @constructor
  1336. * @extends BiAStarFinder
  1337. * @param {Object} opt
  1338. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1339. * Deprecated, use diagonalMovement instead.
  1340. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1341. * block corners. Deprecated, use diagonalMovement instead.
  1342. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1343. * @param {function} opt.heuristic Heuristic function to estimate the distance
  1344. * (defaults to manhattan).
  1345. */
  1346. function BiBestFirstFinder(opt) {
  1347. BiAStarFinder.call(this, opt);
  1348.  
  1349. var orig = this.heuristic;
  1350. this.heuristic = function(dx, dy) {
  1351. return orig(dx, dy) * 1000000;
  1352. };
  1353. }
  1354.  
  1355. BiBestFirstFinder.prototype = new BiAStarFinder();
  1356. BiBestFirstFinder.prototype.constructor = BiBestFirstFinder;
  1357.  
  1358. module.exports = BiBestFirstFinder;
  1359.  
  1360. },{"./BiAStarFinder":11}],13:[function(_dereq_,module,exports){
  1361. var Util = _dereq_('../core/Util');
  1362. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  1363.  
  1364. /**
  1365. * Bi-directional Breadth-First-Search path finder.
  1366. * @constructor
  1367. * @param {object} opt
  1368. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1369. * Deprecated, use diagonalMovement instead.
  1370. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1371. * block corners. Deprecated, use diagonalMovement instead.
  1372. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1373. */
  1374. function BiBreadthFirstFinder(opt) {
  1375. opt = opt || {};
  1376. this.allowDiagonal = opt.allowDiagonal;
  1377. this.dontCrossCorners = opt.dontCrossCorners;
  1378. this.diagonalMovement = opt.diagonalMovement;
  1379.  
  1380. if (!this.diagonalMovement) {
  1381. if (!this.allowDiagonal) {
  1382. this.diagonalMovement = DiagonalMovement.Never;
  1383. } else {
  1384. if (this.dontCrossCorners) {
  1385. this.diagonalMovement = DiagonalMovement.OnlyWhenNoObstacles;
  1386. } else {
  1387. this.diagonalMovement = DiagonalMovement.IfAtMostOneObstacle;
  1388. }
  1389. }
  1390. }
  1391. }
  1392.  
  1393.  
  1394. /**
  1395. * Find and return the the path.
  1396. * @return {Array<Array<number>>} The path, including both start and
  1397. * end positions.
  1398. */
  1399. BiBreadthFirstFinder.prototype.findPath = function(startX, startY, endX, endY, grid) {
  1400. var startNode = grid.getNodeAt(startX, startY),
  1401. endNode = grid.getNodeAt(endX, endY),
  1402. startOpenList = [], endOpenList = [],
  1403. neighbors, neighbor, node,
  1404. diagonalMovement = this.diagonalMovement,
  1405. BY_START = 0, BY_END = 1,
  1406. i, l;
  1407.  
  1408. // push the start and end nodes into the queues
  1409. startOpenList.push(startNode);
  1410. startNode.opened = true;
  1411. startNode.by = BY_START;
  1412.  
  1413. endOpenList.push(endNode);
  1414. endNode.opened = true;
  1415. endNode.by = BY_END;
  1416.  
  1417. // while both the queues are not empty
  1418. while (startOpenList.length && endOpenList.length) {
  1419.  
  1420. // expand start open list
  1421.  
  1422. node = startOpenList.shift();
  1423. node.closed = true;
  1424.  
  1425. neighbors = grid.getNeighbors(node, diagonalMovement);
  1426. for (i = 0, l = neighbors.length; i < l; ++i) {
  1427. neighbor = neighbors[i];
  1428.  
  1429. if (neighbor.closed) {
  1430. continue;
  1431. }
  1432. if (neighbor.opened) {
  1433. // if this node has been inspected by the reversed search,
  1434. // then a path is found.
  1435. if (neighbor.by === BY_END) {
  1436. return Util.biBacktrace(node, neighbor);
  1437. }
  1438. continue;
  1439. }
  1440. startOpenList.push(neighbor);
  1441. neighbor.parent = node;
  1442. neighbor.opened = true;
  1443. neighbor.by = BY_START;
  1444. }
  1445.  
  1446. // expand end open list
  1447.  
  1448. node = endOpenList.shift();
  1449. node.closed = true;
  1450.  
  1451. neighbors = grid.getNeighbors(node, diagonalMovement);
  1452. for (i = 0, l = neighbors.length; i < l; ++i) {
  1453. neighbor = neighbors[i];
  1454.  
  1455. if (neighbor.closed) {
  1456. continue;
  1457. }
  1458. if (neighbor.opened) {
  1459. if (neighbor.by === BY_START) {
  1460. return Util.biBacktrace(neighbor, node);
  1461. }
  1462. continue;
  1463. }
  1464. endOpenList.push(neighbor);
  1465. neighbor.parent = node;
  1466. neighbor.opened = true;
  1467. neighbor.by = BY_END;
  1468. }
  1469. }
  1470.  
  1471. // fail to find the path
  1472. return [];
  1473. };
  1474.  
  1475. module.exports = BiBreadthFirstFinder;
  1476.  
  1477. },{"../core/DiagonalMovement":3,"../core/Util":7}],14:[function(_dereq_,module,exports){
  1478. var BiAStarFinder = _dereq_('./BiAStarFinder');
  1479.  
  1480. /**
  1481. * Bi-directional Dijkstra path-finder.
  1482. * @constructor
  1483. * @extends BiAStarFinder
  1484. * @param {Object} opt
  1485. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1486. * Deprecated, use diagonalMovement instead.
  1487. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1488. * block corners. Deprecated, use diagonalMovement instead.
  1489. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1490. */
  1491. function BiDijkstraFinder(opt) {
  1492. BiAStarFinder.call(this, opt);
  1493. this.heuristic = function(dx, dy) {
  1494. return 0;
  1495. };
  1496. }
  1497.  
  1498. BiDijkstraFinder.prototype = new BiAStarFinder();
  1499. BiDijkstraFinder.prototype.constructor = BiDijkstraFinder;
  1500.  
  1501. module.exports = BiDijkstraFinder;
  1502.  
  1503. },{"./BiAStarFinder":11}],15:[function(_dereq_,module,exports){
  1504. var Util = _dereq_('../core/Util');
  1505. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  1506.  
  1507. /**
  1508. * Breadth-First-Search path finder.
  1509. * @constructor
  1510. * @param {Object} opt
  1511. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1512. * Deprecated, use diagonalMovement instead.
  1513. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1514. * block corners. Deprecated, use diagonalMovement instead.
  1515. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1516. */
  1517. function BreadthFirstFinder(opt) {
  1518. opt = opt || {};
  1519. this.allowDiagonal = opt.allowDiagonal;
  1520. this.dontCrossCorners = opt.dontCrossCorners;
  1521. this.diagonalMovement = opt.diagonalMovement;
  1522.  
  1523. if (!this.diagonalMovement) {
  1524. if (!this.allowDiagonal) {
  1525. this.diagonalMovement = DiagonalMovement.Never;
  1526. } else {
  1527. if (this.dontCrossCorners) {
  1528. this.diagonalMovement = DiagonalMovement.OnlyWhenNoObstacles;
  1529. } else {
  1530. this.diagonalMovement = DiagonalMovement.IfAtMostOneObstacle;
  1531. }
  1532. }
  1533. }
  1534. }
  1535.  
  1536. /**
  1537. * Find and return the the path.
  1538. * @return {Array<Array<number>>} The path, including both start and
  1539. * end positions.
  1540. */
  1541. BreadthFirstFinder.prototype.findPath = function(startX, startY, endX, endY, grid) {
  1542. var openList = [],
  1543. diagonalMovement = this.diagonalMovement,
  1544. startNode = grid.getNodeAt(startX, startY),
  1545. endNode = grid.getNodeAt(endX, endY),
  1546. neighbors, neighbor, node, i, l;
  1547.  
  1548. // push the start pos into the queue
  1549. openList.push(startNode);
  1550. startNode.opened = true;
  1551.  
  1552. // while the queue is not empty
  1553. while (openList.length) {
  1554. // take the front node from the queue
  1555. node = openList.shift();
  1556. node.closed = true;
  1557.  
  1558. // reached the end position
  1559. if (node === endNode) {
  1560. return Util.backtrace(endNode);
  1561. }
  1562.  
  1563. neighbors = grid.getNeighbors(node, diagonalMovement);
  1564. for (i = 0, l = neighbors.length; i < l; ++i) {
  1565. neighbor = neighbors[i];
  1566.  
  1567. // skip this neighbor if it has been inspected before
  1568. if (neighbor.closed || neighbor.opened) {
  1569. continue;
  1570. }
  1571.  
  1572. openList.push(neighbor);
  1573. neighbor.opened = true;
  1574. neighbor.parent = node;
  1575. }
  1576. }
  1577.  
  1578. // fail to find the path
  1579. return [];
  1580. };
  1581.  
  1582. module.exports = BreadthFirstFinder;
  1583.  
  1584. },{"../core/DiagonalMovement":3,"../core/Util":7}],16:[function(_dereq_,module,exports){
  1585. var AStarFinder = _dereq_('./AStarFinder');
  1586.  
  1587. /**
  1588. * Dijkstra path-finder.
  1589. * @constructor
  1590. * @extends AStarFinder
  1591. * @param {Object} opt
  1592. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1593. * Deprecated, use diagonalMovement instead.
  1594. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1595. * block corners. Deprecated, use diagonalMovement instead.
  1596. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1597. */
  1598. function DijkstraFinder(opt) {
  1599. AStarFinder.call(this, opt);
  1600. this.heuristic = function(dx, dy) {
  1601. return 0;
  1602. };
  1603. }
  1604.  
  1605. DijkstraFinder.prototype = new AStarFinder();
  1606. DijkstraFinder.prototype.constructor = DijkstraFinder;
  1607.  
  1608. module.exports = DijkstraFinder;
  1609.  
  1610. },{"./AStarFinder":9}],17:[function(_dereq_,module,exports){
  1611. var Util = _dereq_('../core/Util');
  1612. var Heuristic = _dereq_('../core/Heuristic');
  1613. var Node = _dereq_('../core/Node');
  1614. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  1615.  
  1616. /**
  1617. * Iterative Deeping A Star (IDA*) path-finder.
  1618. *
  1619. * Recursion based on:
  1620. * http://www.apl.jhu.edu/~hall/AI-Programming/IDA-Star.html
  1621. *
  1622. * Path retracing based on:
  1623. * V. Nageshwara Rao, Vipin Kumar and K. Ramesh
  1624. * "A Parallel Implementation of Iterative-Deeping-A*", January 1987.
  1625. * ftp://ftp.cs.utexas.edu/.snapshot/hourly.1/pub/AI-Lab/tech-reports/UT-AI-TR-87-46.pdf
  1626. *
  1627. * @author Gerard Meier (www.gerardmeier.com)
  1628. *
  1629. * @constructor
  1630. * @param {Object} opt
  1631. * @param {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
  1632. * Deprecated, use diagonalMovement instead.
  1633. * @param {boolean} opt.dontCrossCorners Disallow diagonal movement touching
  1634. * block corners. Deprecated, use diagonalMovement instead.
  1635. * @param {DiagonalMovement} opt.diagonalMovement Allowed diagonal movement.
  1636. * @param {function} opt.heuristic Heuristic function to estimate the distance
  1637. * (defaults to manhattan).
  1638. * @param {number} opt.weight Weight to apply to the heuristic to allow for
  1639. * suboptimal paths, in order to speed up the search.
  1640. * @param {boolean} opt.trackRecursion Whether to track recursion for
  1641. * statistical purposes.
  1642. * @param {number} opt.timeLimit Maximum execution time. Use <= 0 for infinite.
  1643. */
  1644. function IDAStarFinder(opt) {
  1645. opt = opt || {};
  1646. this.allowDiagonal = opt.allowDiagonal;
  1647. this.dontCrossCorners = opt.dontCrossCorners;
  1648. this.diagonalMovement = opt.diagonalMovement;
  1649. this.heuristic = opt.heuristic || Heuristic.manhattan;
  1650. this.weight = opt.weight || 1;
  1651. this.trackRecursion = opt.trackRecursion || false;
  1652. this.timeLimit = opt.timeLimit || Infinity; // Default: no time limit.
  1653.  
  1654. if (!this.diagonalMovement) {
  1655. if (!this.allowDiagonal) {
  1656. this.diagonalMovement = DiagonalMovement.Never;
  1657. } else {
  1658. if (this.dontCrossCorners) {
  1659. this.diagonalMovement = DiagonalMovement.OnlyWhenNoObstacles;
  1660. } else {
  1661. this.diagonalMovement = DiagonalMovement.IfAtMostOneObstacle;
  1662. }
  1663. }
  1664. }
  1665.  
  1666. // When diagonal movement is allowed the manhattan heuristic is not
  1667. // admissible, it should be octile instead
  1668. if (this.diagonalMovement === DiagonalMovement.Never) {
  1669. this.heuristic = opt.heuristic || Heuristic.manhattan;
  1670. } else {
  1671. this.heuristic = opt.heuristic || Heuristic.octile;
  1672. }
  1673. }
  1674.  
  1675. /**
  1676. * Find and return the the path. When an empty array is returned, either
  1677. * no path is possible, or the maximum execution time is reached.
  1678. *
  1679. * @return {Array<Array<number>>} The path, including both start and
  1680. * end positions.
  1681. */
  1682. IDAStarFinder.prototype.findPath = function(startX, startY, endX, endY, grid) {
  1683. // Used for statistics:
  1684. var nodesVisited = 0;
  1685.  
  1686. // Execution time limitation:
  1687. var startTime = new Date().getTime();
  1688.  
  1689. // Heuristic helper:
  1690. var h = function(a, b) {
  1691. return this.heuristic(Math.abs(b.x - a.x), Math.abs(b.y - a.y));
  1692. }.bind(this);
  1693.  
  1694. // Step cost from a to b:
  1695. var cost = function(a, b) {
  1696. return (a.x === b.x || a.y === b.y) ? 1 : Math.SQRT2;
  1697. };
  1698.  
  1699. /**
  1700. * IDA* search implementation.
  1701. *
  1702. * @param {Node} The node currently expanding from.
  1703. * @param {number} Cost to reach the given node.
  1704. * @param {number} Maximum search depth (cut-off value).
  1705. * @param {Array<Array<number>>} The found route.
  1706. * @param {number} Recursion depth.
  1707. *
  1708. * @return {Object} either a number with the new optimal cut-off depth,
  1709. * or a valid node instance, in which case a path was found.
  1710. */
  1711. var search = function(node, g, cutoff, route, depth) {
  1712. nodesVisited++;
  1713.  
  1714. // Enforce timelimit:
  1715. if (this.timeLimit > 0 &&
  1716. new Date().getTime() - startTime > this.timeLimit * 1000) {
  1717. // Enforced as "path-not-found".
  1718. return Infinity;
  1719. }
  1720.  
  1721. var f = g + h(node, end) * this.weight;
  1722.  
  1723. // We've searched too deep for this iteration.
  1724. if (f > cutoff) {
  1725. return f;
  1726. }
  1727.  
  1728. if (node == end) {
  1729. route[depth] = [node.x, node.y];
  1730. return node;
  1731. }
  1732.  
  1733. var min, t, k, neighbour;
  1734.  
  1735. var neighbours = grid.getNeighbors(node, this.diagonalMovement);
  1736.  
  1737. // Sort the neighbours, gives nicer paths. But, this deviates
  1738. // from the original algorithm - so I left it out.
  1739. //neighbours.sort(function(a, b){
  1740. // return h(a, end) - h(b, end);
  1741. //});
  1742.  
  1743.  
  1744. /*jshint -W084 *///Disable warning: Expected a conditional expression and instead saw an assignment
  1745. for (k = 0, min = Infinity; neighbour = neighbours[k]; ++k) {
  1746. /*jshint +W084 *///Enable warning: Expected a conditional expression and instead saw an assignment
  1747. if (this.trackRecursion) {
  1748. // Retain a copy for visualisation. Due to recursion, this
  1749. // node may be part of other paths too.
  1750. neighbour.retainCount = neighbour.retainCount + 1 || 1;
  1751.  
  1752. if(neighbour.tested !== true) {
  1753. neighbour.tested = true;
  1754. }
  1755. }
  1756.  
  1757. t = search(neighbour, g + cost(node, neighbour), cutoff, route, depth + 1);
  1758.  
  1759. if (t instanceof Node) {
  1760. route[depth] = [node.x, node.y];
  1761.  
  1762. // For a typical A* linked list, this would work:
  1763. // neighbour.parent = node;
  1764. return t;
  1765. }
  1766.  
  1767. // Decrement count, then determine whether it's actually closed.
  1768. if (this.trackRecursion && (--neighbour.retainCount) === 0) {
  1769. neighbour.tested = false;
  1770. }
  1771.  
  1772. if (t < min) {
  1773. min = t;
  1774. }
  1775. }
  1776.  
  1777. return min;
  1778.  
  1779. }.bind(this);
  1780.  
  1781. // Node instance lookups:
  1782. var start = grid.getNodeAt(startX, startY);
  1783. var end = grid.getNodeAt(endX, endY);
  1784.  
  1785. // Initial search depth, given the typical heuristic contraints,
  1786. // there should be no cheaper route possible.
  1787. var cutOff = h(start, end);
  1788.  
  1789. var j, route, t;
  1790.  
  1791. // With an overflow protection.
  1792. for (j = 0; true; ++j) {
  1793.  
  1794. route = [];
  1795.  
  1796. // Search till cut-off depth:
  1797. t = search(start, 0, cutOff, route, 0);
  1798.  
  1799. // Route not possible, or not found in time limit.
  1800. if (t === Infinity) {
  1801. return [];
  1802. }
  1803.  
  1804. // If t is a node, it's also the end node. Route is now
  1805. // populated with a valid path to the end node.
  1806. if (t instanceof Node) {
  1807. return route;
  1808. }
  1809.  
  1810. // Try again, this time with a deeper cut-off. The t score
  1811. // is the closest we got to the end node.
  1812. cutOff = t;
  1813. }
  1814.  
  1815. // This _should_ never to be reached.
  1816. return [];
  1817. };
  1818.  
  1819. module.exports = IDAStarFinder;
  1820.  
  1821. },{"../core/DiagonalMovement":3,"../core/Heuristic":5,"../core/Node":6,"../core/Util":7}],18:[function(_dereq_,module,exports){
  1822. /**
  1823. * @author imor / https://github.com/imor
  1824. */
  1825. var JumpPointFinderBase = _dereq_('./JumpPointFinderBase');
  1826. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  1827.  
  1828. /**
  1829. * Path finder using the Jump Point Search algorithm which always moves
  1830. * diagonally irrespective of the number of obstacles.
  1831. */
  1832. function JPFAlwaysMoveDiagonally(opt) {
  1833. JumpPointFinderBase.call(this, opt);
  1834. }
  1835.  
  1836. JPFAlwaysMoveDiagonally.prototype = new JumpPointFinderBase();
  1837. JPFAlwaysMoveDiagonally.prototype.constructor = JPFAlwaysMoveDiagonally;
  1838.  
  1839. /**
  1840. * Search recursively in the direction (parent -> child), stopping only when a
  1841. * jump point is found.
  1842. * @protected
  1843. * @return {Array<Array<number>>} The x, y coordinate of the jump point
  1844. * found, or null if not found
  1845. */
  1846. JPFAlwaysMoveDiagonally.prototype._jump = function(x, y, px, py) {
  1847. var grid = this.grid,
  1848. dx = x - px, dy = y - py;
  1849.  
  1850. if (!grid.isWalkableAt(x, y)) {
  1851. return null;
  1852. }
  1853.  
  1854. if(this.trackJumpRecursion === true) {
  1855. grid.getNodeAt(x, y).tested = true;
  1856. }
  1857.  
  1858. if (grid.getNodeAt(x, y) === this.endNode) {
  1859. return [x, y];
  1860. }
  1861.  
  1862. // check for forced neighbors
  1863. // along the diagonal
  1864. if (dx !== 0 && dy !== 0) {
  1865. if ((grid.isWalkableAt(x - dx, y + dy) && !grid.isWalkableAt(x - dx, y)) ||
  1866. (grid.isWalkableAt(x + dx, y - dy) && !grid.isWalkableAt(x, y - dy))) {
  1867. return [x, y];
  1868. }
  1869. // when moving diagonally, must check for vertical/horizontal jump points
  1870. if (this._jump(x + dx, y, x, y) || this._jump(x, y + dy, x, y)) {
  1871. return [x, y];
  1872. }
  1873. }
  1874. // horizontally/vertically
  1875. else {
  1876. if( dx !== 0 ) { // moving along x
  1877. if((grid.isWalkableAt(x + dx, y + 1) && !grid.isWalkableAt(x, y + 1)) ||
  1878. (grid.isWalkableAt(x + dx, y - 1) && !grid.isWalkableAt(x, y - 1))) {
  1879. return [x, y];
  1880. }
  1881. }
  1882. else {
  1883. if((grid.isWalkableAt(x + 1, y + dy) && !grid.isWalkableAt(x + 1, y)) ||
  1884. (grid.isWalkableAt(x - 1, y + dy) && !grid.isWalkableAt(x - 1, y))) {
  1885. return [x, y];
  1886. }
  1887. }
  1888. }
  1889.  
  1890. return this._jump(x + dx, y + dy, x, y);
  1891. };
  1892.  
  1893. /**
  1894. * Find the neighbors for the given node. If the node has a parent,
  1895. * prune the neighbors based on the jump point search algorithm, otherwise
  1896. * return all available neighbors.
  1897. * @return {Array<Array<number>>} The neighbors found.
  1898. */
  1899. JPFAlwaysMoveDiagonally.prototype._findNeighbors = function(node) {
  1900. var parent = node.parent,
  1901. x = node.x, y = node.y,
  1902. grid = this.grid,
  1903. px, py, nx, ny, dx, dy,
  1904. neighbors = [], neighborNodes, neighborNode, i, l;
  1905.  
  1906. // directed pruning: can ignore most neighbors, unless forced.
  1907. if (parent) {
  1908. px = parent.x;
  1909. py = parent.y;
  1910. // get the normalized direction of travel
  1911. dx = (x - px) / Math.max(Math.abs(x - px), 1);
  1912. dy = (y - py) / Math.max(Math.abs(y - py), 1);
  1913.  
  1914. // search diagonally
  1915. if (dx !== 0 && dy !== 0) {
  1916. if (grid.isWalkableAt(x, y + dy)) {
  1917. neighbors.push([x, y + dy]);
  1918. }
  1919. if (grid.isWalkableAt(x + dx, y)) {
  1920. neighbors.push([x + dx, y]);
  1921. }
  1922. if (grid.isWalkableAt(x + dx, y + dy)) {
  1923. neighbors.push([x + dx, y + dy]);
  1924. }
  1925. if (!grid.isWalkableAt(x - dx, y)) {
  1926. neighbors.push([x - dx, y + dy]);
  1927. }
  1928. if (!grid.isWalkableAt(x, y - dy)) {
  1929. neighbors.push([x + dx, y - dy]);
  1930. }
  1931. }
  1932. // search horizontally/vertically
  1933. else {
  1934. if(dx === 0) {
  1935. if (grid.isWalkableAt(x, y + dy)) {
  1936. neighbors.push([x, y + dy]);
  1937. }
  1938. if (!grid.isWalkableAt(x + 1, y)) {
  1939. neighbors.push([x + 1, y + dy]);
  1940. }
  1941. if (!grid.isWalkableAt(x - 1, y)) {
  1942. neighbors.push([x - 1, y + dy]);
  1943. }
  1944. }
  1945. else {
  1946. if (grid.isWalkableAt(x + dx, y)) {
  1947. neighbors.push([x + dx, y]);
  1948. }
  1949. if (!grid.isWalkableAt(x, y + 1)) {
  1950. neighbors.push([x + dx, y + 1]);
  1951. }
  1952. if (!grid.isWalkableAt(x, y - 1)) {
  1953. neighbors.push([x + dx, y - 1]);
  1954. }
  1955. }
  1956. }
  1957. }
  1958. // return all neighbors
  1959. else {
  1960. neighborNodes = grid.getNeighbors(node, DiagonalMovement.Always);
  1961. for (i = 0, l = neighborNodes.length; i < l; ++i) {
  1962. neighborNode = neighborNodes[i];
  1963. neighbors.push([neighborNode.x, neighborNode.y]);
  1964. }
  1965. }
  1966.  
  1967. return neighbors;
  1968. };
  1969.  
  1970. module.exports = JPFAlwaysMoveDiagonally;
  1971.  
  1972. },{"../core/DiagonalMovement":3,"./JumpPointFinderBase":23}],19:[function(_dereq_,module,exports){
  1973. /**
  1974. * @author imor / https://github.com/imor
  1975. */
  1976. var JumpPointFinderBase = _dereq_('./JumpPointFinderBase');
  1977. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  1978.  
  1979. /**
  1980. * Path finder using the Jump Point Search algorithm which moves
  1981. * diagonally only when there is at most one obstacle.
  1982. */
  1983. function JPFMoveDiagonallyIfAtMostOneObstacle(opt) {
  1984. JumpPointFinderBase.call(this, opt);
  1985. }
  1986.  
  1987. JPFMoveDiagonallyIfAtMostOneObstacle.prototype = new JumpPointFinderBase();
  1988. JPFMoveDiagonallyIfAtMostOneObstacle.prototype.constructor = JPFMoveDiagonallyIfAtMostOneObstacle;
  1989.  
  1990. /**
  1991. * Search recursively in the direction (parent -> child), stopping only when a
  1992. * jump point is found.
  1993. * @protected
  1994. * @return {Array<Array<number>>} The x, y coordinate of the jump point
  1995. * found, or null if not found
  1996. */
  1997. JPFMoveDiagonallyIfAtMostOneObstacle.prototype._jump = function(x, y, px, py) {
  1998. var grid = this.grid,
  1999. dx = x - px, dy = y - py;
  2000.  
  2001. if (!grid.isWalkableAt(x, y)) {
  2002. return null;
  2003. }
  2004.  
  2005. if(this.trackJumpRecursion === true) {
  2006. grid.getNodeAt(x, y).tested = true;
  2007. }
  2008.  
  2009. if (grid.getNodeAt(x, y) === this.endNode) {
  2010. return [x, y];
  2011. }
  2012.  
  2013. // check for forced neighbors
  2014. // along the diagonal
  2015. if (dx !== 0 && dy !== 0) {
  2016. if ((grid.isWalkableAt(x - dx, y + dy) && !grid.isWalkableAt(x - dx, y)) ||
  2017. (grid.isWalkableAt(x + dx, y - dy) && !grid.isWalkableAt(x, y - dy))) {
  2018. return [x, y];
  2019. }
  2020. // when moving diagonally, must check for vertical/horizontal jump points
  2021. if (this._jump(x + dx, y, x, y) || this._jump(x, y + dy, x, y)) {
  2022. return [x, y];
  2023. }
  2024. }
  2025. // horizontally/vertically
  2026. else {
  2027. if( dx !== 0 ) { // moving along x
  2028. if((grid.isWalkableAt(x + dx, y + 1) && !grid.isWalkableAt(x, y + 1)) ||
  2029. (grid.isWalkableAt(x + dx, y - 1) && !grid.isWalkableAt(x, y - 1))) {
  2030. return [x, y];
  2031. }
  2032. }
  2033. else {
  2034. if((grid.isWalkableAt(x + 1, y + dy) && !grid.isWalkableAt(x + 1, y)) ||
  2035. (grid.isWalkableAt(x - 1, y + dy) && !grid.isWalkableAt(x - 1, y))) {
  2036. return [x, y];
  2037. }
  2038. }
  2039. }
  2040.  
  2041. // moving diagonally, must make sure one of the vertical/horizontal
  2042. // neighbors is open to allow the path
  2043. if (grid.isWalkableAt(x + dx, y) || grid.isWalkableAt(x, y + dy)) {
  2044. return this._jump(x + dx, y + dy, x, y);
  2045. } else {
  2046. return null;
  2047. }
  2048. };
  2049.  
  2050. /**
  2051. * Find the neighbors for the given node. If the node has a parent,
  2052. * prune the neighbors based on the jump point search algorithm, otherwise
  2053. * return all available neighbors.
  2054. * @return {Array<Array<number>>} The neighbors found.
  2055. */
  2056. JPFMoveDiagonallyIfAtMostOneObstacle.prototype._findNeighbors = function(node) {
  2057. var parent = node.parent,
  2058. x = node.x, y = node.y,
  2059. grid = this.grid,
  2060. px, py, nx, ny, dx, dy,
  2061. neighbors = [], neighborNodes, neighborNode, i, l;
  2062.  
  2063. // directed pruning: can ignore most neighbors, unless forced.
  2064. if (parent) {
  2065. px = parent.x;
  2066. py = parent.y;
  2067. // get the normalized direction of travel
  2068. dx = (x - px) / Math.max(Math.abs(x - px), 1);
  2069. dy = (y - py) / Math.max(Math.abs(y - py), 1);
  2070.  
  2071. // search diagonally
  2072. if (dx !== 0 && dy !== 0) {
  2073. if (grid.isWalkableAt(x, y + dy)) {
  2074. neighbors.push([x, y + dy]);
  2075. }
  2076. if (grid.isWalkableAt(x + dx, y)) {
  2077. neighbors.push([x + dx, y]);
  2078. }
  2079. if (grid.isWalkableAt(x, y + dy) || grid.isWalkableAt(x + dx, y)) {
  2080. neighbors.push([x + dx, y + dy]);
  2081. }
  2082. if (!grid.isWalkableAt(x - dx, y) && grid.isWalkableAt(x, y + dy)) {
  2083. neighbors.push([x - dx, y + dy]);
  2084. }
  2085. if (!grid.isWalkableAt(x, y - dy) && grid.isWalkableAt(x + dx, y)) {
  2086. neighbors.push([x + dx, y - dy]);
  2087. }
  2088. }
  2089. // search horizontally/vertically
  2090. else {
  2091. if(dx === 0) {
  2092. if (grid.isWalkableAt(x, y + dy)) {
  2093. neighbors.push([x, y + dy]);
  2094. if (!grid.isWalkableAt(x + 1, y)) {
  2095. neighbors.push([x + 1, y + dy]);
  2096. }
  2097. if (!grid.isWalkableAt(x - 1, y)) {
  2098. neighbors.push([x - 1, y + dy]);
  2099. }
  2100. }
  2101. }
  2102. else {
  2103. if (grid.isWalkableAt(x + dx, y)) {
  2104. neighbors.push([x + dx, y]);
  2105. if (!grid.isWalkableAt(x, y + 1)) {
  2106. neighbors.push([x + dx, y + 1]);
  2107. }
  2108. if (!grid.isWalkableAt(x, y - 1)) {
  2109. neighbors.push([x + dx, y - 1]);
  2110. }
  2111. }
  2112. }
  2113. }
  2114. }
  2115. // return all neighbors
  2116. else {
  2117. neighborNodes = grid.getNeighbors(node, DiagonalMovement.IfAtMostOneObstacle);
  2118. for (i = 0, l = neighborNodes.length; i < l; ++i) {
  2119. neighborNode = neighborNodes[i];
  2120. neighbors.push([neighborNode.x, neighborNode.y]);
  2121. }
  2122. }
  2123.  
  2124. return neighbors;
  2125. };
  2126.  
  2127. module.exports = JPFMoveDiagonallyIfAtMostOneObstacle;
  2128.  
  2129. },{"../core/DiagonalMovement":3,"./JumpPointFinderBase":23}],20:[function(_dereq_,module,exports){
  2130. /**
  2131. * @author imor / https://github.com/imor
  2132. */
  2133. var JumpPointFinderBase = _dereq_('./JumpPointFinderBase');
  2134. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  2135.  
  2136. /**
  2137. * Path finder using the Jump Point Search algorithm which moves
  2138. * diagonally only when there are no obstacles.
  2139. */
  2140. function JPFMoveDiagonallyIfNoObstacles(opt) {
  2141. JumpPointFinderBase.call(this, opt);
  2142. }
  2143.  
  2144. JPFMoveDiagonallyIfNoObstacles.prototype = new JumpPointFinderBase();
  2145. JPFMoveDiagonallyIfNoObstacles.prototype.constructor = JPFMoveDiagonallyIfNoObstacles;
  2146.  
  2147. /**
  2148. * Search recursively in the direction (parent -> child), stopping only when a
  2149. * jump point is found.
  2150. * @protected
  2151. * @return {Array<Array<number>>} The x, y coordinate of the jump point
  2152. * found, or null if not found
  2153. */
  2154. JPFMoveDiagonallyIfNoObstacles.prototype._jump = function(x, y, px, py) {
  2155. var grid = this.grid,
  2156. dx = x - px, dy = y - py;
  2157.  
  2158. if (!grid.isWalkableAt(x, y)) {
  2159. return null;
  2160. }
  2161.  
  2162. if(this.trackJumpRecursion === true) {
  2163. grid.getNodeAt(x, y).tested = true;
  2164. }
  2165.  
  2166. if (grid.getNodeAt(x, y) === this.endNode) {
  2167. return [x, y];
  2168. }
  2169.  
  2170. // check for forced neighbors
  2171. // along the diagonal
  2172. if (dx !== 0 && dy !== 0) {
  2173. // if ((grid.isWalkableAt(x - dx, y + dy) && !grid.isWalkableAt(x - dx, y)) ||
  2174. // (grid.isWalkableAt(x + dx, y - dy) && !grid.isWalkableAt(x, y - dy))) {
  2175. // return [x, y];
  2176. // }
  2177. // when moving diagonally, must check for vertical/horizontal jump points
  2178. if (this._jump(x + dx, y, x, y) || this._jump(x, y + dy, x, y)) {
  2179. return [x, y];
  2180. }
  2181. }
  2182. // horizontally/vertically
  2183. else {
  2184. if (dx !== 0) {
  2185. if ((grid.isWalkableAt(x, y - 1) && !grid.isWalkableAt(x - dx, y - 1)) ||
  2186. (grid.isWalkableAt(x, y + 1) && !grid.isWalkableAt(x - dx, y + 1))) {
  2187. return [x, y];
  2188. }
  2189. }
  2190. else if (dy !== 0) {
  2191. if ((grid.isWalkableAt(x - 1, y) && !grid.isWalkableAt(x - 1, y - dy)) ||
  2192. (grid.isWalkableAt(x + 1, y) && !grid.isWalkableAt(x + 1, y - dy))) {
  2193. return [x, y];
  2194. }
  2195. // When moving vertically, must check for horizontal jump points
  2196. // if (this._jump(x + 1, y, x, y) || this._jump(x - 1, y, x, y)) {
  2197. // return [x, y];
  2198. // }
  2199. }
  2200. }
  2201.  
  2202. // moving diagonally, must make sure one of the vertical/horizontal
  2203. // neighbors is open to allow the path
  2204. if (grid.isWalkableAt(x + dx, y) && grid.isWalkableAt(x, y + dy)) {
  2205. return this._jump(x + dx, y + dy, x, y);
  2206. } else {
  2207. return null;
  2208. }
  2209. };
  2210.  
  2211. /**
  2212. * Find the neighbors for the given node. If the node has a parent,
  2213. * prune the neighbors based on the jump point search algorithm, otherwise
  2214. * return all available neighbors.
  2215. * @return {Array<Array<number>>} The neighbors found.
  2216. */
  2217. JPFMoveDiagonallyIfNoObstacles.prototype._findNeighbors = function(node) {
  2218. var parent = node.parent,
  2219. x = node.x, y = node.y,
  2220. grid = this.grid,
  2221. px, py, nx, ny, dx, dy,
  2222. neighbors = [], neighborNodes, neighborNode, i, l;
  2223.  
  2224. // directed pruning: can ignore most neighbors, unless forced.
  2225. if (parent) {
  2226. px = parent.x;
  2227. py = parent.y;
  2228. // get the normalized direction of travel
  2229. dx = (x - px) / Math.max(Math.abs(x - px), 1);
  2230. dy = (y - py) / Math.max(Math.abs(y - py), 1);
  2231.  
  2232. // search diagonally
  2233. if (dx !== 0 && dy !== 0) {
  2234. if (grid.isWalkableAt(x, y + dy)) {
  2235. neighbors.push([x, y + dy]);
  2236. }
  2237. if (grid.isWalkableAt(x + dx, y)) {
  2238. neighbors.push([x + dx, y]);
  2239. }
  2240. if (grid.isWalkableAt(x, y + dy) && grid.isWalkableAt(x + dx, y)) {
  2241. neighbors.push([x + dx, y + dy]);
  2242. }
  2243. }
  2244. // search horizontally/vertically
  2245. else {
  2246. var isNextWalkable;
  2247. if (dx !== 0) {
  2248. isNextWalkable = grid.isWalkableAt(x + dx, y);
  2249. var isTopWalkable = grid.isWalkableAt(x, y + 1);
  2250. var isBottomWalkable = grid.isWalkableAt(x, y - 1);
  2251.  
  2252. if (isNextWalkable) {
  2253. neighbors.push([x + dx, y]);
  2254. if (isTopWalkable) {
  2255. neighbors.push([x + dx, y + 1]);
  2256. }
  2257. if (isBottomWalkable) {
  2258. neighbors.push([x + dx, y - 1]);
  2259. }
  2260. }
  2261. if (isTopWalkable) {
  2262. neighbors.push([x, y + 1]);
  2263. }
  2264. if (isBottomWalkable) {
  2265. neighbors.push([x, y - 1]);
  2266. }
  2267. }
  2268. else if (dy !== 0) {
  2269. isNextWalkable = grid.isWalkableAt(x, y + dy);
  2270. var isRightWalkable = grid.isWalkableAt(x + 1, y);
  2271. var isLeftWalkable = grid.isWalkableAt(x - 1, y);
  2272.  
  2273. if (isNextWalkable) {
  2274. neighbors.push([x, y + dy]);
  2275. if (isRightWalkable) {
  2276. neighbors.push([x + 1, y + dy]);
  2277. }
  2278. if (isLeftWalkable) {
  2279. neighbors.push([x - 1, y + dy]);
  2280. }
  2281. }
  2282. if (isRightWalkable) {
  2283. neighbors.push([x + 1, y]);
  2284. }
  2285. if (isLeftWalkable) {
  2286. neighbors.push([x - 1, y]);
  2287. }
  2288. }
  2289. }
  2290. }
  2291. // return all neighbors
  2292. else {
  2293. neighborNodes = grid.getNeighbors(node, DiagonalMovement.OnlyWhenNoObstacles);
  2294. for (i = 0, l = neighborNodes.length; i < l; ++i) {
  2295. neighborNode = neighborNodes[i];
  2296. neighbors.push([neighborNode.x, neighborNode.y]);
  2297. }
  2298. }
  2299.  
  2300. return neighbors;
  2301. };
  2302.  
  2303. module.exports = JPFMoveDiagonallyIfNoObstacles;
  2304.  
  2305. },{"../core/DiagonalMovement":3,"./JumpPointFinderBase":23}],21:[function(_dereq_,module,exports){
  2306. /**
  2307. * @author imor / https://github.com/imor
  2308. */
  2309. var JumpPointFinderBase = _dereq_('./JumpPointFinderBase');
  2310. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  2311.  
  2312. /**
  2313. * Path finder using the Jump Point Search algorithm allowing only horizontal
  2314. * or vertical movements.
  2315. */
  2316. function JPFNeverMoveDiagonally(opt) {
  2317. JumpPointFinderBase.call(this, opt);
  2318. }
  2319.  
  2320. JPFNeverMoveDiagonally.prototype = new JumpPointFinderBase();
  2321. JPFNeverMoveDiagonally.prototype.constructor = JPFNeverMoveDiagonally;
  2322.  
  2323. /**
  2324. * Search recursively in the direction (parent -> child), stopping only when a
  2325. * jump point is found.
  2326. * @protected
  2327. * @return {Array<Array<number>>} The x, y coordinate of the jump point
  2328. * found, or null if not found
  2329. */
  2330. JPFNeverMoveDiagonally.prototype._jump = function(x, y, px, py) {
  2331. var grid = this.grid,
  2332. dx = x - px, dy = y - py;
  2333.  
  2334. if (!grid.isWalkableAt(x, y)) {
  2335. return null;
  2336. }
  2337.  
  2338. if(this.trackJumpRecursion === true) {
  2339. grid.getNodeAt(x, y).tested = true;
  2340. }
  2341.  
  2342. if (grid.getNodeAt(x, y) === this.endNode) {
  2343. return [x, y];
  2344. }
  2345.  
  2346. if (dx !== 0) {
  2347. if ((grid.isWalkableAt(x, y - 1) && !grid.isWalkableAt(x - dx, y - 1)) ||
  2348. (grid.isWalkableAt(x, y + 1) && !grid.isWalkableAt(x - dx, y + 1))) {
  2349. return [x, y];
  2350. }
  2351. }
  2352. else if (dy !== 0) {
  2353. if ((grid.isWalkableAt(x - 1, y) && !grid.isWalkableAt(x - 1, y - dy)) ||
  2354. (grid.isWalkableAt(x + 1, y) && !grid.isWalkableAt(x + 1, y - dy))) {
  2355. return [x, y];
  2356. }
  2357. //When moving vertically, must check for horizontal jump points
  2358. if (this._jump(x + 1, y, x, y) || this._jump(x - 1, y, x, y)) {
  2359. return [x, y];
  2360. }
  2361. }
  2362. else {
  2363. throw new Error("Only horizontal and vertical movements are allowed");
  2364. }
  2365.  
  2366. return this._jump(x + dx, y + dy, x, y);
  2367. };
  2368.  
  2369. /**
  2370. * Find the neighbors for the given node. If the node has a parent,
  2371. * prune the neighbors based on the jump point search algorithm, otherwise
  2372. * return all available neighbors.
  2373. * @return {Array<Array<number>>} The neighbors found.
  2374. */
  2375. JPFNeverMoveDiagonally.prototype._findNeighbors = function(node) {
  2376. var parent = node.parent,
  2377. x = node.x, y = node.y,
  2378. grid = this.grid,
  2379. px, py, nx, ny, dx, dy,
  2380. neighbors = [], neighborNodes, neighborNode, i, l;
  2381.  
  2382. // directed pruning: can ignore most neighbors, unless forced.
  2383. if (parent) {
  2384. px = parent.x;
  2385. py = parent.y;
  2386. // get the normalized direction of travel
  2387. dx = (x - px) / Math.max(Math.abs(x - px), 1);
  2388. dy = (y - py) / Math.max(Math.abs(y - py), 1);
  2389.  
  2390. if (dx !== 0) {
  2391. if (grid.isWalkableAt(x, y - 1)) {
  2392. neighbors.push([x, y - 1]);
  2393. }
  2394. if (grid.isWalkableAt(x, y + 1)) {
  2395. neighbors.push([x, y + 1]);
  2396. }
  2397. if (grid.isWalkableAt(x + dx, y)) {
  2398. neighbors.push([x + dx, y]);
  2399. }
  2400. }
  2401. else if (dy !== 0) {
  2402. if (grid.isWalkableAt(x - 1, y)) {
  2403. neighbors.push([x - 1, y]);
  2404. }
  2405. if (grid.isWalkableAt(x + 1, y)) {
  2406. neighbors.push([x + 1, y]);
  2407. }
  2408. if (grid.isWalkableAt(x, y + dy)) {
  2409. neighbors.push([x, y + dy]);
  2410. }
  2411. }
  2412. }
  2413. // return all neighbors
  2414. else {
  2415. neighborNodes = grid.getNeighbors(node, DiagonalMovement.Never);
  2416. for (i = 0, l = neighborNodes.length; i < l; ++i) {
  2417. neighborNode = neighborNodes[i];
  2418. neighbors.push([neighborNode.x, neighborNode.y]);
  2419. }
  2420. }
  2421.  
  2422. return neighbors;
  2423. };
  2424.  
  2425. module.exports = JPFNeverMoveDiagonally;
  2426.  
  2427. },{"../core/DiagonalMovement":3,"./JumpPointFinderBase":23}],22:[function(_dereq_,module,exports){
  2428. /**
  2429. * @author aniero / https://github.com/aniero
  2430. */
  2431. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  2432. var JPFNeverMoveDiagonally = _dereq_('./JPFNeverMoveDiagonally');
  2433. var JPFAlwaysMoveDiagonally = _dereq_('./JPFAlwaysMoveDiagonally');
  2434. var JPFMoveDiagonallyIfNoObstacles = _dereq_('./JPFMoveDiagonallyIfNoObstacles');
  2435. var JPFMoveDiagonallyIfAtMostOneObstacle = _dereq_('./JPFMoveDiagonallyIfAtMostOneObstacle');
  2436.  
  2437. /**
  2438. * Path finder using the Jump Point Search algorithm
  2439. * @param {Object} opt
  2440. * @param {function} opt.heuristic Heuristic function to estimate the distance
  2441. * (defaults to manhattan).
  2442. * @param {DiagonalMovement} opt.diagonalMovement Condition under which diagonal
  2443. * movement will be allowed.
  2444. */
  2445. function JumpPointFinder(opt) {
  2446. opt = opt || {};
  2447. if (opt.diagonalMovement === DiagonalMovement.Never) {
  2448. return new JPFNeverMoveDiagonally(opt);
  2449. } else if (opt.diagonalMovement === DiagonalMovement.Always) {
  2450. return new JPFAlwaysMoveDiagonally(opt);
  2451. } else if (opt.diagonalMovement === DiagonalMovement.OnlyWhenNoObstacles) {
  2452. return new JPFMoveDiagonallyIfNoObstacles(opt);
  2453. } else {
  2454. return new JPFMoveDiagonallyIfAtMostOneObstacle(opt);
  2455. }
  2456. }
  2457.  
  2458. module.exports = JumpPointFinder;
  2459.  
  2460. },{"../core/DiagonalMovement":3,"./JPFAlwaysMoveDiagonally":18,"./JPFMoveDiagonallyIfAtMostOneObstacle":19,"./JPFMoveDiagonallyIfNoObstacles":20,"./JPFNeverMoveDiagonally":21}],23:[function(_dereq_,module,exports){
  2461. /**
  2462. * @author imor / https://github.com/imor
  2463. */
  2464. var Heap = _dereq_('heap');
  2465. var Util = _dereq_('../core/Util');
  2466. var Heuristic = _dereq_('../core/Heuristic');
  2467. var DiagonalMovement = _dereq_('../core/DiagonalMovement');
  2468.  
  2469. /**
  2470. * Base class for the Jump Point Search algorithm
  2471. * @param {object} opt
  2472. * @param {function} opt.heuristic Heuristic function to estimate the distance
  2473. * (defaults to manhattan).
  2474. */
  2475. function JumpPointFinderBase(opt) {
  2476. opt = opt || {};
  2477. this.heuristic = opt.heuristic || Heuristic.manhattan;
  2478. this.trackJumpRecursion = opt.trackJumpRecursion || false;
  2479. }
  2480.  
  2481. /**
  2482. * Find and return the path.
  2483. * @return {Array<Array<number>>} The path, including both start and
  2484. * end positions.
  2485. */
  2486. JumpPointFinderBase.prototype.findPath = function(startX, startY, endX, endY, grid) {
  2487. var openList = this.openList = new Heap(function(nodeA, nodeB) {
  2488. return nodeA.f - nodeB.f;
  2489. }),
  2490. startNode = this.startNode = grid.getNodeAt(startX, startY),
  2491. endNode = this.endNode = grid.getNodeAt(endX, endY), node;
  2492.  
  2493. this.grid = grid;
  2494.  
  2495.  
  2496. // set the `g` and `f` value of the start node to be 0
  2497. startNode.g = 0;
  2498. startNode.f = 0;
  2499.  
  2500. // push the start node into the open list
  2501. openList.push(startNode);
  2502. startNode.opened = true;
  2503.  
  2504. // while the open list is not empty
  2505. while (!openList.empty()) {
  2506. // pop the position of node which has the minimum `f` value.
  2507. node = openList.pop();
  2508. node.closed = true;
  2509.  
  2510. if (node === endNode) {
  2511. return Util.expandPath(Util.backtrace(endNode));
  2512. }
  2513.  
  2514. this._identifySuccessors(node);
  2515. }
  2516.  
  2517. // fail to find the path
  2518. return [];
  2519. };
  2520.  
  2521. /**
  2522. * Identify successors for the given node. Runs a jump point search in the
  2523. * direction of each available neighbor, adding any points found to the open
  2524. * list.
  2525. * @protected
  2526. */
  2527. JumpPointFinderBase.prototype._identifySuccessors = function(node) {
  2528. var grid = this.grid,
  2529. heuristic = this.heuristic,
  2530. openList = this.openList,
  2531. endX = this.endNode.x,
  2532. endY = this.endNode.y,
  2533. neighbors, neighbor,
  2534. jumpPoint, i, l,
  2535. x = node.x, y = node.y,
  2536. jx, jy, dx, dy, d, ng, jumpNode,
  2537. abs = Math.abs, max = Math.max;
  2538.  
  2539. neighbors = this._findNeighbors(node);
  2540. for(i = 0, l = neighbors.length; i < l; ++i) {
  2541. neighbor = neighbors[i];
  2542. jumpPoint = this._jump(neighbor[0], neighbor[1], x, y);
  2543. if (jumpPoint) {
  2544.  
  2545. jx = jumpPoint[0];
  2546. jy = jumpPoint[1];
  2547. jumpNode = grid.getNodeAt(jx, jy);
  2548.  
  2549. if (jumpNode.closed) {
  2550. continue;
  2551. }
  2552.  
  2553. // include distance, as parent may not be immediately adjacent:
  2554. d = Heuristic.octile(abs(jx - x), abs(jy - y));
  2555. ng = node.g + d; // next `g` value
  2556.  
  2557. if (!jumpNode.opened || ng < jumpNode.g) {
  2558. jumpNode.g = ng;
  2559. jumpNode.h = jumpNode.h || heuristic(abs(jx - endX), abs(jy - endY));
  2560. jumpNode.f = jumpNode.g + jumpNode.h;
  2561. jumpNode.parent = node;
  2562.  
  2563. if (!jumpNode.opened) {
  2564. openList.push(jumpNode);
  2565. jumpNode.opened = true;
  2566. } else {
  2567. openList.updateItem(jumpNode);
  2568. }
  2569. }
  2570. }
  2571. }
  2572. };
  2573.  
  2574. module.exports = JumpPointFinderBase;
  2575.  
  2576. },{"../core/DiagonalMovement":3,"../core/Heuristic":5,"../core/Util":7,"heap":1}]},{},[8])
  2577. (8)
  2578. });
Advertisement
Add Comment
Please, Sign In to add comment