I'm trying to solve a pathfinding problem. I've read that it's possible to precompute a table of pathfinding routes based on a static map of nodes, thus making pathfinding from one particular node to another very easy at runtime.

Consider this image:

In the image above, the level is comprised of a grid-based layout, with either 'walkable' or 'non walkable' tiles. Therefore, the possible range of tiles that can be walked upon are any that show as white (clear) in the diagram.

Taking the example in the image, I want to be able to select any random point on the grid - shown in the image as the red dot - and have the player walk to that location, taking the 'best route' possible.

I know about A*, but I've also read that precomputed paths is also a worthwhile direction to go in. Considering the grid size of this game is likely to only be around the 20 x 20 mark (400 tiles) would this be a worthwhile way of calculating paths? Although I sure that A* has innumerable benefits - the structure of the levels will never (ever) change, so surely a dynamic run-time solution isn't required?

If it's 20x20 then forget about optimizing and just select the pathfinding you like the best (unless you are doing something really unusual with these 20x20 map like 100 units that do pathfinding per tile).

As for nodes, I never did these but it is for rather big maps. For something that small most likely it will have an opposte effect and hinder the overall performance (I think).

Is there anything that will ever cause a blockage, like an 'enemy' positioning itself on the map? If so, precomputed paths are completely worthless.

Further, you wouldn't want to store the actual path, instead you'd want the cost from this tile to a specific goal. However, even doing that is going to be expensive. It's going t be approximately N*N, where N = X*Y. And that's just for a single room.

If you're not going to have variable cost ground movement, then you can use A* with just euclidean or Manhattan and get pretty good results.

If its a very very tiny map. (your map would qualify) then you dont even need a pathfinding algoryth.

Give each walkable tile a number. (you have 65)

Then (by hand) note down for each tile in wich direction you must walk (lets say you use 4 directions)to reach another tilenumner.

This would build a map, wich can pathfind from any position to any other position without any! pathfinding at runtime.The Agent just need to know its current location, the target location, and then choose the direction (stores in the current tile) to walk to.

Example, you are on the blue-dot tile (tile number 23), going to red tile number (56)You have to go westas you store for each tile in tile number 23 where to golike (N,S,E,W for directions)Thus Reaching node 28, where you go south.. etc.

1 N2 N...10 E11 E12 S...22 W23 W...

Ok this sounds silly, but I actually did something like that years ago with a shooter-map having around 100 nodes.But using some graphical method to speed this up a lot.

--------------

Technically you can let the computer precompute the path-node storage of course using A*, a flood-fill or any other pathfinding method.

10 Years ago it would have even made technical sense on slow (nokia) JavaME phones.

The problem with precomputing is the insane amount of memory that is needed for it. For example, you can store a direction to every other tile in each tile for only two bits each, but this still balloons up insanely:

I understand how you feel about making the runtime simpler (and maybe more predictable). I'm interested in your findings, because I might do similar for the maps in my game (currently I just compute paths with A* at runtime).

