Files
OpenFrontIO/src/core/pathfinding/PathFinding.ts
T
2025-02-01 12:05:11 -08:00

104 lines
2.7 KiB
TypeScript

import { Cell, Game } from "../game/Game";
import { AStar, PathFindResultType, TileResult } from "./AStar";
import { SerialAStar } from "./SerialAStar";
import { MiniAStar } from "./MiniAStar";
import { consolex } from "../Consolex";
import { TileRef } from "../game/GameMap";
export class PathFinder {
private curr: TileRef = null;
private dst: TileRef = null;
private path: TileRef[];
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().isOcean(tr);
},
iterations,
maxTries,
);
});
}
nextTile(curr: TileRef, dst: TileRef, dist: number = 1): TileResult {
if (curr == null) {
consolex.error("curr is null");
}
if (dst == null) {
consolex.error("dst is null");
}
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 {
return { type: PathFindResultType.NextTile, tile: this.path.shift() };
}
}
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 };
}
}
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 if (dist > 10) {
tolerance = 3;
} else {
tolerance = 0;
}
if (this.game.manhattanDist(this.dst, dst) > tolerance) {
return true;
}
return false;
}
}