123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- export const astar = (function() {
- class _OpenSet {
- constructor() {
- this._priorityQueue = buckets.PriorityQueue((a, b) => {
- if (a.fScore > b.fScore) {
- return -1;
- }
- if (a.fScore < b.fScore) {
- return 1;
- }
- if (a.gScore > b.gScore) {
- return 1;
- }
- if (a.gScore < b.gScore) {
- return -1;
- }
- return 0;
- });
- this._dict = {};
- }
- add(k, v) {
- this._priorityQueue.add(v);
- this._dict[k] = true;
- }
- dequeue() {
- const v = this._priorityQueue.dequeue();
- delete this._dict[v.key];
- return v;
- }
- peek() {
- return this._priorityQueue.peek();
- }
- hasKey(k) {
- return (k in this._dict);
- }
- size() {
- return this._priorityQueue.size();
- }
- };
- class _AStarClient {
- constructor(start, end, nodes) {
- this._start = start;
- this._end = end;
- this._nodes = nodes;
- this._path = null;
- this._astarInstance = null;
- }
- Start(instance) {
- this._astarInstance = instance;
- }
- get Path() {
- return this._path;
- }
- get started() {
- return this._astarInstance != null;
- }
- get finished() {
- if (this._path) {
- return true;
- }
- if (!this._astarInstance) {
- return false;
- }
- return this._astarInstance.finished;
- }
- CachePath() {
- if (!this._astarInstance) {
- return null;
- }
- this._path = this._astarInstance.BuildPath();
- this._path = this._path.map(k => this._astarInstance._nodes[k])
- this._astarInstance = null;
- }
- Step() {
- if (!this._astarInstance) {
- return;
- }
- this._astarInstance.Step();
- }
- };
- const _MAX_ASTAR = 400;
- class _AStarManager {
- constructor(nodes, costFunction, weightFunction) {
- this._nodes = nodes;
- this._costFunction = costFunction;
- this._weightFunction = weightFunction;
- this._live = [];
- this._clients = [];
- }
- Step() {
- for (let c of this._clients) {
- if (!c._astarInstance && !c.finished && this._live.length < _MAX_ASTAR) {
- const a = new _AStar(this._nodes, c._start, c._end, this._costFunction, this._weightFunction);
- c.Start(a);
- this._live.push(c);
- }
- }
- for (let c of this._live) {
- c.Step();
- if (c.finished) {
- c.CachePath();
- }
- }
- this._live = this._live.filter(c => !c.finished);
- }
- CreateClient(start, end) {
- const c = new _AStarClient(start, end, this._nodes);
- this._clients.push(c);
- return c;
- }
- }
- class _AStar {
- constructor(nodes, start, end, costFunction, weightFunction) {
- this._start = start;
- this._end = end;
- this._nodes = nodes;
- this._costFunction = costFunction;
- this._weightFunction = weightFunction;
- this._finished = false;
- this._steps = 0;
- this._data = {};
- this._data[start] = {
- key: start,
- gScore: 0,
- fScore: costFunction(start, end),
- cameFrom: null,
- };
- this._open = new _OpenSet();
- this._open.add(start, this._data[start]);
- }
- get finished() {
- return this._finished;
- }
- BuildInProgressPath() {
- const lowestF = this._open.peek();
- const path = [lowestF.key];
- while (true) {
- const n = this._data[path[path.length - 1]];
- if (n.cameFrom == null) {
- break;
- }
- path.push(n.cameFrom);
- }
- return path.reverse();
- }
- BuildPath() {
- if (!this.finished) {
- return this.BuildInProgressPath();
- }
- const path = [this._end];
- while (true) {
- const n = this._data[path[path.length - 1]];
- if (n.cameFrom == null) {
- break;
- }
- path.push(n.cameFrom);
- }
- return path.reverse();
- }
- Step() {
- if (this.finished) {
- return;
- }
- if (this._open.size() > 0) {
- this._steps += 1;
- const curNode = this._open.dequeue();
- const k = curNode.key;
- if (k == this._end) {
- this._finished = true;
- return;
- }
- for (const e of this._nodes[k].edges) {
- // Lazily instantiate graph instead of in constructor.
- if (!(e in this._data)) {
- this._data[e] = {
- key: k,
- gScore: Number.MAX_VALUE,
- fScore: Number.MAX_VALUE,
- cameFrom: null,
- };
- }
-
- const gScore = this._data[k].gScore + this._weightFunction(k, e);
- if (gScore < this._data[e].gScore) {
- this._data[e] = {
- key: e,
- gScore: gScore,
- fScore: gScore + this._costFunction(this._end, e),
- cameFrom: k,
- };
- if (!this._open.hasKey(e)) {
- this._open.add(e, this._data[e]);
- }
- }
- }
- }
- }
- };
- return {
- AStarManager: _AStarManager,
- };
- })();
|