Keep in mind that pre-computed paths might require a lot of data (the directional technique suggested by Damocles sounds like a fine way to store the pathing in the map, but heed theagentd's warning). It depends on whether you need to reduce runtime CPU or RAM (if either are really a constraint).

One reason to use pre-computed paths is if you need to hand-tweak something. For instance, A* might give an optimal path, but for whatever gameplay purposes, you might want to offer a different route from some A to B. You could feasibly hand-tweak the paths if the application simply uses static data. Then again, you can also include weighted nodes in A* to make some nodes "heavier" (less desirable for pathing).

The simplest answer is probably just to implement a simple A* algorithm.

O_O I have no idea what you just said, but please elaborate. What previously calculated 2D grid?

You start with a generating a distance map to with (X,Y) as starting point. You process the distance-map, and turn it into a flow-map (X/N/W/S/E).You start with a generating a distance map to with (X+1,Y) as starting point. You process the distance-map, and turn it into a flow-map (X/N/W/S/E).

Now you diff the two maps. There will (most likely) be only a fraction of all tiles that have a different value in the flow-map. The most likely places where there will be a difference, will be on the lines (X,*) and (X+1, *), and the grid (X-1..X+2, Y-1...Y+1), you can make a special case for these, as it's probably simply swapping those lines, and moving that 3x3 sub-grid along the X axis. After that, you calculate the diff of these flow-maps that you predict will be there, for even less mismatches. I think that on average, with these additional corrections, you're dealing with a handful of tiles with a different value.

You have your first distance-map fully stored in a Map<Coord, Direction> collection.The second distance-map only holds the tiles that were modified.

When you lookup a distance-map for layer N, you iterate over all the entries of the diff-map of layer N. Every tile that does not have a value, can be looked up in the layer beneath it, until you reach the root, which by definition holds all tiles in the grid (as it's a diff-map of layer 0 and Nothing).

Basically, you can compare it with a lossless video codec, with very specific knowledge of the coherence of frames.

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

Thanks, everybody, for the insightful and helpful posts on my original question.

Given that the tile grid size example I gave could possibly be increased somewhat (maybe 50 x 50?), I'm reticent to choose a solution that could balloon memory usage - especially since there's every possibility that the game may end up on a mobile device where memory is a pretty valuable resource.

I'll likely follow the advice given in avoiding precomputed pathfinding for that very reason.

Regarding A-star, is there (and I hate myself for saying this) such a thing as a 'dummies guide'. The engine itself is fully tile-based, being a roguelike game, and therefore things like distances between one position and the next will remain constant (i.e. by the tile size for lateral movement, or with the square root of the squares of the 2 tile sides for diagonal movement). I have no idea if this simplifies A*, but part of me doubts it.

I'm fairly well versed in the language, but this will be first time for delving into pathfinding - so I'm ideally looking for a resource online that can lead me gently on this topic! I'm sure someone out there knows of a very useful and easily comprehendable resource

Thanks again for all your help - and any you can offer re: an A* learning resource.

A* is indeed made easy by being on a grid, since the obvious heuristic is "Manhattan Distance", the trivially computed number of grid squares you'd have to move if there was nothing in the way.

A roguelike with lots of rooms with exits lends itself very well to hierarchical pathfinding, which is simply where you put every location in a zone, then pathfind between zones. When you discover "waypoints" between zones, you can easily cache the paths between them. A real world example of this would be "to get from Prospect Park in Brooklyn to the Bronx Zoo, drive through Queens or Manhattan"

I do have a question about what you're intending to make. Because I can't really think of a game that needs a pathfinder that functions on a completely static map. Maybe the walls/floor tiles won't change, but typically there will be something like objects/entities on the map that will change how your path finder will work and which is best for you.

Pathfinding on the last known static map then handling the case of running into obstacles when they're hit or otherwise detected is pretty decent sim behavior. The actors on the map aren't supposed to be omniscient.

As mentioned before, it's a Roguelike game; but I understand your query over the absence of dynamic entities on the map.

I was under the impression (previously) that precomputed paths worked on the basis of providing a specific (precalculated) route from any one position to another. Therefore, on the assumption that the player is moved to each of the intervening positions during the movement phase, I could check for dynamic entities 'en route', so to speak, and handle any potential collisions on the path.

So assuming that a path from A-G took the basic route:

A -> B -> C -> D -> E -> F -> G

The player would start moving from each point to the next. But supposing the player was at position D, and an enemy was on tile E, the player would be stopped on their travels, and have to deal with the encounter - the code preventing the rest of the path from being 'played out'.

Then, once the enemy was defeated (hopefully!), the player would presumably attempt to continue on that path - but the path would now be something like:

E -> F -> G

My reasoning here was that I was under the assumption that a precomputed path provides information about the next node on any particular route - allowing me to 'peek' at that node's location before committing to a move action, thus being able to respond to things like enemies, doors and so forth.

However, for some of the reasons explained above (memory, etc.) I'm going to try and write an implementation of A*.

Thanks to Sproingie's links, I'm starting to get a handle on how it all works - although it does look pretty CPU intensive!

Yes, pathfinding eats tons of CPU, it's easily the biggest CPU hog in a game like Dwarf Fortress (which is why cats are such a bane, since they're always goal-seeking toward vermin or fish bones they pick up, not to mention always getting in the way). Hierarchical pathfinding and caching can help, but you'll still have to budget a lot of CPU for it regardless. There are GPU pathfinding algorithms out there, though none I've been able to find usable source for, let alone actually understand.

Hmmm, could be useful to have a Player based pathfinder for rogue like, however part of the appeal of a rogue like is the control over your movement. It seems to me that instead of having the pathfinder stop on enemy collision, it should stop when a seen enemy crosses your path or something like that.

But this will really depend on how intelligent you want your pathfinder to be, and what part it's going to play in your movement control scheme in game. If you're implementing anything like an 'Explored area' service. You'd only want your A* to function on the known areas (Since you have a map of it), instead of on the unknown portions. Otherwise it leads to really allowing Pathfinder Precognition Syndrome... If you're moving to an unexplored area, you can A* to the nearest known square (The one that renders the 'best expected cost') then best first across the unexplored area, or something like that.

But now I'm just rambling.

For A*, you can cut a lot of corners if you can make assumptions about the map. From what you've said you can:

1) Assume that the first path to a square is likely the best path to a square, which removes the need to ever revisit a tile. (If you need me to explain this, I can).2) Building on 1, if you can only move N,E,S,W then the Manhattan Heuristic is admissible and will always be the best path when you arrive at your goal (If you can move in diagonals, then the Euclidean Heuristic is better).

