Behavior pathfinding architecture — support A*↔Dijkstra spectrum, multi-root, and custom heuristics #315
Labels
No labels
Alpha Release Requirement
Bugfix
Demo Target
Documentation
Major Feature
Minor Feature
priority:tier1-active
priority:tier2-foundation
priority:tier3-future
priority:tier4-deferred
Refactoring & Cleanup
system:animation
system:documentation
system:grid
system:input
system:performance
system:procgen
system:python-binding
system:rendering
system:ui-hierarchy
Tiny Feature
workflow:blocked
workflow:needs-benchmark
workflow:needs-documentation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
john/McRogueFace#315
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
The Phase 3 behavior system (#300, #302) uses
DijkstraMapas the distance-field source for SEEK/FLEE behaviors. This works, but it hard-wires the behavior system to one end of the pathfinding cost/accuracy spectrum. The engine already ships bothDijkstraMap(exhaustive field from a root, viaGrid.get_dijkstra_map()) andAStarPath(directed search with heuristic, viaGrid.find_path()). Behaviors should be free to use either — or anything in between.The pathfinding spectrum
With a heuristic function
h(x, y → goal):h = 0→ A* degenerates into Dijkstra (explores everything, optimal)h = true_distance→ A* is perfect (direct line, optimal)A single A* implementation with a pluggable heuristic covers the whole spectrum. That is the design behind the
libtcod-headlessbranchfeature/pathfinding-nextgen-demo.Upstream features —
libtcod-headlessbranchfeature/pathfinding-nextgen-demoAll four commits already exist on the branch; this ticket brings them into McRogueFace as first-class Python API and demonstrates them in the behavior system.
Custom A* heuristic callback (commit
a4080eba)TCOD_heuristic_func_t— callback typefloat(int x, int y, int gx, int gy, void* userdata)TCOD_path_new_using_function_ex(...)— create pathfinder with custom heuristic and weightTCOD_path_set_heuristic(...)— swap heuristics on an existing pathfinderTCOD_path_set_cells()checks for a custom function before falling back to EuclideanBuilt-in heuristics (commit
8bb0a468)Five pre-built functions passable to the callback slot:
euclidean(default, admissible, slowest-but-optimal)manhattan(admissible on 4-connected grids)chebyshev(admissible on 8-connected grids with cost-1 diagonals)diagonal(octile — admissible on 8-connected grids with √2 diagonals)zero(explicitly converts A* into Dijkstra — single code path, no branching required)Multi-root Dijkstra (commit
b61b87e1)TCOD_dijkstra_compute_multi(...)— distance field from N root positions simultaneously, cell value = distance to nearest rootTCOD_dijkstra_compute_masked(...)— takes auint8_tbitmap mask of roots (perfect fit for a DiscreteMap over the grid)Use cases:
threat" — one pass instead of NFlee utilities (commit
162412af)TCOD_dijkstra_invert(...)— transforms a distance map into a safety map (far = high value). Close cells become dangerous, far cells become safe.TCOD_dijkstra_get_descent(...)— follow the gradient to the nearest lower-distance neighbor. One-step lookahead.Together these enable FLEE in three lines: compute multi-root Dijkstra from threats → invert → descent from current cell → move there.
Engine-side work
1.
PathProviderabstraction onEntityBehaviorCurrently the behavior struct types its path field as
DijkstraMap(see #300, ROADMAP Phase 3a). Replace with a handle that can wrap any of:AStarPathDijkstraMap(single root)Common interface:
next_step(from_pos) -> cell | noneis_stale() -> boolrecompute()to_heightmap() -> HeightMap(for persistence — companion to #294's DiscreteMap serialization)2. SEEK / FLEE behavior redesign
Separate target policy from pathfinding policy:
Grid/turn manager resolves target → cells, hands to a PathProvider, asks for next step each turn.
3. Python surface
Demo strategy
The nextgen branch isn't merged upstream yet. The fastest path to upstream merge is demonstrating the features inside a real engine. McRogueFace behaviors are a natural fit: a side-by-side demo showing Dijkstra flood vs. weighted A* vs. multi-root flee, animated with guard entities, would be compelling review material.
Plan:
feature/pathfinding-nextgen-demosubmodule branchtests/demo/screens/(pathfinding comparison with live entity movement)Related
DijkstraMap; becomesPathProviderentity.perspective_map(companion Phase 4.5 — visibility storage, orthogonal to this)Dependencies
libtcod-headlessbranchfeature/pathfinding-nextgen-demoin the submodule (or building against it directly until upstream merges).Out of scope