mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-22 10:28:13 +00:00
69e422d35e
- Updated the design notes to clarify the multi-source, any-target BFS approach for boat routing on a water-only grid. - Simplified the explanation of the algorithm, focusing on the use of a virtual super-source and super-target. - Enhanced the API description, detailing the return value structure and movement model. - Added performance optimizations, including the use of typed arrays and precomputation of water component IDs to improve routing efficiency.
2.3 KiB
2.3 KiB
MultiSourceAnyTargetBFS (boats) — design notes
What we’re doing
Boat routing is now a single, sound multi-source / any-target shortest-path solve on a water-only grid. For equal cost edges, that’s just BFS.
The mental model is the classic “virtual super-source / super-target” trick:
- Pretend there is a
STARTnode with 0-cost edges to every sourceS. - Pretend every target
Dhas a 0-cost edge to anENDnode. - Run shortest path
START → END.
We don’t build those nodes: we seed the queue with all sources, and we stop when we dequeue any target.
API shape
Return value: { source, target, path } | null
source: which seed-origin won (useful when seeds are water-adjacent tiles but the origin is a shore tile).target: the water tile we reached (usually adjacent to the chosen landing shore).path: water path as a list ofTileRefto cache and replay (no per-tick pathfinding).
Movement model (boats)
- Traversal:
gm.isWater(tile)only. - Neighbors: king moves (8-neighbor / Chebyshev) by default.
- No-corner-cutting: diagonal is only allowed if both touching orthogonals are water.
- All moves cost 1, so BFS is optimal.
Performance wins (the non-negotiables)
- Use typed arrays + stamps (no
Set/Mapin the inner loop). - Precompute water-body component IDs once per map instance (
WaterComponents.ts) and filter sources/targets:- If source component ≠ target component, skip it (ocean vs lake becomes O(1) reject).
- This makes “impossible” routes cheap and lets us delete hacky visited-count early exits.
How this integrates (transport/trade/warships)
- Destination selection stays “near click”: pick a bounded set of landing shore candidates, then convert to adjacent water targets.
- Source selection stays bounded (sampling/extrema/etc), then convert to adjacent water seeds.
- Compute the route once on launch/init, cache
path, and only advance an index during ticks. - Retreat follows the existing cached path backwards (no recompute).
Current known waste
If the client pre-queries and the server recomputes, you will see two searches for a single action. We should ensure we only do one solve per user action (exact mechanism TBD: remove the pre-query, or reuse/publish the computed route).