mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-29 18:32:34 +00:00
Rabbit review
This commit is contained in:
@@ -47,10 +47,18 @@ export class AirPathFinder implements PathFinder<TileRef> {
|
||||
let nextY = y;
|
||||
const ratio = Math.floor(1 + Math.abs(dstY - y) / (Math.abs(dstX - x) + 1));
|
||||
|
||||
if (random.chance(ratio) && x !== dstX) {
|
||||
if (x === dstX) {
|
||||
// Can only move in Y
|
||||
nextY += y < dstY ? 1 : -1;
|
||||
} else if (y === dstY) {
|
||||
// Can only move in X
|
||||
nextX += x < dstX ? 1 : -1;
|
||||
} else {
|
||||
nextY += y < dstY ? 1 : -1;
|
||||
if (random.chance(ratio)) {
|
||||
nextX += x < dstX ? 1 : -1;
|
||||
} else {
|
||||
nextY += y < dstY ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
return this.game.ref(nextX, nextY);
|
||||
|
||||
@@ -102,9 +102,16 @@ export class PathFinderStepper<T> implements SteppingPathFinder<T> {
|
||||
|
||||
findPath(from: T | T[], to: T): T[] | null {
|
||||
if (this.config.preCheck) {
|
||||
const first = Array.isArray(from) ? from[0] : from;
|
||||
const result = this.config.preCheck(first, to);
|
||||
if (result?.status === PathStatus.NOT_FOUND) return null;
|
||||
const fromArray = Array.isArray(from) ? from : [from];
|
||||
|
||||
const allFailed = fromArray.every((f) => {
|
||||
const result = this.config.preCheck!(f, to);
|
||||
return result?.status === PathStatus.NOT_FOUND;
|
||||
});
|
||||
|
||||
if (allFailed) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return this.finder.findPath(from, to);
|
||||
|
||||
@@ -11,12 +11,16 @@ export class MinHeap implements PriorityQueue {
|
||||
private priorities: Float32Array;
|
||||
private size = 0;
|
||||
|
||||
constructor(capacity: number) {
|
||||
constructor(private capacity: number) {
|
||||
this.heap = new Int32Array(capacity);
|
||||
this.priorities = new Float32Array(capacity);
|
||||
}
|
||||
|
||||
push(node: number, priority: number): void {
|
||||
if (this.size >= this.capacity) {
|
||||
throw new Error(`MinHeap capacity exceeded: ${this.capacity}`);
|
||||
}
|
||||
|
||||
let i = this.size++;
|
||||
this.heap[i] = node;
|
||||
this.priorities[i] = priority;
|
||||
|
||||
@@ -18,24 +18,19 @@ export class ShoreCoercingTransformer implements PathFinder<number> {
|
||||
) {}
|
||||
|
||||
findPath(from: TileRef | TileRef[], to: TileRef): TileRef[] | null {
|
||||
// Coerce from tiles
|
||||
const fromArray = Array.isArray(from) ? from : [from];
|
||||
const coercedFromArray: Array<{
|
||||
water: TileRef;
|
||||
original: TileRef | null;
|
||||
}> = [];
|
||||
const waterToOriginal = new Map<TileRef, TileRef | null>();
|
||||
const waterFrom: TileRef[] = [];
|
||||
|
||||
for (const f of fromArray) {
|
||||
const coerced = this.coerceToWater(f);
|
||||
if (coerced.water !== null) {
|
||||
coercedFromArray.push({
|
||||
water: coerced.water,
|
||||
original: coerced.original,
|
||||
});
|
||||
waterFrom.push(coerced.water);
|
||||
waterToOriginal.set(coerced.water, coerced.original);
|
||||
}
|
||||
}
|
||||
|
||||
if (coercedFromArray.length === 0) {
|
||||
if (waterFrom.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -45,52 +40,27 @@ export class ShoreCoercingTransformer implements PathFinder<number> {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build water-only from array
|
||||
const waterFrom =
|
||||
coercedFromArray.length === 1
|
||||
? coercedFromArray[0].water
|
||||
: coercedFromArray.map((c) => c.water);
|
||||
|
||||
// Search on water tiles
|
||||
const path = this.inner.findPath(waterFrom, coercedTo.water);
|
||||
if (!path || path.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Fix extremes: find which source was used and prepend/append originals
|
||||
const result = [...path];
|
||||
|
||||
// Find the original for the source that was used (closest to path start)
|
||||
if (coercedFromArray.length > 0) {
|
||||
const pathStart = result[0];
|
||||
let bestOriginal: TileRef | null = null;
|
||||
let minDist = Infinity;
|
||||
|
||||
for (const { water, original } of coercedFromArray) {
|
||||
if (original !== null) {
|
||||
const dist = this.map.manhattanDist(pathStart, water);
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
bestOriginal = original;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend original if we have one and it's not already at start
|
||||
if (bestOriginal !== null && result[0] !== bestOriginal) {
|
||||
result.unshift(bestOriginal);
|
||||
}
|
||||
// Look up the actual path start in the map
|
||||
const originalShore = waterToOriginal.get(path[0]);
|
||||
if (originalShore !== undefined && originalShore !== null) {
|
||||
path.unshift(originalShore);
|
||||
}
|
||||
|
||||
// Append original to if different
|
||||
if (
|
||||
coercedTo.original !== null &&
|
||||
result[result.length - 1] !== coercedTo.original
|
||||
path[path.length - 1] !== coercedTo.original
|
||||
) {
|
||||
result.push(coercedTo.original);
|
||||
path.push(coercedTo.original);
|
||||
}
|
||||
|
||||
return result;
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* npx tsx tests/pathfinding/benchmark/compare.ts --synthetic <map-name> <adapters>
|
||||
*
|
||||
* Examples:
|
||||
* npx tsx tests/pathfinding/benchmark/compare.ts default hpa,legacy
|
||||
* npx tsx tests/pathfinding/benchmark/compare.ts --synthetic giantworldmap hpa,legacy,a.optimized
|
||||
* npx tsx tests/pathfinding/benchmark/compare.ts default hpa,a.baseline
|
||||
* npx tsx tests/pathfinding/benchmark/compare.ts --synthetic giantworldmap hpa,hpa.cached,a.full
|
||||
*/
|
||||
|
||||
import {
|
||||
@@ -111,17 +111,18 @@ Usage:
|
||||
|
||||
Arguments:
|
||||
<scenario> Name of the scenario (default: "default")
|
||||
<adapters> Comma-separated list of adapters to compare (e.g., "hpa,legacy,a.optimized")
|
||||
<adapters> Comma-separated list of adapters to compare (e.g., "hpa,a.baseline")
|
||||
|
||||
Examples:
|
||||
npx tsx tests/pathfinding/benchmark/compare.ts default hpa,legacy
|
||||
npx tsx tests/pathfinding/benchmark/compare.ts --synthetic giantworldmap hpa,legacy,a.optimized
|
||||
npx tsx tests/pathfinding/benchmark/compare.ts default hpa,a.baseline
|
||||
npx tsx tests/pathfinding/benchmark/compare.ts --synthetic giantworldmap hpa,hpa.cached,a.full
|
||||
|
||||
Available adapters:
|
||||
a.baseline - A* on minimap (inlined)
|
||||
a.generic - A* on minimap (adapter)
|
||||
a.full - A* on full map
|
||||
hpa - Hierarchical pathfinding (no cache)
|
||||
hpa.cached - Hierarchical pathfinding (with cache)
|
||||
legacy - Legacy A* algorithm
|
||||
a.optimized - Optimized A* algorithm
|
||||
`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user