Files
OpenFrontIO/src/core/pathfinding/PathFinding.ts
T
Scott Anderson 3b07f78e97 strictNullChecks
2025-04-07 05:12:09 -04:00

110 lines
2.9 KiB
TypeScript

import { consolex } from "../Consolex";
import { Game } from "../game/Game";
import { TileRef } from "../game/GameMap";
import { AStar, PathFindResultType, TileResult } from "./AStar";
import { MiniAStar } from "./MiniAStar";
export class PathFinder {
private curr: TileRef | null = null;
private dst: TileRef | null = null;
private path: TileRef[] | null = null;
private aStar: AStar;
private computeFinished = true;
private constructor(
private game: Game,
private newAStar: (curr: TileRef, dst: TileRef) => AStar,
) {}
public static Mini(
game: Game,
iterations: number,
canMoveOnLand: boolean,
maxTries: number = 20,
) {
return new PathFinder(game, (curr: TileRef, dst: TileRef) => {
return new MiniAStar(
game.map(),
game.miniMap(),
curr,
dst,
(tr: TileRef): boolean => {
if (canMoveOnLand) {
return true;
}
return game.miniMap().isWater(tr);
},
iterations,
maxTries,
);
});
}
nextTile(curr: TileRef, dst: TileRef, dist: number = 1): TileResult {
if (curr == null) {
consolex.error("curr is null");
return { type: PathFindResultType.PathNotFound };
}
if (dst == null) {
consolex.error("dst is null");
return { type: PathFindResultType.PathNotFound };
}
if (this.game.manhattanDist(curr, dst) < dist) {
return { type: PathFindResultType.Completed, tile: curr };
}
if (this.computeFinished) {
if (this.shouldRecompute(curr, dst)) {
this.curr = curr;
this.dst = dst;
this.path = null;
this.aStar = this.newAStar(curr, dst);
this.computeFinished = false;
return this.nextTile(curr, dst);
} else {
const tile = this.path?.shift();
if (typeof tile === "undefined") {
throw new Error("missing tile");
}
return { type: PathFindResultType.NextTile, tile };
}
}
switch (this.aStar.compute()) {
case PathFindResultType.Completed:
this.computeFinished = true;
this.path = this.aStar.reconstructPath();
// Remove the start tile
this.path.shift();
return this.nextTile(curr, dst);
case PathFindResultType.Pending:
return { type: PathFindResultType.Pending };
case PathFindResultType.PathNotFound:
return { type: PathFindResultType.PathNotFound };
default:
throw new Error("unexpected compute result");
}
}
private shouldRecompute(curr: TileRef, dst: TileRef) {
if (this.path == null || this.curr == null || this.dst == null) {
return true;
}
const dist = this.game.manhattanDist(curr, dst);
let tolerance = 10;
if (dist > 50) {
tolerance = 10;
} else if (dist > 25) {
tolerance = 5;
} else {
tolerance = 0;
}
if (this.game.manhattanDist(this.dst, dst) > tolerance) {
return true;
}
return false;
}
}