roguelike-pumpkin-patch
Version:
A roguelike development library in JavaScript.
145 lines • 7.26 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
/** Pathfinder to determine how to travel from one point to another */
var PathFinder = /** @class */ (function () {
function PathFinder(parameters) {
var canPass = parameters.canPass, metric = parameters.metric, maxIterations = parameters.maxIterations, weight = parameters.weight, rest = __rest(parameters, ["canPass", "metric", "maxIterations", "weight"]);
this.canPass = canPass;
if (!metric) {
// Default metric is Manhattan metric, if none provided
metric = function (position1, position2) {
return Math.abs(position2[1] - position1[1]) + Math.abs(position2[0] - position1[0]);
};
}
if (!weight) {
// Default to everything being length of 1
weight = function (position) { return 1; };
}
this.maxIterations = maxIterations;
this.metric = metric;
this.weight = weight;
}
/** Find route from startPosition to endPosition, via A* */
PathFinder.prototype.findPath = function (startPosition, endPosition, orthogonalOnly) {
var _this = this;
if (orthogonalOnly === void 0) { orthogonalOnly = false; }
var route = [];
// Limit the loop so it doesn't break things
var maxIterations = (this.maxIterations) ? this.maxIterations : 40 * this.metric(startPosition, endPosition);
var iterations = 0;
// Initialize the list, and add the start to it
var closedList = [
{
position: __spreadArrays(startPosition),
steps: 0,
distanceFromGoal: this.metric(startPosition, endPosition),
previousLocation: null
}
];
var openList = [];
// Handle diagonals
var stepSizeArr = [0, 1, 1.2];
// Find a path
while (iterations < maxIterations &&
!this.contains(closedList, endPosition)) {
iterations++;
// Expand the open list
closedList.forEach(function (location) {
for (var i = -1; i < 2; i++) {
for (var j = -1; j < 2; j++) {
if (orthogonalOnly && i !== 0 && j !== 0) {
continue;
}
var newPosition = [location.position[0] + i, location.position[1] + j];
// Determine the cost / size of step into the square
var stepSize = stepSizeArr[Math.abs(i) + Math.abs(j)] * _this.weight(newPosition);
if (!_this.canPass(newPosition)) {
continue;
}
var inClosedListAlready = _this.getLocation(closedList, newPosition);
var inOpenListAlready = _this.getLocation(openList, newPosition);
// New position is in neither list
if (!inClosedListAlready && !inOpenListAlready) {
openList.push({
position: newPosition,
steps: location.steps + stepSize,
distanceFromGoal: _this.metric(newPosition, endPosition),
previousLocation: location
});
}
else {
// if the position is already in the list, adjust to be whichever version is shorter
if (inClosedListAlready && inClosedListAlready.steps > location.steps + stepSize) {
inClosedListAlready.steps = location.steps + stepSize;
inClosedListAlready.previousLocation = location;
}
if (inOpenListAlready && inOpenListAlready.steps > location.steps + stepSize) {
inOpenListAlready.steps = location.steps + stepSize;
inOpenListAlready.previousLocation = location;
}
}
}
}
});
// Sort the open list (highest --> lowest)
openList.sort(function (a, b) { return (b.steps + b.distanceFromGoal) - (a.steps + a.distanceFromGoal); });
// Pop off the lowest openList item and add it to the closed list
closedList.push(openList.pop());
}
// Found a route! Put the pieces together by working backwards
var location = this.getLocation(closedList, endPosition);
if (this.contains(closedList, endPosition)) {
iterations = 0;
while ((location.position[0] !== startPosition[0] || location.position[1] !== startPosition[1]) && iterations < maxIterations) {
iterations++;
route.push(location.position);
location = location.previousLocation;
}
}
return route.reverse();
};
PathFinder.prototype.isEqual = function (position1, position2) {
return (position1.position[0] === position2.position[0] && position1.position[1] === position2.position[1]);
};
PathFinder.prototype.contains = function (locationList, testLocation) {
var _this = this;
if (Array.isArray(testLocation)) {
return locationList.some(function (location) {
return (location.position[0] === testLocation[0] && location.position[1] === testLocation[1]);
});
}
else {
return locationList.some(function (location) {
return _this.isEqual(location, testLocation);
});
}
};
PathFinder.prototype.getLocation = function (locationList, testPosition) {
for (var _i = 0, locationList_1 = locationList; _i < locationList_1.length; _i++) {
var location_1 = locationList_1[_i];
if (location_1.position[0] === testPosition[0] && location_1.position[1] === testPosition[1]) {
return location_1;
}
}
return undefined;
};
return PathFinder;
}());
export default PathFinder;
//# sourceMappingURL=PathFinder.js.map