This thread reminds me of some experiments I was working on last year trying to make a fast "item finder" algorithm, where I was mainly focused on making trips between levels more efficient, or (where possible) avoid such trips if they are actually detours. I think this might potentially be useful to combine with other algorithms discussed here that mainly concentrate on making travel on 2D maps more efficient.
My goal was to help fix the old problem of dwarves choosing a target item that's below them on the next level, and then taking a huge detour to actually get there (and especially when walking past many other other items of the same type along the detour). It's based on a distance estimate heuristic intended as a replacement for the current 3D Manhattan distance that's apparently currently used for that purpose, while still being cheap enough to calculate when searching tens of thousands of candidates. That estimate can also be used as a distance heuristic for A* search.
The core idea is that the travel distance from point A to a point B on a different level has a lower bound of (distance from A to the closest stairs or ramp)+(levels between A and B)+(distance from B to the closest stairs or ramp), and that this number can be used as a cheap-to-calculate estimate when trying to choose a target among candidate items, without doing full pathfinding between them. It does this by saving a "distance to the closest level connection" lower bound value for each cell in the map, and updating that grid when the level connections change. These updates are fairly cheap to do, the changes don't need to propagate far to be useful as estimates.
Here's an interactive Javascript demo in case you want to experiment with it:
http://pocketworkstation.org/ofinder/world.htmlThe demo's "Fortress" map has >10000 items, and it searches for the closest candidate(s) among them after each repositioning, intentionally done by a simple loop with no caching. You can select the heuristics used for target item selection and A* pathfinding separately:
- 3D distance: simple 3D distance between start and goal, ignoring stairs and walls, presumably as currently used by DF for target item selection.
- admissible stairs: check distance to stairs (ignoring stair direction) on the starting and ending level only. This is admissible for A* search.
- greedy stairs: sum level-to-level distance estimates for intermediate levels too, and check stair directions assuming a sequential start-to-goal level sequence. This isn't an admissible algorithm and can get confused for "express elevator" style maps, where the closest path going from A to a higher B might involve going down a level first to get to an otherwise-inaccessible direct staircase. But those should be rare for typical fortresses. The A* implementation I used tolerates an inadmissible algorithm, but it might not find the true shortest path in this case.
Let me know if you have questions or comments about this. I've tried to comment the "find.js" code to explain what it's doing, but please don't look too closely at the very hackish gui code ;-)