I just dug up a pathfinding demo applet I made for testing my game's A* implementation. It allows you to place obstacles, a start, and a goal, then watch the A* behavior as it searches for an optimal path:

Sproingie:Taking a game like this into consideration, I daresay that even the most ineffecient pathfinding mechanism will still run acceptibly. Bear in mind that the game I'm making is slightly more traditionally Roguelike - so there are no 'smooth' transitions between tiles - just immediate movement onto the tile's center point, then to the next and so on. This means that the impact of A* (even if horribly implemented) is unlikely to have much impact on how smooth the game feels, or indeed how CPU intensive it seems.

UprightPath:I'll always be using the Manhattan-style algorithm, since there's only 4 directions (as you pointed out). This should mean at the very worst, any one node (barring the origin, of course) should have a maximum of 3 children, cutting down the intensive process involved in checking the diagonals. I know it's all relative, but it should reduce unecessary overhead.

And you're probably right - the first path is likely to be the best, unless I decide to start making horribly designed levels with twisting, turning long passages - but that'd be stupid in the context of this game which is supposed to be more focused towards events happening in rooms, rather than corridors.

This has definitely given me plenty of food for thought. Thanks again for your help and insights.

I just dug up a pathfinding demo applet I made for testing my game's A* implementation. It allows you to place obstacles, a start, and a goal, then watch the A* behavior as it searches for an optimal path:

For some odd reason, Firefox self-combusted upon trying to run the applet. Second time around it doesn't seem to want to load. I was looking forward to seeing it!

I was planning on creating a similar tech-demo myself, in order to further enhance my grounding in the subject. You've pretty much summed up my intended goals in learning this facet of programming. Once I can nail this, that's another string to the bow.

At most three? Does this mean that you have no spaces where you will have a square of eight floor tiles? If you think it's more likely that most of your tiles have have two neighbors, instead of three or four, you can use this to greatly simplify your pathfinding.

For some odd reason, Firefox self-combusted upon trying to run the applet. Second time around it doesn't seem to want to load. I was looking forward to seeing it!

