rot-js
Version:
A roguelike toolkit in JavaScript
91 lines (90 loc) • 2.73 kB
JavaScript
import Path from "./path.js";
/**
* @class Simplified A* algorithm: all edges have a value of 1
* @augments ROT.Path
* @see ROT.Path
*/
export default class AStar extends Path {
constructor(toX, toY, passableCallback, options = {}) {
super(toX, toY, passableCallback, options);
this._todo = [];
this._done = {};
}
/**
* Compute a path from a given point
* @see ROT.Path#compute
*/
compute(fromX, fromY, callback) {
this._todo = [];
this._done = {};
this._fromX = fromX;
this._fromY = fromY;
this._add(this._toX, this._toY, null);
while (this._todo.length) {
let item = this._todo.shift();
let id = item.x + "," + item.y;
if (id in this._done) {
continue;
}
this._done[id] = item;
if (item.x == fromX && item.y == fromY) {
break;
}
let neighbors = this._getNeighbors(item.x, item.y);
for (let i = 0; i < neighbors.length; i++) {
let neighbor = neighbors[i];
let x = neighbor[0];
let y = neighbor[1];
let id = x + "," + y;
if (id in this._done) {
continue;
}
this._add(x, y, item);
}
}
let item = this._done[fromX + "," + fromY];
if (!item) {
return;
}
while (item) {
callback(item.x, item.y);
item = item.prev;
}
}
_add(x, y, prev) {
let h = this._distance(x, y);
let obj = {
x: x,
y: y,
prev: prev,
g: (prev ? prev.g + 1 : 0),
h: h
};
/* insert into priority queue */
let f = obj.g + obj.h;
for (let i = 0; i < this._todo.length; i++) {
let item = this._todo[i];
let itemF = item.g + item.h;
if (f < itemF || (f == itemF && h < item.h)) {
this._todo.splice(i, 0, obj);
return;
}
}
this._todo.push(obj);
}
_distance(x, y) {
switch (this._options.topology) {
case 4:
return (Math.abs(x - this._fromX) + Math.abs(y - this._fromY));
break;
case 6:
let dx = Math.abs(x - this._fromX);
let dy = Math.abs(y - this._fromY);
return dy + Math.max(0, (dx - dy) / 2);
break;
case 8:
return Math.max(Math.abs(x - this._fromX), Math.abs(y - this._fromY));
break;
}
}
}