Skip to content

feat(nav): renderoni/nav — tiled grid A*, expedition router, spatial hash - #41

Open
cmaycumber wants to merge 1 commit into
elemarin:mainfrom
cmaycumber:feat/nav
Open

cmaycumber wants to merge 1 commit into
elemarin:mainfrom
cmaycumber:feat/nav

Conversation

@cmaycumber

Copy link
Copy Markdown
Contributor

A new renderoni/nav entry point: grid pathfinding for large worlds, extracted from a shipping game.

  • NavGrid: generic over a NavCostField the game supplies (size, cellCost(x, z), optional coarseWalkable/passable for far-away queries that must not build tiles).
    • Tiles are sampled lazily and LRU-evicted, with pooled arrays.
    • Blockers (buildings) are re-applied when a tile rebuilds.
    • A* runs in a bounded window with generation-stamped scratch and a typed-array heap, so there's no per-search allocation.
    • It also offers nearestWalkable, lineClear, segmentWalkable and prewarm.
    • Cell size, tile size, tile cap, window, node budget, easy cost and blocker slack are all options.
  • ExpeditionRouter: joins complete local paths into long corridors across the map against a small RouterNav interface, with a ticketed request API.
  • SpatialHash<T>: a neighbour-query grid over anything with position: { x, z }.

The game now supplies only its cost rules (water, cliffs, slope, roads) and uses these classes directly. Its 496-test suite passes on them, including long-range navigation tests.

Verification: typecheck, build, 246/246 tests.

🤖 Generated with Claude Code

…atial hash

NavGrid is generic over a NavCostField the game supplies (size, cellCost,
optional coarseWalkable/passable). Tiles are sampled lazily and LRU-evicted
(evicted arrays are pooled), blockers are re-applied on rebuild, and A* runs
in a bounded window with generation-stamped scratch and a typed-array heap.
Cell size, tile size, tile cap, window, budget, easy-cost and blocker slack
are options; defaults reproduce the Sunder March grid exactly.

ExpeditionRouter joins complete local paths into long corridors against a
small RouterNav interface. SpatialHash<T> works over anything with a
position {x, z}.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@elemarin elemarin left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is well built. The lazy tiles, re-applying blockers on rebuild, and the stamped typed-array A* all check out. Build, typecheck and tests (246/246) pass, and I found no correctness bugs in the A* itself.

Before merge:

  1. Router input validation: an out-of-bounds or unwalkable goal burns about 1,800 local searches before failing. Please check inBounds/walkable in request() and return blocked immediately.
  2. minSpacing: halving can undershoot the floor (100 → 50 → 25). Please clamp with Math.max(minSpacing, spacing / 2).
  3. Costs below 1: the octile heuristic is only admissible for costs ≥ 1, so "fast" cells such as roads give non-optimal paths. Please add a minCost scale or document it.
  4. Generalize: please rename ExpeditionRouter to something like RoutePlanner and drop the house/door/road wording. Use an enum reason instead of English UI strings, and plain {x, z} instead of three's Vector2. Router defaults would be better scaled from nav.cell than absolute metres.
  5. Hardening: please add invalidate(x, z, r) for runtime cost changes, guard SpatialHash against non-finite radius and out-of-range coordinates, and validate n <= 46340 (Int32 index math).
  6. Docs: please soften the "allocation-free" wording in AGENTS.md. The router allocates string keys and arrays per update.
  7. Tests: please add cases for router failure paths, costs below 1, and SpatialHash with negative and far coordinates.

Note: this will need a small AGENTS.md rebase after #39 and #40 land.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants