import type { Aabb } from "../world/geometry.js"; export type NavPoint = readonly [number, number]; export interface NavGridConfig { bounds: Aabb; cellSize: number; /** Allow 8-neighbour movement (no corner cutting). Default true. */ diagonal?: boolean; } export interface NavCell { col: number; row: number; } export interface FindPathOptions { /** String-pull the raw grid path into straight runs where line-of-sight is clear. Default true. */ smooth?: boolean; /** Diameter of the mover in world units — blocks cells within this margin of an obstacle. Default 0. */ clearance?: number; /** Multiplier (>=1) applied to the base cost of stepping from one cell center to a neighbour's. Use to penalize slopes, terrain, etc. */ stepCost?: (from: NavPoint, to: NavPoint) => number; /** Additional edge/shortcut policy. Called after grid occupancy checks. */ canTraverse?: (from: NavPoint, to: NavPoint) => boolean; /** Maximum expanded cells. Omit for the legacy whole-grid search. */ maxNodes?: number; } export interface NavGrid { readonly cols: number; readonly rows: number; readonly cellSize: number; readonly bounds: Aabb; readonly diagonal: boolean; isWalkable(col: number, row: number): boolean; setWalkable(col: number, row: number, walkable: boolean): void; blockAabb(aabb: Aabb): void; clearAabb(aabb: Aabb): void; reset(walkable: boolean): void; inBounds(col: number, row: number): boolean; cellAt(point: NavPoint): NavCell; center(col: number, row: number): NavPoint; /** Nearest walkable cell to a point (spiral search); null if the whole grid is blocked. */ nearestWalkable(point: NavPoint): NavCell | null; /** Unobstructed straight line between two world points (supercover cell walk). */ lineOfSight(from: NavPoint, to: NavPoint): boolean; } export declare function createNavGrid(config: NavGridConfig): NavGrid; /** * A* over the walkable grid. Returns a polyline of world-space `[x, z]` waypoints * from `from` to `to`, or `null` when no route exists. Blocked start/goal snap to * the nearest walkable cell so a click on an obstacle still routes to its edge. */ export declare function findPath(grid: NavGrid, from: NavPoint, to: NavPoint, options?: FindPathOptions): NavPoint[] | null; /** Bounded grid search distinguishes exhausted work from a proven unreachable goal. */ export type FindPathResult = { status: "path"; points: NavPoint[]; visited: number; } | { status: "no-path" | "budget"; visited: number; }; /** * Same endpoint snapping as {@link findPath}, with explicit search-budget exhaustion. * @capability bounded-grid-route distinguish no path from exhausted grid search work */ export declare function findPathResult(grid: NavGrid, from: NavPoint, to: NavPoint, options?: FindPathOptions): FindPathResult; /** * `FindPathOptions.stepCost` factory that penalizes steep terrain: cost is * `1 + weight * |Δheight| / horizontalDistance`, so with the default weight a * 45° slope roughly doubles the step cost. */ export declare function slopeStepCost(field: { sampleHeight(x: number, z: number): number; }, weight?: number): (from: NavPoint, to: NavPoint) => number; /** Remove waypoints the mover can skip because it has clear line-of-sight past them. */ export declare function smoothPath(grid: NavGrid, points: readonly NavPoint[], canTraverse?: (from: NavPoint, to: NavPoint) => boolean): NavPoint[];