This is exactly what happens when I try to use any applet with the IcedTea Plug-In (in Firefox, in Ubuntu, at least). I've never gotten it to work for me. I've switched to using the Oracle Java Plug-In. (Suggestions welcome at my post on the subject.)

At most three? Does this mean that you have no spaces where you will have a square of eight floor tiles? If you think it's more likely that most of your tiles have have two neighbors, instead of three or four, you can use this to greatly simplify your pathfinding.

Sorry, perhaps I didn't explain it well enough. What I meant was that when expanding a search node, I'd only expand in the available walk directions (up, down, left, right), negating the direction from which I've just calculated the values for. From what I understood, when you examine the next node towards the goal, you'd normal expand in all directions - including diagonals - minus those nodes on your closed list. I was under the impression restricting it based on non-diagonal movements only would speed up the pathfinder testing a little?

Whoops! That was a worthless statement! I just realized what you meant, heh...

Ah, you can do a hierarchical version, which could offer some major increases in you pathfinding speed. Basically, it requires you to sort of ignore the fact that you're on a grid in places. If you have "Hallways" (Places where several tiles only have two neighbors) you can condense hallways into single nodes in your pathfinder. Then, apply your heuristic to the end of these hallways instead of going through each tile in them each time.

This is a sort of pre-processing step that you can do. Basically, your pathfinding map will be different from your displayed map, in that all hallways become a single node, where the path cost is equal to the number of squares that you have to traverse in that hallway. A hallway ends at a room (A collection of more than one tile with three-or-more neighbors) or at intersections (A single tile with three or more neighbors). Then you'll have your 'rooms', your 'intersections' and your 'hallways'. These would become nodes and vertices:

Intersection: Costs '1' to traverse. Holds a set of hallways that lead away. This is the point you find the Manhattan Distance from goal from.Hallway: Costs the hallway's length to traverse it. This is the primary vertex. No actual pathfinding should be done on it, unless your goal is inside of one (In theory, you can also have Deadend hallways, which are only important if the start/end of the path is in one).Room: Keeps track of entrances (Hallways and Intersections that open onto it), and the distances between entrances.

Pathfinder would function differently based on where you're starting and where you're ending. (I'm using RIH to the abbreviate Rooms/Intersection/Hallway map)1) Starting in a room1.1) Ending in the same room: Pathfind through the room to the end points. Then pathfind from start to each exit (Use the Manhattan distance, actually) and from end point to each exit. If the combination of any two is less than the distance across the room, pathfind from those exits across the RIH and see if any result in a better goal. (SECOND WORST CASE)1.2) Ending in another room: Pathfind to the exits, pathfind across the RIH, then pathfind from the new room's exits to the goal. (WORST CASE)1.3) Ending in an intersection: Pathfind to the exits, then across the RIH to the right intersection.1.4) Ending in a hallway: Pathfind to the exits, then pathfind across the RIH to the hallway's two entrances, then to the place in the hallway (This computation is not costly, since it's just iterating through the hallway).2) Starting in an intersection2.1) Ending in a room: Pathfind across the RIH to the room, then across the room.2.2) Ending in an intersection: Pathfind across the RIH to the other intersection.2.3) Ending in a hallway: Pathfind to the two entrances of the hallway, then check which is the best entrance.3) Starting in a hallway.3.1) Ending in a room: Pathfind across the RIH from the exits of the hallway to the entrances to the room, then across the room.3.2) Ending in an intersection: Pathfind across RIH from the Hallway's exits to the intersection.3.3) Ending in the same hallway: Pathfind through the hallway, then check if there's a better path from end of hallway to end through the RIH.3.4) Ending in a different hallway: Pathfind from the exits to the entrances.

That's probably 'Nodes visited'. A* provides the best efficiency under optimal conditions. If it's not an optimal condition (There is no straight line to the goal), then it'll still be moreefficient than other options.

