topical media & game development

talk show tell print

mobile-query-three-plugins-simplemaze-vendor-pathfinding-browser.js / js



  
____ _ _ _____ _ _ _ _ | _ \ __ _| |_| |__ | ___(_)_ __ __| (_)_ __ __ _ (_)___ | |_) / _` | __| '_ \| |_ | | '_ \ / _` | | '_ \ / _` | | / __| | __/ (_| | |_| | | | _| | | | | | (_| | | | | | (_| |_ | __ \ |_| __,_|__|_| |_|_| |_|_| |_|__,_|_|_| |_|__, (_)/ |___/ |___/ |__/ github.com/qiao/PathFinding.js

  
  var PF = (function() {var require = function (file, cwd) {
      var resolved = require.resolve(file, cwd || '/');
      var mod = require.modules[resolved];
      if (!mod) throw new Error(
          'Failed to resolve module ' + file + ', tried ' + resolved
      );
      var res = mod._cached ? mod._cached : mod();
      return res;
  }
  
  require.paths = [];
  require.modules = {};
  require.extensions = [".js",".coffee"];
  
  require._core = {
      'assert': true,
      'events': true,
      'fs': true,
      'path': true,
      'vm': true
  };
  
  require.resolve = (function () {
      return function (x, cwd) {
          if (!cwd) cwd = '/';
          
          if (require._core[x]) return x;
          var path = require.modules.path();
          cwd = path.resolve('/', cwd);
          var y = cwd || '/';
          
          if (x.match(/^(?:\.\.?\/|\/)/)) {
              var m = loadAsFileSync(path.resolve(y, x))
                  || loadAsDirectorySync(path.resolve(y, x));
              if (m) return m;
          }
          
          var n = loadNodeModulesSync(x, y);
          if (n) return n;
          
          throw new Error("Cannot find module '" + x + "'");
          
          function loadAsFileSync (x) {
              if (require.modules[x]) {
                  return x;
              }
              
              for (var i = 0; i < require.extensions.length; i++) {
                  var ext = require.extensions[i];
                  if (require.modules[x + ext]) return x + ext;
              }
          }
          
          function loadAsDirectorySync (x) {
              x = x.replace(/\/+/, '');
              var pkgfile = x + '/package.json';
              if (require.modules[pkgfile]) {
                  var pkg = require.modules[pkgfile]();
                  var b = pkg.browserify;
                  if (typeof b === 'object' && b.main) {
                      var m = loadAsFileSync(path.resolve(x, b.main));
                      if (m) return m;
                  }
                  else if (typeof b === 'string') {
                      var m = loadAsFileSync(path.resolve(x, b));
                      if (m) return m;
                  }
                  else if (pkg.main) {
                      var m = loadAsFileSync(path.resolve(x, pkg.main));
                      if (m) return m;
                  }
              }
              
              return loadAsFileSync(x + '/index');
          }
          
          function loadNodeModulesSync (x, start) {
              var dirs = nodeModulesPathsSync(start);
              for (var i = 0; i < dirs.length; i++) {
                  var dir = dirs[i];
                  var m = loadAsFileSync(dir + '/' + x);
                  if (m) return m;
                  var n = loadAsDirectorySync(dir + '/' + x);
                  if (n) return n;
              }
              
              var m = loadAsFileSync(x);
              if (m) return m;
          }
          
          function nodeModulesPathsSync (start) {
              var parts;
              if (start === '/') parts = [ '' ];
              else parts = path.normalize(start).split('/');
              
              var dirs = [];
              for (var i = parts.length - 1; i >= 0; i--) {
                  if (parts[i] === 'node_modules') continue;
                  var dir = parts.slice(0, i + 1).join('/') + '/node_modules';
                  dirs.push(dir);
              }
              
              return dirs;
          }
      };
  })();
  
  require.alias = function (from, to) {
      var path = require.modules.path();
      var res = null;
      try {
          res = require.resolve(from + '/package.json', '/');
      }
      catch (err) {
          res = require.resolve(from, '/');
      }
      var basedir = path.dirname(res);
      
      var keys = (Object.keys || function (obj) {
          var res = [];
          for (var key in obj) res.push(key)
          return res;
      })(require.modules);
      
      for (var i = 0; i < keys.length; i++) {
          var key = keys[i];
          if (key.slice(0, basedir.length + 1) === basedir + '/') {
              var f = key.slice(basedir.length);
              require.modules[to + f] = require.modules[basedir + f];
          }
          else if (key === basedir) {
              require.modules[to] = require.modules[basedir];
          }
      }
  };
  
  require.define = function (filename, fn) {
      var dirname = require._core[filename]
          ? ''
          : require.modules.path().dirname(filename)
      ;
      
      var require_ = function (file) {
          return require(file, dirname)
      };
      require_.resolve = function (name) {
          return require.resolve(name, dirname);
      };
      require_.modules = require.modules;
      require_.define = require.define;
      var module_ = { exports : {} };
      
      require.modules[filename] = function () {
          require.modules[filename]._cached = module_.exports;
          fn.call(
              module_.exports,
              require_,
              module_,
              module_.exports,
              dirname,
              filename
          );
          require.modules[filename]._cached = module_.exports;
          return module_.exports;
      };
  };
  
  if (typeof process === 'undefined') process = {};
  
  if (!process.nextTick) process.nextTick = (function () {
      var queue = [];
      var canPost = typeof window !== 'undefined'
          && window.postMessage && window.addEventListener
      ;
      
      if (canPost) {
          window.addEventListener('message', function (ev) {
              if (ev.source === window && ev.data === 'browserify-tick') {
                  ev.stopPropagation();
                  if (queue.length > 0) {
                      var fn = queue.shift();
                      fn();
                  }
              }
          }, true);
      }
      
      return function (fn) {
          if (canPost) {
              queue.push(fn);
              window.postMessage('browserify-tick', '*');
          }
          else setTimeout(fn, 0);
      };
  })();
  
  if (!process.title) process.title = 'browser';
  
  if (!process.binding) process.binding = function (name) {
      if (name === 'evals') return require('vm')
      else throw new Error('No such module')
  };
  
  if (!process.cwd) process.cwd = function () { return '.' };
  
  if (!process.env) process.env = {};
  if (!process.argv) process.argv = [];
  
  require.define("path", function (require, module, exports, __dirname, __filename) {
  function filter (xs, fn) {
      var res = [];
      for (var i = 0; i < xs.length; i++) {
          if (fn(xs[i], i, xs)) res.push(xs[i]);
      }
      return res;
  }
  
  // resolves . and .. elements in a path array with directory names there
  // must be no slashes, empty elements, or device names (c:\) in the array
  // (so also no leading and trailing slashes - it does not distinguish
  // relative and absolute paths)
  function normalizeArray(parts, allowAboveRoot) {
    // if the path tries to go above the root, `up` ends up > 0
    var up = 0;
    for (var i = parts.length; i >= 0; i--) {
      var last = parts[i];
      if (last == '.') {
        parts.splice(i, 1);
      } else if (last === '..') {
        parts.splice(i, 1);
        up++;
      } else if (up) {
        parts.splice(i, 1);
        up--;
      }
    }
  
    // if the path is allowed to go above the root, restore leading ..s
    if (allowAboveRoot) {
      for (; up--; up) {
        parts.unshift('..');
      }
    }
  
    return parts;
  }
  
  // Regex to split a filename into [*, dir, basename, ext]
  // posix version
  var splitPathRe = /^(.+\/(?!)|\/)?((?:.+?)?(\.[^.]*)?)/;
  
  // path.resolve([from ...], to)
  // posix version
  exports.resolve = function() {
  var resolvedPath = '',
      resolvedAbsolute = false;
  
  for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) {
    var path = (i >= 0)
        ? arguments[i]
        : process.cwd();
  
    // Skip empty and invalid entries
    if (typeof path !== 'string' || !path) {
      continue;
    }
  
    resolvedPath = path + '/' + resolvedPath;
    resolvedAbsolute = path.charAt(0) === '/';
  }
  
  // At this point the path should be resolved to a full absolute path, but
  // handle relative paths to be safe (might happen when process.cwd() fails)
  
  // Normalize the path
  resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
      return !!p;
    }), !resolvedAbsolute).join('/');
  
    return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
  };
  
  // path.normalize(path)
  // posix version
  exports.normalize = function(path) {
  var isAbsolute = path.charAt(0) === '/',
      trailingSlash = path.slice(-1) === '/';
  
  // Normalize the path
  path = normalizeArray(filter(path.split('/'), function(p) {
      return !!p;
    }), !isAbsolute).join('/');
  
    if (!path && !isAbsolute) {
      path = '.';
    }
    if (path && trailingSlash) {
      path += '/';
    }
    
    return (isAbsolute ? '/' : '') + path;
  };
  
  // posix version
  exports.join = function() {
    var paths = Array.prototype.slice.call(arguments, 0);
    return exports.normalize(filter(paths, function(p, index) {
      return p && typeof p === 'string';
    }).join('/'));
  };
  
  exports.dirname = function(path) {
    var dir = splitPathRe.exec(path)[1] || '';
    var isWindows = false;
    if (!dir) {
      // No dirname
      return '.';
    } else if (dir.length === 1 ||
        (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) {
      // It is just a slash or a drive letter with a slash
      return dir;
    } else {
      // It is a full dirname, strip trailing slash
      return dir.substring(0, dir.length - 1);
    }
  };
  
  exports.basename = function(path, ext) {
    var f = splitPathRe.exec(path)[2] || '';
    // TODO: make this comparison case-insensitive on windows?
    if (ext && f.substr(-1 * ext.length) === ext) {
      f = f.substr(0, f.length - ext.length);
    }
    return f;
  };
  
  exports.extname = function(path) {
    return splitPathRe.exec(path)[3] || '';
  };
  
  });
  
  require.define("/core/Node.js", function (require, module, exports, __dirname, __filename) {
  
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
parameter: {number} x - The x coordinate of the node on the grid.
parameter: {number} y - The y coordinate of the node on the grid.
parameter: {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;
  
  });
  
  require.define("/core/Grid.js", function (require, module, exports, __dirname, __filename) {
  var Node = require('./Node');
  
  
The Grid class, which serves as the encapsulation of the layout of the nodes. @constructor
parameter: {number} width Number of columns of the grid.
parameter: {number} height Number of rows of the grid.
parameter: {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
parameter: {number} width
parameter: {number} height
parameter: {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.)
parameter: {number} x - The x coordinate of the node.
parameter: {number} y - The y coordinate of the node.
returns: {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.
parameter: {number} x
parameter: {number} y
returns: {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.
parameter: {number} x - The x coordinate of the node.
parameter: {number} y - The y coordinate of the node.
parameter: {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.
parameter: {Node} node
parameter: {boolean} allowDiagonal
parameter: {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.
returns: {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;
  
  });
  
  require.define("/core/Heap.js", function (require, module, exports, __dirname, __filename) {
  // From github.com/qiao/heap.js
  // Generated by CoffeeScript 1.3.1
  (function() {
    var Heap, defaultCmp, floor, heapify, heappop, heappush, heappushpop, heapreplace, insort, min, nlargest, nsmallest, updateItem, _siftdown, _siftup;
  
    floor = Math.floor, min = Math.min;
  
    /* 
    Default comparison function to be used
    */
  
    defaultCmp = function(x, y) {
      if (x < y) {
        return -1;
      }
      if (x > 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 (cmp(lo, hi) < 0) {
        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);
      _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.name = 'Heap';
  
      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);
  
  });
  
  require.define("/core/Util.js", function (require, module, exports, __dirname, __filename) {
  
Backtrace according to the parent records and return the path. (including both start and end nodes)
parameter: {Node} node End node
returns: {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)
parameter: {Node}
parameter: {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.
parameter: {Array.>} path The path
returns: {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
parameter: {number} x0 Start x coordinate
parameter: {number} y0 Start y coordinate
parameter: {number} x1 End x coordinate
parameter: {number} y1 End y coordinate
returns: {Array.>} The coordinates on the line

  
  function getLine(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.getLine = getLine;
  
  
Smoothen the give path. The original path will not be modified; a new path will be returned.
parameter: {PF.Grid} grid
parameter: {Array.>} path The path
returns: {Array.>} Smoothened 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 = getLine(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;
  
  });
  
  require.define("/core/Heuristic.js", function (require, module, exports, __dirname, __filename) {
  
@namespace PF.Heuristic @description A collection of heuristic functions.

  
  module.exports = {
  
    
Manhattan distance.
parameter: {number} dx - Difference in x.
parameter: {number} dy - Difference in y.
returns: {number} dx + dy

  
    manhattan: function(dx, dy) {
        return dx + dy;
    },
  
    
Euclidean distance.
parameter: {number} dx - Difference in x.
parameter: {number} dy - Difference in y.
returns: {number} sqrt(dx * dx + dy * dy)

  
    euclidean: function(dx, dy) {
        return Math.sqrt(dx * dx + dy * dy);
    },
  
    
Chebyshev distance.
parameter: {number} dx - Difference in x.
parameter: {number} dy - Difference in y.
returns: {number} max(dx, dy)

  
    chebyshev: function(dx, dy) {
        return Math.max(dx, dy);
    }
  
  };
  
  });
  
  require.define("/finders/AStarFinder.js", function (require, module, exports, __dirname, __filename) {
  var Heap       = require('../core/Heap');
  var Util       = require('../core/Util');
  var Heuristic  = require('../core/Heuristic');
  
  
A* path-finder. based upon github.com/bgrins/javascript-astar @constructor
parameter: {object} opt
parameter: {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
parameter: {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners.
parameter: {function} opt.heuristic Heuristic function to estimate the distance (defaults to manhattan).

  
  function AStarFinder(opt) {
      opt = opt || {};
      this.allowDiagonal = opt.allowDiagonal;
      this.dontCrossCorners = opt.dontCrossCorners;
      this.heuristic = opt.heuristic || Heuristic.manhattan;
  }
  
  
Find and return the the path.
returns: {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,
          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 || 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;
  
  });
  
  require.define("/finders/BestFirstFinder.js", function (require, module, exports, __dirname, __filename) {
  var AStarFinder = require('./AStarFinder');
  
  
Best-First-Search path-finder. @constructor @extends AStarFinder
parameter: {object} opt
parameter: {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
parameter: {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners.
parameter: {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;
  
  });
  
  require.define("/finders/BreadthFirstFinder.js", function (require, module, exports, __dirname, __filename) {
  var Util = require('../core/Util');
  
  
Breadth-First-Search path finder. @constructor
parameter: {object} opt
parameter: {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
parameter: {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.
returns: {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;
  
  });
  
  require.define("/finders/DijkstraFinder.js", function (require, module, exports, __dirname, __filename) {
  var AStarFinder = require('./AStarFinder');
  
  
Dijkstra path-finder. @constructor @extends AStarFinder
parameter: {object} opt
parameter: {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
parameter: {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;
  
  });
  
  require.define("/finders/BiAStarFinder.js", function (require, module, exports, __dirname, __filename) {
  var Heap       = require('../core/Heap');
  var Util       = require('../core/Util');
  var Heuristic  = require('../core/Heuristic');
  
  
A* path-finder. based upon github.com/bgrins/javascript-astar @constructor
parameter: {object} opt
parameter: {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
parameter: {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners.
parameter: {function} opt.heuristic Heuristic function to estimate the distance (defaults to manhattan).

  
  function BiAStarFinder(opt) {
      opt = opt || {};
      this.allowDiagonal = opt.allowDiagonal;
      this.dontCrossCorners = opt.dontCrossCorners;
      this.heuristic = opt.heuristic || Heuristic.manhattan;
  }
  
  
Find and return the the path.
returns: {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,
          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 || 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 || 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;
  
  });
  
  require.define("/finders/BiBestFirstFinder.js", function (require, module, exports, __dirname, __filename) {
  var BiAStarFinder = require('./BiAStarFinder');
  
  
Bi-direcitional Best-First-Search path-finder. @constructor @extends BiAStarFinder
parameter: {object} opt
parameter: {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
parameter: {boolean} opt.dontCrossCorners Disallow diagonal movement touching block corners.
parameter: {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;
  
  });
  
  require.define("/finders/BiBreadthFirstFinder.js", function (require, module, exports, __dirname, __filename) {
  var Util = require('../core/Util');
  
  
Bi-directional Breadth-First-Search path finder. @constructor
parameter: {object} opt
parameter: {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
parameter: {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.
returns: {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;
  
  });
  
  require.define("/finders/BiDijkstraFinder.js", function (require, module, exports, __dirname, __filename) {
  var BiAStarFinder = require('./BiAStarFinder');
  
  
Bi-directional Dijkstra path-finder. @constructor @extends BiAStarFinder
parameter: {object} opt
parameter: {boolean} opt.allowDiagonal Whether diagonal movement is allowed.
parameter: {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;
  
  });
  
  require.define("/finders/JumpPointFinder.js", function (require, module, exports, __dirname, __filename) {
  

author: aniero / github.com/aniero

  
  var Heap       = require('../core/Heap');
  var Util       = require('../core/Util');
  var Heuristic  = require('../core/Heuristic');
  
  
Path finder using the Jump Point Search algorithm
parameter: {object} opt
parameter: {function} opt.heuristic Heuristic function to estimate the distance (defaults to manhattan).

  
  function JumpPointFinder(opt) {
      opt = opt || {};
      this.heuristic = opt.heuristic || Heuristic.manhattan;
  }
  
  
Find and return the the path.
returns: {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.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
returns: {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, jx, jy;
  
      if (!grid.isWalkableAt(x, y)) {
          return null;
      }
      else 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) {
          jx = this._jump(x + dx, y, x, y);
          jy = this._jump(x, y + dy, x, y);
          if (jx || jy) {
              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.
returns: {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)) {
                      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)) {
                      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;
  
  });
  
  require.define("/PathFinding.js", function (require, module, exports, __dirname, __filename) {
      module.exports = {
      'Node'                 : require('./core/Node'),
      'Grid'                 : require('./core/Grid'),
      'Heap'                 : require('./core/Heap'),
      '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')
  };
  
  });
  require("/PathFinding.js");
  return require("/PathFinding");})();


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.