Skip to content

Advanced Pathfinding Algorithms

This page covers advanced pathfinding algorithms in @esengine/pathfinding for performance-sensitive scenarios.

A unified high-performance grid pathfinder with three configurable modes:

import { createGridPathfinder, GridMap } from '@esengine/pathfinding';
const grid = new GridMap(500, 500);
// fast mode (default) - suitable for medium to large maps
const pathfinder = createGridPathfinder(grid, { mode: 'fast' });
// bidirectional mode - suitable for very large open maps
const biPathfinder = createGridPathfinder(grid, { mode: 'bidirectional' });
// standard mode - basic A*
const basicPathfinder = createGridPathfinder(grid, { mode: 'standard' });
const result = pathfinder.findPath(0, 0, 499, 499);
ModeUse CaseOptimizationPerformance
standardSmall mapsBasic A*Baseline
fastMedium-large mapsTypedArray + version reset~1.5-2x faster
bidirectionalVery large open mapsDual-direction search~2-3x faster on large maps
function chooseMode(width: number, height: number): GridPathfinderMode {
const size = width * height;
if (size < 10000) return 'standard'; // < 100x100
if (size < 250000) return 'fast'; // < 500x500
return 'bidirectional'; // Large open maps
}

Jump Point Search algorithm, 10-100x faster than A* on open maps.

import { createJPSPathfinder, GridMap } from '@esengine/pathfinding';
const grid = new GridMap(300, 300);
const jps = createJPSPathfinder(grid);
const result = jps.findPath(0, 0, 299, 299);
console.log('Nodes searched:', result.nodesSearched); // Much fewer than A*

JPS “jumps” over symmetric paths, only expanding nodes at:

  • Start and end points
  • Turning points (forced neighbors)
  • Jump endpoints
Map TypeJPS AdvantageNotes
Open terrain10-100x fewer nodesBest performance
Scattered obstacles3-10x fewer nodesStill beneficial
Maze-like1-2xMinimal advantage
// ✅ Good for JPS
// - Open grasslands, desert terrain
// - Sparse obstacles
// - High-frequency pathfinding
// ❌ Not ideal for JPS
// - Maze-like maps
// - Very dense obstacles
// - Non-diagonal movement required

Hierarchical Pathfinding A* for very large maps.

import { createHPAPathfinder, GridMap } from '@esengine/pathfinding';
const grid = new GridMap(1000, 1000);
// Create HPA* pathfinder
const hpa = createHPAPathfinder(grid, {
clusterSize: 32, // Cluster size
});
// Preprocess (build hierarchical graph)
hpa.preprocess();
// Find path
const result = hpa.findPath(10, 10, 990, 990);
  1. Clustering: Divide map into clusters
  2. Entrances: Identify inter-cluster passages
  3. Abstract Graph: Build cluster connectivity graph
  4. Hierarchical Search: Search abstract graph first, then refine within clusters
interface IHPAConfig {
clusterSize: number; // Cluster size, default 64
maxEntranceWidth: number; // Max entrance width, default 16
cacheInternalPaths: boolean; // Internal path caching, default true
entranceStrategy?: 'middle' | 'end'; // Entrance strategy, default 'end'
lazyIntraEdges?: boolean; // Lazy intra-edge computation, default true
}
Cluster SizePreprocess TimeSearch SpeedMemory
10x10LongerFasterHigher
20x20MediumMediumMedium
40x40ShorterSlowerLower
// ✅ Good for HPA*
// - Very large maps (1000x1000+)
// - Relatively stable map structure
// - Many pathfinding requests
// ❌ Not ideal for HPA*
// - Small maps (preprocessing overhead not worth it)
// - Frequently changing maps
// - Single pathfinding scenarios
// Need to reprocess when obstacles change
grid.setWalkable(100, 100, false);
hpa.preprocess(); // Rebuild hierarchical graph

Cache repeated pathfinding requests for significant speedup:

import { createPathCache, createAStarPathfinder } from '@esengine/pathfinding';
const pathfinder = createAStarPathfinder(grid);
// Create cache
const cache = createPathCache({
maxEntries: 1000, // Max cache entries
ttlMs: 60000, // TTL in milliseconds
});
// Cached pathfinding
function findPathCached(sx: number, sy: number, ex: number, ey: number) {
const key = `${sx},${sy}-${ex},${ey}`;
const cached = cache.get(key);
if (cached) return cached;
const result = pathfinder.findPath(sx, sy, ex, ey);
cache.set(key, result);
return result;
}
StrategyDescriptionUse Case
Exact matchSame start and endFixed targets (buildings)
Region matchStart/end in same regionMany agents going to similar locations
TTL expiryAuto-clear after timeoutMaps that change
Need to choose a pathfinding algorithm?
├── Map < 100x100?
│ └── AStarPathfinder or GridPathfinder(standard)
├── Map 100x100 ~ 500x500?
│ ├── Open terrain? → JPSPathfinder
│ └── Has obstacles? → GridPathfinder(fast)
├── Map > 500x500?
│ ├── Open terrain? → GridPathfinder(bidirectional)
│ └── Many pathfinding requests? → HPAPathfinder
└── Need non-blocking?
└── IncrementalAStarPathfinder

Diagonal path on 500x500 open map (0,0 → 499,499):

AlgorithmTimeNodes Searched
A*~3ms~500
GridPathfinder(fast)~1.5ms~500
GridPathfinder(bidirectional)~1ms~250
JPS~0.5ms~3
HPA* (after preprocess)~0.2ms-

Actual performance varies by map structure and hardware