Because of the backtracking/straight line deviation that you created, it'll exercise a lot more nodes at the start. If you were to have a more direct path, it'd find it much more efficiently.

That's brilliantly explained, thank you. I like the idea of compressing a unified space (like a hallway) into a single point of traversal. As you point out, the cost is simply the 'length' of the hallway.

I could (theoretically) improve upon this a little by implementing the 'forbidden' routes, perhaps as a precalculated step - using the methodology that any concave space is technically impassable (such as a deadend hallway) - and treated as a zone. If the target end point doesn't include this zone, it is effectively dropped from the search graph, since it doesn't contribute in any way to any paths. That way, you'd save N*N additional node checks (where N*N is the area in tiles of the zone in question).

It certainly can be useful. Really, what I just did was explain one style of the Hierarchical system that was mentioned earlier.

If you'd like, I can go a bit deeper into some Graph Theory stuff that will allow you to figure out other, deeper Hierarchies.

However, I do have some questions/cautions to think about that really end up depending on how you're implementing your world.

1) How often are you generating new maps? If you expect that your player will be able to cause new maps to be generated quickly/often, then a lot of preprocessing (Which is what the Hierarchical stuff is) will result in a lot of loading time between maps. Then if you end up throwing maps often as well, such as if the whole dungeon is lost if you return to town, then you'll be wasting a lot of those loading times. (From what I read, you're going to be hand writing the maps? That means that you can manually define the RIH map and the like, rather than leaving that to an algorithm).2) Are you implementing a 'Visited Tile/Seen Tile' system? Like, if you just step into your map, will your character have no knowledge of the map? If so, you'll have to figure out how to merge this intelligent/efficient pathfinder, with an exploratory one. Otherwise, you'll end up with the Omniscient Pathfinder Syndrome, or a Cowardly Pathfinder Syndrome. Which is to say, either it'll seem to know where the best path will be upfront, or it'll avoid crossing through unexplored regions when moving between known regions.

I'm glad you asked. I should imagine the following answer will either (a) further complexify or (b) simplify the solution.

The player starts off in a set location in the new map. They are shrounded by a 'fog of war', so to speak, with a view radius of about 3 tiles. Since there is code in place to uncover the 'fog' tiles when the player is within a certain proximity to them, I haven't needed to implement any further complex view mechanics, since everything inside of the 'fog' area is ignored.

Please ignore my horrible graphics! Very early placeholders for now

The player has just entered the map, and can only see within a certain radius.

The player has moved around, and the visited areas are clear to see.

There are intended to be two movement styles in the game - keyboard and mouse. Tapping W,S,A,D moves laterally, whereas clicking can move automatically to a specified tile. The pathfinding was never actually intended for enemy movement, since the enemies will not 'move', per se, but will only implement basic 'back and forth' motion to give the illusion of wandering (either walking back and forth on the X or Y axes).

The intention was to allow the player to click on a tile and have them move automatically to that space - thus needing some kind of pathfinding. It probably doesn't look worth doing in the above screenshots, but it was more for the zoomed out view - like you might see in Desktop Dungeons. The fact that you can't 'click' on a destination tile within the fog area means that scenarios involving pathfinding in 'unknown space' are never going to happen.

In answer to your other question re: the dynamic state of the map - the worst case scenario was to have maybe some locked doors, or impassable tiles that can only be traversed with certain equipped items (slime pit / protective boots etc.). They should be minimal interruptions, at best.

Well, somewhat, but opens up another question. You mentioned, earlier, that you were thinking about how it'd work if it were ported over to a mobile device. To me, that means touch screen controls for the most part. And that seems lead me to think about mouse-only movement.

However, to your earlier question?

Static Dynamics like that don't cause many issues. Because those spots just become another type of node in the RIH map, somewhat like an intersection. You just have a flag check to see if that intersection can be traversed.

Converting the two? Just need to add a visited flag to the RIH map nodes to see if you're allowed to path through it.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org