NPCs create battleships, destroyers. start work on miniastar

This commit is contained in:
Evan
2024-11-30 12:41:22 -08:00
parent 5d4befb117
commit 30f72a3365
11 changed files with 221 additions and 55 deletions
+5
View File
@@ -25,5 +25,10 @@ export enum PathFindResultType {
export interface SearchNode {
cost(): number
cell(): Cell
neighbors(): SearchNode[]
}
export interface Point {
x: number;
y: number;
}
+88
View File
@@ -0,0 +1,88 @@
import { Cell, Game, TerrainMap, TerrainTile, TerrainType } from "../game/Game";
import { AStar, PathFindResultType, Point, SearchNode } from "./AStar";
import { SerialAStar } from "./SerialAStar";
// TODO: test this, get it work
export class MiniAStar implements AStar {
private aStar: SerialAStar
constructor(
private terrainMap: TerrainMap,
private miniMap: TerrainMap,
private src: SearchNode,
private dst: SearchNode,
private canMove: (t: SearchNode) => boolean,
private iterations: number,
private maxTries: number
) {
const miniSrc = miniMap.terrain(new Cell(Math.floor(src.cell().x / 2), Math.floor(src.cell().y / 2)))
const miniDst = miniMap.terrain(new Cell(Math.floor(dst.cell().x / 2), Math.floor(dst.cell().y / 2)))
this.aStar = new SerialAStar(
miniSrc,
miniDst,
(t => (t as TerrainTile).terrainType() == TerrainType.Ocean),
iterations,
maxTries
)
}
compute(): PathFindResultType {
return this.aStar.compute()
}
reconstructPath(): SearchNode[] {
const upscaled = upscalePath(this.aStar.reconstructPath())
.map(p => this.terrainMap.terrain(new Cell(p.x, p.y))) as SearchNode[]
upscaled.push(this.dst)
return upscaled
}
reconstructPathAsPoints(): Point[] {
const upscaled = upscalePath(this.aStar.reconstructPath())
upscaled.push({ x: this.dst.cell().x, y: this.dst.cell().y })
return upscaled
}
}
function upscalePath(path: SearchNode[], scaleFactor: number = 2): Point[] {
// Scale up each point
const scaledPath = path.map(point => ({
x: point.cell().x * scaleFactor,
y: point.cell().y * scaleFactor
}));
const smoothPath: Point[] = [];
for (let i = 0; i < scaledPath.length - 1; i++) {
const current = scaledPath[i];
const next = scaledPath[i + 1];
// Add the current point
smoothPath.push(current);
// Always interpolate between scaled points
const dx = next.x - current.x;
const dy = next.y - current.y;
// Calculate number of steps needed
const distance = Math.max(Math.abs(dx), Math.abs(dy));
const steps = distance;
// Add intermediate points
for (let step = 1; step < steps; step++) {
smoothPath.push({
x: Math.round(current.x + (dx * step) / steps),
y: Math.round(current.y + (dy * step) / steps)
});
}
}
// Add the last point
if (scaledPath.length > 0) {
smoothPath.push(scaledPath[scaledPath.length - 1]);
}
return smoothPath;
}
+21 -2
View File
@@ -3,6 +3,7 @@ import { manhattanDist } from "../Util";
import { AStar, PathFindResultType, TileResult } from "./AStar";
import { ParallelAStar, WorkerClient } from "../worker/WorkerClient";
import { SerialAStar } from "./SerialAStar";
import { MiniAStar } from "./MiniAStar";
export class PathFinder {
@@ -16,6 +17,23 @@ export class PathFinder {
private newAStar: (curr: Tile, dst: Tile) => AStar
) { }
public static Mini(game: Game, iterations: number, canMove: (t: Tile) => boolean, maxTries: number = 20) {
return new PathFinder(
(curr: Tile, dst: Tile) => {
return new MiniAStar(
game.terrainMap(),
game.terrainMiniMap(),
curr,
dst,
canMove,
iterations,
maxTries
)
}
)
}
public static Serial(iterations: number, canMove: (t: Tile) => boolean, maxTries: number = 20): PathFinder {
return new PathFinder(
(curr: Tile, dst: Tile) => {
@@ -23,7 +41,8 @@ export class PathFinder {
curr,
dst,
canMove,
sn => ((sn as Tile).neighbors()), iterations, maxTries
iterations,
maxTries
)
}
)
@@ -65,7 +84,7 @@ export class PathFinder {
switch (this.aStar.compute()) {
case PathFindResultType.Completed:
this.computeFinished = true
this.path = this.aStar.reconstructPath().map(sn => sn as Tile)
this.path = this.aStar.reconstructPath() as Tile[]
// Remove the start tile
this.path.shift()
return this.nextTile(curr, dst)
+2 -3
View File
@@ -3,7 +3,7 @@ import { AStar, SearchNode } from "./AStar";
import { PathFindResultType } from "./AStar";
export class SerialAStar implements AStar{
export class SerialAStar implements AStar {
private fwdOpenSet: PriorityQueue<{ tile: SearchNode; fScore: number; }>;
private bwdOpenSet: PriorityQueue<{ tile: SearchNode; fScore: number; }>;
private fwdCameFrom: Map<SearchNode, SearchNode>;
@@ -17,7 +17,6 @@ export class SerialAStar implements AStar{
private src: SearchNode,
private dst: SearchNode,
private canMove: (t: SearchNode) => boolean,
private neighbors: (sn: SearchNode) => SearchNode[],
private iterations: number,
private maxTries: number
) {
@@ -85,7 +84,7 @@ export class SerialAStar implements AStar{
}
private expandSearchNode(current: SearchNode, isForward: boolean) {
for (const neighbor of this.neighbors(current)) {
for (const neighbor of current.neighbors()) {
if (neighbor !== (isForward ? this.dst : this.src) && !this.canMove(neighbor)) continue;
const gScore = isForward ? this.fwdGScore : this.bwdGScore;