Bay 12 Games Forum

Dwarf Fortress => DF Suggestions => Topic started by: sockless on January 30, 2011, 11:06:57 pm

Title: Improving Pathfinding. (Computer sciency)
Post by: sockless on January 30, 2011, 11:06:57 pm
I'n not sure exactly how pathfinding is done, but I'm going to take a wild guess and say that every single piece of ground you can walk on is a node and that the entire fortress just makes a giant graph. If this is the case, then I'm not surprised that pathfinding is so slow. I potential solution to this slowness would be for every second square to be a node.

OXOXOXO
XOXOXOX
OXOXOXO
XOXOXOX

Like that.

That way, there would be half as many nodes. After figuring the route out this way, it would be rudimentary to figure out how to get from one node to another, as if they are connected in the graph, then there's a way to get from one to the other.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Max White on January 30, 2011, 11:10:07 pm
That might make finding a lever a little tricky if it is on an odd node, would it not?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: sockless on January 30, 2011, 11:18:26 pm
You could just make the dwarf path to a random node 1 square away from the lever, then walk the one extra square to the lever. Perhaps not 100% efficient, as you might have to walk another couple of squares to get to it.

I guess stairs would have to have a node attached to them as well, regardless of whether they would or not usually.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Max White on January 30, 2011, 11:21:43 pm
Ok, a level was a bad example, because you can set the location when you give the order.

What if, for example, there was a sword on the ground in an odd node, and the dwarf wanted to find the closest sword so he could arm himself. He can't just path to the closest even node, on the basis that then every even node would have to check if the required object was next to it, and all it all the process would take longer.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on January 30, 2011, 11:29:16 pm
What if you had to travel through a single-tile-wide hallway to get to where you were going most efficiently?  If you build a pathfinding system where only diagonal moves are allowed, you wouldn't be able to see horizontal hallways, which are the most common types of hallways built in DF.

You know, there have been quite a few threads on trying to find more efficient pathfinding methods, maybe you could search for and read some of them. 

---

I can't remember a good search term for it, but there was one post that I kept seeing links to that explained how the pathfinding currently works, although obviously I didn't take it well enough to heart to remember a good search term.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: thijser on January 31, 2011, 01:17:41 am
Perhaps there is a better system using this to fill in areas that are not next to walls and simply making every tile next to a wall a node. That way pathing should always work. a bit like this

OXOXOXOXOX
XOXOXOXOXO
OXOXOXOXOX
XXXXXXXXXX
wwwwwwww
w=wall
X=node
O=open space
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on January 31, 2011, 01:38:31 am
How do you know where a wall is?  You have to test it to find out, which is just as costly as testing a node.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: thijser on January 31, 2011, 01:40:44 am
You could lay out this grid during the game itself as the walls are revealed/build. This would add another map but it could also be combined with the travel pathing cost map (low trafic high trafic ext.).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: sockless on January 31, 2011, 02:50:02 am
Another potential way to have less nodes is to cut them down even more, so that you only have a node at every corner/intersection/stair. E.g.

N=node
                +-+
                |N|
                |  |
-----------+ +---------------+
                 N                     N|
-----------+ +------------+  |
                |  |                  |  |

This way you'd have a rather small number of nodes.
Since the nodes are at every point where a dwarf have to make a decision, they don't have to calculate things that would be definite, the problem though, is that it would have difficulty doing large halls, as dorfs would have a tendency to just stick to walls.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on January 31, 2011, 09:55:05 am
Don't forget that pathfinding in DF prefers to use diagonals whenever possible, which means that in corners like the one you just illustrated, they actually never step on those node tiles.  Plus, players tend to have plenty of doors along hallways.

Still, that's an improvement, you're still only trying to make a linear growth improvement, but it's moving towards fitting the practical problem.  One could even try to to turn it into a fractal map where you have larger hub nodes that feed smaller capilary pathfinding nodes, which would be better for pathfinding in labyrinthine dwarf tunnels, but poor for pathfinding in open areas. 

Don't forget that we have both open areas and twisting mazes, and we need a system that works well for both.

Look, while it's great that you want to help, if you're going to really improve something, you have to understand the system that DF is using, and try to work out a better core algorithm.  Dwarf Fortress apparently uses a modified A* pathing function with a manhattan distance heuristic function, and saved accessible/inaccessible states for tiles.

You should look at this thread, at the very least:
http://www.bay12forums.com/smf/index.php?topic=43265.0

and look up the A* and manhattan systems to understand their methods.

DF players (and Toady) know their stuff, and pathfinding has been a known problem for years.  If you have some sort of very simple solution to try to solve pathfinding that doesn't require a detailed knowledge of the inner workings of the algorithm, odds are someone else has thought of it already, and it either is already in use, an improved version of it is in use, or it will not work for one reason or another.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: thijser on January 31, 2011, 10:26:47 am
Maybe we could split inside and outside pathing? That way we can use an efficent methode for both.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on January 31, 2011, 10:49:06 am
You can make large, open environments even "inside", though.  Some people even make large hallways consisting of nothing but up/down stairs so that dwarves can "fly" by moving in every possible direction, since that optimizes pathfinding for A*. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on January 31, 2011, 11:20:46 am
One could even try to to turn it into a fractal map where you have larger hub nodes that feed smaller capilary pathfinding nodes, which would be better for pathfinding in labyrinthine dwarf tunnels, but poor for pathfinding in open areas.

I think we visited this once, where we broke the grid down into chunks of 3x3 grids, and determined all of the possible layouts of 3x3 tiles and their connectivity.
(And the longest path on a 3x3 grid is 5 tiles IIRC)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: thijser on January 31, 2011, 02:14:00 pm
You can make large, open environments even "inside", though.  Some people even make large hallways consisting of nothing but up/down stairs so that dwarves can "fly" by moving in every possible direction, since that optimizes pathfinding for A*.

But on average outside will be more open then inside. 

Another interesting question is how you are going to do ramps vs stairs.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: sockless on January 31, 2011, 07:37:04 pm
How is DF meant to use Manhattan Geometry when dwarves can go in diagonals? Isn't very essence of Manhattan distance that you can only move orthogonally?

But even with the a* algorithm, you could have a node in every second square instead of every single square. That would be faster whatever algorithm you use.

I guess if you did have a node at every corner, like you said, it would suffer horribly in open spaces, as dwarves would just stick to the side.

Really, the best solution, I've decided, would be to just invest time into making the game multi threaded. That would make the game run a lot faster for most people. It's not a solution, but it fixes the symptoms.

Or you could prove that P=nP

PS. thijser, Vous êtes Français?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on January 31, 2011, 07:39:47 pm
But even with the a* algorithm, you could have a node in every second square instead of every single square. That would be faster whatever algorithm you use.

Please....please....please actually read the arguments as to why that is a bad idea.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: sockless on January 31, 2011, 07:57:48 pm
Well you would still be able to move orthogonally, but it will be able to assume that there's a walkable space between 2 connected nodes.
The point about the sword is an interesting one, but right now the dwarf would just look at the nearest as-the-ghost-flies distance and decide to pick up that sword, so with sparser nodes, that wouldn't be affected, it would be the same as if you were pathing to a lever. It would just grab the swords co-ords, then randomly choose a pathable space next to it. Then the dwarf would path to that square, then walk the one square different.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on January 31, 2011, 08:09:34 pm
Well you would still be able to move orthogonally, but it will be able to assume that there's a walkable space between 2 connected nodes.

So now not are you storing nodes, your storing node connections, rather than being able to infer connections because the two nodes are neighboring.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Max White on January 31, 2011, 08:11:45 pm
Dosn't the great Toady one himself have degrees in mathamatics, or softwere or something of that nature? I mean I'm sure he has given this plenty of thought.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: sockless on January 31, 2011, 08:43:45 pm
Yes that is what I'm doing, so you build a graph at the start of the game, then as you mine stuff, it adds it to the graph.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: thijser on February 01, 2011, 12:49:28 am
Of course a third methode for pathing past obstacles is that whenever the computer finds a obstacle it will start to try path next to it. That way it won't have to store as much data.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Silverionmox on February 01, 2011, 02:04:09 pm
Currently the pathfinding is like an amnesiac autist: do everything step by step, include every little detail, and repeat it every time you have to go somewhere.

- Dwarves could pathfind within burrows first, as that is the most likely place to find stuff. Animals could do something similar, at least the territorial ones. Cows/sheep should path to the leading bull/ram of the herd, but don't need much else.
- Dwarves could store frequently used paths, such as from their bedroom to the first high traffic zone (probably a staircase or important connecting corridor). It would be great if the computer could detect central staircases and prefer them for pathfinding.
- Dwarves performing routine tasks should use the above. If something pulls them out of their routine, they could revert to the ordinary, more flexible pathfinding. Adventurer mode will have townsfolk perform routine tasks anyway, so the same code can be reused.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 01, 2011, 02:17:15 pm
Wouldn't storing pathfinding results for "most common paths" lead to a massive consumption of memory, though?  Not that having an ability to trade processor time for memory space is a bad thing, but it can potentially exchange one problem for another if you have enough creatures walking around the map.

I'd expect it would really help with workshops, though, if you have a "prefer items from this stockpile" command that would tell workers to only search for the materials in one particular stockpile before they do a general map search of every single item of that type in the entire fortress, and compare how to path to each one.  You could even store the pathfinding from workshop to stockpile and back, which I'm sure is THE most frequent pathfinding function you perform.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 01, 2011, 03:08:12 pm
I'd expect it would really help with workshops, though, if you have a "prefer items from this stockpile" command that would tell workers to only search for the materials in one particular stockpile before they do a general map search of every single item of that type in the entire fortress, and compare how to path to each one.

I don't think the game paths to each item in that case. It finds the closest item by Cartesian distance and then paths to that one only.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on February 01, 2011, 03:10:15 pm
Currently the pathfinding is like an amnesiac autist: do everything step by step, include every little detail, and repeat it every time you have to go somewhere.

It's a computer program.  Computers can't generalize, at all, ever.  They must perform the repetitive, excessive detail, tasks every time because that's how computers work.  The only way to skip code is to be less accurate or find some way to infer the data without looking at it (i.e. a process that takes less cycles but comes to the same result, such as "that tile is a food stockpile tile" skipping the check that asks if each item in that tile is a stone or not*).

*There could be a stone in that tile, but odds are there isn't.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 01, 2011, 03:12:18 pm
I'd expect it would really help with workshops, though, if you have a "prefer items from this stockpile" command that would tell workers to only search for the materials in one particular stockpile before they do a general map search of every single item of that type in the entire fortress, and compare how to path to each one.

I don't think the game paths to each item in that case. It finds the closest item by Cartesian distance and then paths to that one only.

I know, but that's not the main reason why the game lags, the game lags because every time a stonecrafter at a workshop wants to find something, he has to access a list of every single stone in the fort to then test cartesian distance of each one to find the closest, even if there are tens of thousands of stones to choose from.

If you were restricting the dwarf to searching only the contents of a single stockpile first, then only searching the rest of the entire fortress if he couldn't find what he needed in the stockpile, then you could potentially trim that list of search targets down by quite a bit, and improve overall speed.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Nadaka on February 01, 2011, 03:15:10 pm
every square is a node, it isn't stored as a graph though. It is stored as an array of node entry costs IIRC. Connectivity between nodes is implicit from adjacency.

Its been a while since I got in on one of these pathfinding discussions.

IIRC the path from unit to goal is recalculated at every step, if each unit stored its current path you would cut path finding costs by a factor approximately equivalent to half the length of the average path divided by the frequency that a path becomes invalid. You could check each step to make sure the path is valid and still get a significant boost, or follow the path until it becomes immediately obstructed and save even more time. This does cost some memory, but isn't likely to be significant.

Cutting the number of nodes by 4 is only a linear speadup, comes with some abstraction issues and won't save on memory. It is the same reason that parallel path processing isn't going to be that useful, the average cpu count right now is close to 2.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on February 01, 2011, 03:18:20 pm
every square is a node, it isn't stored as a graph though. It is stored as an array of node entry costs IIRC. Connectivity between nodes is implicit from adjacency.

Precisely my earlier point.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 01, 2011, 03:21:26 pm
The path isn't recalculated with every step.  You can test this to a degree by placing obstacles in the way of a dwarf who has already on deciding to go somewhere.  Locking a door in front of a dwarf when he is intent on going somewhere, like, say, to pick up a sock from a dwarf who died in a goblin ambush, will cause him to smack head-first into the door before he realizes it is now locked (or try to walk into deep water before he realizes his path has flooded), and then try to find a way to path around the obstacle the dwarf now suddenly realizes is in the way.

edit: In fact, when they realize a path is blocked, they will stand still for a while and flash a "?" sign to signify they just walked face-first into a locked door.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Jacob/Lee on February 01, 2011, 03:33:49 pm
There was a whole topic on the pathfinding algorithm some time ago.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Silverionmox on February 01, 2011, 04:27:13 pm
Wouldn't storing pathfinding results for "most common paths" lead to a massive consumption of memory, though?  Not that having an ability to trade processor time for memory space is a bad thing, but it can potentially exchange one problem for another if you have enough creatures walking around the map.

I'd expect it would really help with workshops, though, if you have a "prefer items from this stockpile" command that would tell workers to only search for the materials in one particular stockpile before they do a general map search of every single item of that type in the entire fortress, and compare how to path to each one.  You could even store the pathfinding from workshop to stockpile and back, which I'm sure is THE most frequent pathfinding function you perform.
It's possible to play around with the storage place. If you we're able to link stockpiles to workshops (though IMO stockpiling and workshop tasks could be both optional functions for a room, but that's another matter) then that path could be stored in the workshop. The bedroom to staircase could also be stored at the room's level. I expect these paths to be rather short anyway, but searching a bedroom starting in the storage room area, finding a staircase, and then searching on towards the right bedroom is much, much more CPU intensive that searching from the storage room to a known central staircase, and then retrieving a stored path from the staircase to the room.

The pathfinding could also treat the z-level differently (which makes sense, dwarves can't change z-levels without stairs or the like): check first if the destination is on the same level; if yes, pathfind only on the level; if not, pathfind to a staircase instead. That would make 90% of routes easier, and 5% more difficult, but it's always possible to revert to the standard, cpu-intensive but almost infallible pathfinding.

Currently the pathfinding is like an amnesiac autist: do everything step by step, include every little detail, and repeat it every time you have to go somewhere.

It's a computer program.  Computers can't generalize, at all, ever.  They must perform the repetitive, excessive detail, tasks every time because that's how computers work.  The only way to skip code is to be less accurate or find some way to infer the data without looking at it (i.e. a process that takes less cycles but comes to the same result, such as "that tile is a food stockpile tile" skipping the check that asks if each item in that tile is a stone or not*).

*There could be a stone in that tile, but odds are there isn't.
That's what I mean. Let them use conceptual heuristics, gaining speed at the cost of accuracy. I'd rather have my dwarves make a detour now and then (or get lost) than cut my FPS in half. There's always the option to fall back on the thorough, standard way to do things instead of shortcut.

It's primarily intended for the routine stuff. Invaders, soldiers, scared dwarves, hunters, miners etc. are alert or in an unfamiliar area and pay attention to where they're walking. Scruffgong the food hauler isn't.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on February 01, 2011, 04:30:55 pm
It's a computer program.  Computers can't generalize, at all, ever.  They must perform the repetitive, excessive detail, tasks every time because that's how computers work.  The only way to skip code is to be less accurate or find some way to infer the data without looking at it (i.e. a process that takes less cycles but comes to the same result, such as "that tile is a food stockpile tile" skipping the check that asks if each item in that tile is a stone or not*).

*There could be a stone in that tile, but odds are there isn't.
That's what I mean. Let them use conceptual heuristics, gaining speed at the cost of accuracy. I'd rather have my dwarves make a detour now and then (or get lost) than cut my FPS in half. There's always the option to fall back on the thorough, standard way to do things instead of shortcut.

It's primarily intended for the routine stuff. Invaders, soldiers, scared dwarves, hunters, miners etc. are alert or in an unfamiliar area and pay attention to where they're walking. Scruffgong the food hauler isn't.
[/quote]

There's a difference between "drop every other node" for speed at the expense of accuracy and actually having a better algorithm.

Dropping half the nodes actually makes the speed worse, due to the fact that you can no longer infer node connectivity due to adjacency (thereby requiring you to store the information increasing memor, or to check at function-run-time decreasing speed) among other things.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 01, 2011, 05:09:14 pm
The pathfinding could also treat the z-level differently (which makes sense, dwarves can't change z-levels without stairs or the like): check first if the destination is on the same level; if yes, pathfind only on the level; if not, pathfind to a staircase instead. That would make 90% of routes easier, and 5% more difficult, but it's always possible to revert to the standard, cpu-intensive but almost infallible pathfinding.

How do you know where staircases are, if not by pathfinding?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 01, 2011, 05:17:00 pm
Actually, I'm more concerned about the assumption that all players will make mostly 2-dimensional forts with rare stairwell access.  What about players who purposefully make their fortress more vertical?  I tend to make things fairly vertical to compres my fortress into being as spheroid as possible whenever I'm not going for more elaborate fractal designs.  It's more efficient that way.

Why should a change in the axis you move along change the way that the game calculates how to get from one point to the other, when it basically is as easy (if not easier) to move vertically than horizontally?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 01, 2011, 09:31:17 pm
I know, but that's not the main reason why the game lags, the game lags because every time a stonecrafter at a workshop wants to find something, he has to access a list of every single stone in the fort to then test cartesian distance of each one to find the closest, even if there are tens of thousands of stones to choose from.

I don't think that would be a significant load on the CPU. Locating an item for a reaction is something that only happens infrequently in terms of simulation steps, even if you're churning out mugs by the binful. And it's cheap: the game only needs to find the closest usable item (it doesn't care by how much A is closer than B, just that it's closer), so it can just compare distance squared for one run through the item list. Since that item list is being iterated all the time anyway, for temperature calculations and decay and whatnot, an additional run-through every hundred steps or so is in all likelihood a drop in the bucket. Though empirical evidence could convince me otherwise.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 01, 2011, 09:39:37 pm
Perform the experiment yourself, if you want: go digging up tens of thousands of stone, while you have a dozen or so stonecrafters constantly working.  Turn off temperature in the raws to exclude it from the experiment.  Now, when you have really, really low FPS, backup a save, alter the boiling point of the major layer stones so that you boil away about 80% of the stone in your fortress, and see what it does to your FPS.  Or just shut off all your workshops, and let dwarves idle.

I personally became very well acquainted with the phenomenon when I altered the trade caravans to have enough cargo capacity for the elves to bring in about 20,000 items onto the map at once, which instantly lopped my FPS down to about a fifth of its previous rate.  Yeah, sure, that was with temperature, but it wasn't all temperature, it was my weavers looking at all that rope reed from across the map every time they went looking for something else to perform their jobs with.

The number of items on the map has huge FPS implications, especially since that "number of items" is in the tens or even hundreds of thousands, and is itereated through each time any character wants to do anything with anything.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 01, 2011, 10:05:57 pm
Or just shut off all your workshops, and let dwarves idle.

That's the experiment I'd do; everyone a stonecrafter versus everyone with all labors off, same save, queue up a bunch of crafting jobs. Temperature on or off wouldn't matter as long as it's the same for both trials. My hypothesis is there would be very little difference.

I personally became very well acquainted with the phenomenon when I altered the trade caravans to have enough cargo capacity for the elves to bring in about 20,000 items onto the map at once, which instantly lopped my FPS down to about a fifth of its previous rate.  Yeah, sure, that was with temperature, but it wasn't all temperature, it was my weavers looking at all that rope reed from across the map every time they went looking for something else to perform their jobs with.

Probably more likely due to the existence of all the additional items themselves. How many weavers did you have, and how much could they possibly have been weaving?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 01, 2011, 10:13:09 pm
Between all the food and clothing industries, about 40 dwarves would be using the products that were carried in the caravan.  I had a mostly clothing-based economy.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 01, 2011, 10:44:20 pm
I just tried this out with a community fort from the forums. I turned off all labors except stonecrafting and built enough workshops for everyone, then paused and put repeat rock craft jobs in each one. Then I duped the save and started up two copies of the game and assigned each to its own core. I used Dwarf Therapist to disable all labors in one game, then unpaused both.

The one with all labors disabled initially dropped way down, presumably while they pathed to a meeting zone to idle in. Then both games settled in near the same speed, 20 FPS for the all-stonecrafter game and 18 for the all-idler game.

(My intent was to do the experiment "blind," since I wouldn't know which instance Dwarf Therapist would attach to, but the idler count gave it away.)

This was with around 50 dwarves, of which 30 or so were non-child civilians, and with about 10k stone.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 01, 2011, 10:51:05 pm
Well, if idling takes up more frames than doing work (something, I should point out, NEVER happens for me, I tend to notice that running out of wood and having my carpenters all idle makes my FPS shoot up about 5 to 10 points), then it implies that something entirely different is happening. 

If, as is your hypothesis, there is negligible impact on the time spent on populating lists of objects for the purposes of finding one to pathfind to, then the framerates should be the same - having it actually drop for idling implies something else is suddenly taking up their processor time.

I'd have to ask how much stone there is laying about in the fortress you tested this on, for starters, on the inventory screen.  I'd also have to ask how far away they were going to get it.  Also, what the idlers were actually doing.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 01, 2011, 11:04:31 pm
I'd have to ask how much stone there is laying about in the fortress you tested this on, for starters, on the inventory screen.  I'd also have to ask how far away they were going to get it.  Also, what the idlers were actually doing.

It was just a random fort I grabbed, but the stone looked like it was "everywhere," just sort of strewn about. I forget the exact number, but it was somewhere in 10-20,000. How far they were going to get it shouldn't make a difference if the CPU load is due to choosing which stone to find.

If, as is your hypothesis, there is negligible impact on the time spent on populating lists of objects for the purposes of finding one to pathfind to, then the framerates should be the same - having it actually drop for idling implies something else is suddenly taking up their processor time.

My guess would be that idle dwarves have to regularly check to see if there are other jobs that need doing (even with labors disabled they can deconstruct or whatever), but whatever it was was enough to, ah, dwarf the cost of looking for stones to craft.

Anyway, that's all for the "further questions" section of the proper lab report. Feel free to reproduce, tweak the experimental design, &c. I'm satisfied that I didn't see any dramatic slowdown due to searching for reaction items.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Max White on February 01, 2011, 11:10:30 pm
This still going on?
Yes, stone and other large amount of objects cause lag. I mean I can only assume this is because your computer is busy handling virtual memmory, but that would imply that somehow DF has eatern your ram alive... Well that does sort of sound reasonable.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Silverionmox on February 02, 2011, 12:46:55 pm
The pathfinding could also treat the z-level differently (which makes sense, dwarves can't change z-levels without stairs or the like): check first if the destination is on the same level; if yes, pathfind only on the level; if not, pathfind to a staircase instead. That would make 90% of routes easier, and 5% more difficult, but it's always possible to revert to the standard, cpu-intensive but almost infallible pathfinding.

How do you know where staircases are, if not by pathfinding?
Staircases in general don't move that often, so if you can identify the big ones, you can use their location again and again without pathfinding again. The drawback is that your dwarves will act a bit confused when, for example, the staircase collapses... but that only adds to the verisimilitude - when a staircase collapses, it does confuse people.

Actually, I'm more concerned about the assumption that all players will make mostly 2-dimensional forts with rare stairwell access.  What about players who purposefully make their fortress more vertical?  I tend to make things fairly vertical to compress my fortress into being as spheroid as possible whenever I'm not going for more elaborate fractal designs.  It's more efficient that way.

Why should a change in the axis you move along change the way that the game calculates how to get from one point to the other, when it basically is as easy (if not easier) to move vertically than horizontally?
Ah, but dwarves are restricted by gravity and walk on the x-y plane. They don't walk along the y-z or x-z plane. In addition, workshops, stockpiles and the like can't be built vertically.

There should obviously be a limit to the efforts of the program to identify the staircases. If there are too many of them, it becomes pointless to identify them. The same with corridors: if there's a central broad hallway with sideways, it makes sense to identify it; but in a maze, don't bother.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: ullrich on February 02, 2011, 10:47:41 pm
You should look at this thread, at the very least:
http://www.bay12forums.com/smf/index.php?topic=43265.0
and look up the A* and manhattan systems to understand their methods.

If he's just using A* with manhattan, regardless of programming optimization, how hard is it to just change the heuristic function, since manhattan weighting can be massively improved with a tie breaker, I have done a project during one of my AI courses which pitted various algorithms against each other on a 2D maze (25x25), these are the results (# of nodes searched to find path):

End in a Room, 1 entrance, close.  Opposite Side of Map, multiple paths.  Opposite Corners of Map, multiple paths. 
Depth-First (not optimal)783181
Breath-First376250488
A* (Euclidian)16394380
A* (Manhattan)7781340
A* (Vector)4872117


The Manhattan weighting is |x1-x2|+|y1-y2|, in 3D it should be |x1-x2|+|y1-y2|+|z2-z1|.
The vector weighting adds onto Manhattan using the cross product, and modifies the values to be less than 1, thereby allowing 2 nodes of value x to be differentiated from so say 2.1 and 2.2 rather than just 2 & 2 forcing both to be expanded.

The formula in 2D is (the 2 vectors are start-end, and node-end): (0 is start location, 2 = end location, 1 is current location/node)
dx1 = x1-x2
dx2 = x0-x2
dy1 = y1-y2
dy2 = y0-y2
CrossProduct = |dx1*dy2 - dx2*dy1|
For my application this was multiplied by 0.001 to ensure this value was never > than 1 but this could be modified upon map creation by taking the max possible cross product +1 as a divider, however in 3D space the cross product is not scalar but another vector, so I'm not entirely sure how to parse that into something meaningful, perhaps a smaller magnitude of a vector, I'm an engineer I'm sure a Mathy could figure something more useful out for 3D (the goal is the path that is more direct between start and end, so a smaller difference between the 2 vectors).

In 3D it would be:
dx1,dx2,dy1,dy2=same as above
dz1 = z1 - z2
dz2 = z0 - z2
CrossProduct = (dy1*dz2-dz1*dy2)i+(dz1*dx2-dx1*dz2)j+(dx1*dy2-dy1*dx2)k

Basically as long as the additional calculations take up less time than the number of nodes that are expanded (which each require further calculations) it is better, and in general mathematics are faster than node handling anyway on a computer.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Kumquat on February 03, 2011, 12:27:37 pm
DF isn't using Manhattan distance.

It is using Max(|x1-x2|,|y1-y2|,|z1-z2|).

If it was using Manhattan then a mason workshop making blocks in a quarry would clear out a diamond-shaped area. Now it clears a square/cube area.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 03, 2011, 01:18:21 pm
DF isn't using Manhattan distance.

It is using Max(|x1-x2|,|y1-y2|,|z1-z2|).

If it was using Manhattan then a mason workshop making blocks in a quarry would clear out a diamond-shaped area. Now it clears a square/cube area.

The algorithm used to decide which input item to use for a reaction is different than the algorithm used as the heuristic in A*.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Coaldiamond on February 17, 2011, 10:18:49 pm
Lets switch tracks for a minute.

I was about to ask Toady this one directly, since I can't find a direct answer in my forum searches. Maybe the B12 forum can deliver?

Question: Has Toady ever mentioned taking the principle of stigmergy from the ACO scheme in order to dynamically modify the PATH_COST value for tiles as dwarves travel over those tiles? My thought is that since we can already improve framerate by manually designating High Traffic Areas, perhaps inserting some code to dynamically modify High Traffic areas as the dwarves are travelling would provide the same benefit while keeping the same A* algorithm in place.

So how about that? Have I missed Toady's prior comments on this very topic?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sheepherder on February 18, 2011, 03:27:43 pm
I just tried this out with a community fort from the forums. I turned off all labors except stonecrafting and built enough workshops for everyone, then paused and put repeat rock craft jobs in each one. Then I duped the save and started up two copies of the game and assigned each to its own core. I used Dwarf Therapist to disable all labors in one game, then unpaused both.

The L2 and L3 cache are shared resources.  If it's being fully utilized the operating system will prioritize.  Also, which core was Dwarf Therapist running on?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 18, 2011, 03:56:32 pm
I only assigned affinities to the two game processes, so I guess Therapist was just running wherever, although it wasn't doing anything once I wrote the changes so I doubt it would matter.

Not sure I understand the cache point; both processes' cores were pegged.

In any case, if you can run a better experiment then please do, but for the moment I don't think there's evidence that the "look for materials to use in a job" routine represents any kind of persistent drain on performance relative to everything else.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: ZioAnthros on February 18, 2011, 04:06:09 pm
Although i am unable to offer technical assistance at this time, i would like to suggest something i would really like to see in the end game.
Creatures should be aware of locked doors and drawbridges in such a way that when no path exists, they linger around the door/bridge/obstacle and wait for it to open, maybe only occasionally looking for an alternative.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Uristocrat on February 18, 2011, 04:34:13 pm

Not sure I understand the cache point; both processes' cores were pegged.


I think he's saying that both CPU cores share the same L2 and L3 cache memory.  That is, that each core does not have its own, so running something else on one core can make it unavailable even when DF is being run on the other core.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on February 18, 2011, 05:07:10 pm
Ah, interesting to know.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on February 21, 2011, 08:15:31 pm
IMHO, the best way to 'fix' pathfinding is to reduce the calls for it.  Right now, dwarves spend a miniscule amount of their time doing anything.  Make every task (eating, sleeping, cooking, smithing, crafting, etc) take more time and you'll see a game speed increase.  200 dwarves (+200 dom. animals) hurt when they are all pathing at once, but not so much when only 1/3 or less are trying to get someplace at a given time.

Obviously some rejiggering would be necessary for balance, but not too much
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Thizda on February 21, 2011, 08:39:12 pm
How about static node generation with Worldgen? Then generate the dynamic nodes, like creatures or levers, nearby.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: PartyBear on February 22, 2011, 07:33:10 pm
What about player-created paths?  Not traffic designations, but set point A to point B paths that creatures can incorporate into their calculated paths.  Only the player actually understands his or her fort's layout well enough to optimize pathfinding within it.  Or optimize it for aesthetics so they'll actually use the nice paved roads, or if the player wants the manic little beard transports to be sure to wander past all the nice calming statuary.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 22, 2011, 07:53:56 pm
What about player-created paths?  Not traffic designations, but set point A to point B paths that creatures can incorporate into their calculated paths.  Only the player actually understands his or her fort's layout well enough to optimize pathfinding within it.  Or optimize it for aesthetics so they'll actually use the nice paved roads, or if the player wants the manic little beard transports to be sure to wander past all the nice calming statuary.

I thought that was the point of traffic designations?  How would you go about doing that without traffic designations?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on February 22, 2011, 07:57:19 pm
You still have to figure out which "waypoint" is nearest to both the dwarf and the destination, which is an NP-hard problem.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: PartyBear on February 22, 2011, 08:54:32 pm
I thought that was the point of traffic designations?  How would you go about doing that without traffic designations?

It's the difference between driving a car and riding a train, basically.  You can only get on or off the train at stations, but you don't have to think much about the part of your route that goes on the train.

You still have to figure out which "waypoint" is nearest to both the dwarf and the destination, which is an NP-hard problem.

My thinking is that you don't search for an existing defined path intentionally, but use them when you stumble across them during regular pathfinding.  Going by the wiki's Path article, a path is calculated by checking every tile around a creature for both the cost to reach it and how far it is from the destination, then picking the best of those and doing the same for the tiles surrounding them.  If this just happens to lead to a well placed player-created path endpoint, probably with the aid of traffic designations, then the (sole, if it wasn't clear) other endpoint of that player-created path is considered as well.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Crashmaster on February 23, 2011, 04:10:48 am
Would it be possible for dwarves to path make as well as path find? Similar to ants; when a dwarf takes a path to a stockpile or building he leaves an invisible (directional) trail terminating at that building and managed by the building. For the next path finding event to that building the AI would search for the building or for any trail to it. If it finds part of a trail first it would not need to expand it's path finding search any farther and could just follow the same path it decided on last time re-calculating only for obstacles. The route this dwarf took would then be tagged onto the end of the previously determined trail.

A maximum diameter from the building for the trails and having it take a number of trips on any route to lay a working trail would be required to prevent working dwarves from painting 1-tile wide route maps to each building from all locations on the map.

This would cause some potential for inefficiency in travel distances in open spaces due to not always going straight for the target.

'q'ing a building or stockpile would let you see all paths related to the building and delete or drag routes or manually make them.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on February 23, 2011, 07:15:25 am
I like optimizing for rooms.  Every area surrounded by doors is a room, node map concentrates on room connectivity, pathfinding is just to the next room.  (each room contains traverse costs). 
Recalc your zones when digging, but only the affected ones.  Same with new doors
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 23, 2011, 08:59:16 am
I like optimizing for rooms.  Every area surrounded by doors is a room, node map concentrates on room connectivity, pathfinding is just to the next room.  (each room contains traverse costs). 
Recalc your zones when digging, but only the affected ones.  Same with new doors

Doesn't this have the same problem as using stairs?

Wouldn't that depend a lot on how many doors you have in your fortress?

I know that early on, my industrial areas are basically just a wide open soil layer that I'll later repurpose into a major stockpile when I actually get my industrial sectors dug out.  I don't use doors then, since I have more important things to work on.

Later on, I tend to throw doors over everything.  Often, doors two layers thick, just in case one gets blocked open.

Plus I know I'm not the only one who does odd playstyles, so there could be all sorts of odd ways people use or don't use doors.

What if people don't use doors, they use lots and lots of stairs to designate rooms?

Using something like stairs and doors to judge player intent requires that you assume what a player's intent for those objects were whenever you see them use doors and stairs.  That's an assumption that's going to fail at some point.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on February 23, 2011, 11:32:16 am
Huh?

There's no player intent involved.  Doors just leverage enclosed spaces with entryways no more than 2 spaces wide.  It's a way to define areas that are minimally connected.

Even if all you do is cut out pathfinding through the bedrooms, you'll see an improvement.

Find some way to not look outside or in caverns unless you know you need to go there and it's a sevond boost. 

Note that this doesn't assume anything.  No doors just means that you've got one big room the same as now with a little bit of extra overhead when you dig.(i.e. check the 'room' code of the 26 surrounding squares) or build a new door.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 23, 2011, 12:10:44 pm
What about something like this?

= is a wall
+ is a door

+=++=++=++=++=++=+

Along one side of a wall.

Or using the door bug to make a string of doors that make up an entire wall.

In order to say "don't check the bedrooms", you have to figure out which ones are the bedrooms, and which ones are the hallways... and doors don't necessarily help you figure that part out.

By saying that players should adapt their door-placing decisions to manipulate pathfinding, you're suddenly talking about doing something fairly unusual in placing furniture to designate an inent in pathfinding, wheras we already have a "traffic zone" menu that is explicitly for pathfinding control.  Wouldn't a reworking of traffic zones to have "This is a hallway" be a better way to show intent?  (And isn't that what the high-traffic designation is already supposed to do, if it is not strictly as efficient at it?)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on February 23, 2011, 12:20:40 pm
I think you are making this more complicated than intended.  The doors aren't magical or anything.

  Just take the first square in the upper left of the surface.  Path to everywhere you can without going through a door.  Add any doors to the list of connections for that zone.  That is zone A.  Now for each door, check the first open space on the other side.  If that doesn't have a zone, path to all available spaces, adding doors as connections.  That is zone B.

Thats how you generate your zones.  After it is complete, you only need to change when digging or building doors, or constructing path-blocking items.

The reason bedrooms get cut off is that they only have one connection.

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 23, 2011, 12:52:11 pm
Well, like I said, you have to plan for how it handles the most complicated, worst-case scenario.  That means that you have to make it as complicated as possible, and see how it handles.

If all we are doing is looking for narrow chokepoints, then you don't need a door at all.  (And what if you have a large bunkroom bedroom with hallways going through it?)

You just need a way to recognize narrow chokepoints, and then create "nodes" out of the abstract areas between each chokepoint, and to possibly also recognize during the connectivity map updates that one specific node has not been altered.  In other words, it's the node-based pathfinding maps suggestion.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on February 23, 2011, 03:01:31 pm
 You are making the algorithm out to be more complicated, not throwing too complicated of a case at the algorithm.

Sure, if you build two long S paths with a shortcut going back and forth, you can game the system to make it choose a longer path.  But that takes effort to do anything non-trivial

The reason bedrooms are a good example is because dwarves complain if they don't have enclosed rooms.  They also complain when people march through their bedrooms.  That means, in a well designed fort, there are guaranteed  opportunities for this to pay off.

The reason doors are good is that they don't occur in nature, it's free to check(you know where one is and you know when you add one) and it's subject to player optimization.  Checking for choke points in a cavern is expensive.

It's guaranteed to give you AN answer, and will most often give you the best answer.

If you think multiple doors leading to non optimal solutions are a danger, just collapse any two rooms with multiple connect points into a single zone.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on February 23, 2011, 03:35:02 pm
So you are seriously saying only bedrooms in these calculations? What about the mass bunking systems?  To simply say that anyone who is using that system is playing the game wrong seems a little on the odd side.  What about workshops that are only used by one specific worker (and the haulers), and are in their own specific room.

Would collapsing rooms with multiple connection points into a single area really less costly than checking for chokepoints? 

What about the large numbers of creatures roaming the caverns?  Those have plenty of chokepoints that can be optimized.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on February 23, 2011, 04:04:13 pm
A zone/room is any contiguous area containing all points that can be pathed to without using a door.  Bedrooms are a useful example, because in order to make dwarves happiest, they should be enclosed and nothing should be pathing through them.  That is, they are a leaf on the connectivity tree(as designed, and without the system knowing thqt its a bedroom or storeroom or whatever.)  I'm using the existance of these leaves to make the claim 'this method will pay for itself.'  Specifically, the node maintainance costs are recouped by the A* never pathing through leaves (bedrooms, or any other dead end)

My justification for possibly collapsing:  imagine a large (50x50) open area with a walled of area 30x30 in the middle, with doors in all faces.  In this instance, a dwarf passing from one side to the other may path around the outside rather than take the shortest path through the center.  A path is still found, but it might be crappy.  (there are a number of these flaws, all solvable, but not necessarily better than straight A*.  i.e. when you hit a door on the inner path, go back to the nodes map)

The reason I like doors is that it's a non-greedy solution that's easy to impliment.  Finding zones through chokepoints would prolly be better, but there's a LOT of special cases to think about, and I'm no longer willing to claim the overhead is worth it. (by non-greedy, I mean that when it doubt, just use A* and huge zones.)

A* is really good at straight paths, it's the dead ends that kill it.  Teach it to ignore deadends and you get a boost.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 04, 2011, 04:19:45 pm
So, this article on memristors and maze solving (http://www.technologyreview.com/blog/arxiv/26467/?nlid=4196) came across my feeds a few days ago. The paper it reports on is a surprisingly easy read (and the pictures at the end are enlightening), so consider reading it.

Basically, some guys built an array of memristors (http://en.wikipedia.org/wiki/Memristor), overlaid a maze (the walls broke connections between the adjacent memristors), chose start and end points and ran a current through them.

Memristors hold a memory of the current that flows over them. Current in one direction increases the resistance, current in the other direction reduces it. If you start from a clear array (minimum resistance) then the path will be marked by a series of memristors with high resistance compared to no change for the memristors not on the path.

In scenarios in which a maze has multiple solutions, the array finds all viable paths with the shortest marked with the highest resistance, the longest with the lowest resistance (but not 0, which is no path), and other paths in between depending on length.

This process can be modeled in software, and as each memristor performs a single, identical operation, this can be easily parallelized.

You can probably imagine how this might be useful in DF:


The maze constructed in the paper is a straight grid, but DF connects tiles that share a corner, so rather than the four memristors per node in the paper, in DF this would need to be eight.

From there, when a units wants a path, it uses its current position as the start point, and the desired location as end, and the memristor algorithm does it's thing and now you have every path to the destination, sortable by length. To fully take advantage of this, such an algorithm should be multi-threaded (not just it's own thread, but possibly multi-threaded itself), but this is a long-desired enhancement to DF in general.

The current system's traffic designation system can still be implemented: once you have a list of paths (which are themselves lists of tiles), the traffic designations on those tiles can be taken into account (so, sort by length, then by cost; or cost, then length, whichever produces better results).

As far as I can tell, it shouldn't be a problem to make this 3D: stairs and ramps would simply connect to the appropriate node in an adjacent level. This method should be highly expandable in terms of features: 4D connections should work the same way as stairs and ramps, so those "magic world" suggestions, gateways into them could be enabled by simply making another connection between a node in the 'real' world and the 'magic' world, and shortcuts in a single world would merely be an additional connection between the two end points of the shortcut, which may or may not have it's own memristor nodes in it (depending on how long it is to be).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on March 06, 2011, 02:59:55 am
You're missing a couple of crucial things.
It's not the memristor function that solves the maze. Even with ordinary resistors, the current would find the best path(s). All the memristors do is store that path so that it's easily readable.
And there's the rub. While the work the memristors do is indeed simple (it's a sort of integral or sum), that's neither here nor there. What's needed is to solve for the current through the maze. Nature, being massively parallel - here basically every valence electron is doing computation for you - does it easily. Doing it in software would be hellish, as you'll appreciate if you've ever tried to figure the current through a complex parallel-and-serial network of electronic components.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on March 06, 2011, 03:07:15 am
...that said, this does have potential in hardware. Perhaps specialized maze-solving hardware will be available; fast 4-to-4, 8-to-8, 10-to-10 or 26-to-26 grids with configurable connection costs rated at "solutions per second"... that would probably end our pathfinding troubles once and for all!
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 06, 2011, 10:32:30 am
You're missing a couple of crucial things.
It's not the memristor function that solves the maze. Even with ordinary resistors, the current would find the best path(s). All the memristors do is store that path so that it's easily readable.
And there's the rub. While the work the memristors do is indeed simple (it's a sort of integral or sum), that's neither here nor there. What's needed is to solve for the current through the maze. Nature, being massively parallel - here basically every valence electron is doing computation for you - does it easily. Doing it in software would be hellish, as you'll appreciate if you've ever tried to figure the current through a complex parallel-and-serial network of electronic components.

(http://imgs.xkcd.com/comics/nerd_sniping.png)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: mszegedy on March 06, 2011, 04:20:11 pm
I hate you. xkcd is drawn by a lazy asshole. It is not a good comic.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 06, 2011, 04:22:08 pm
...that said, this does have potential in hardware. Perhaps specialized maze-solving hardware will be available; fast 4-to-4, 8-to-8, 10-to-10 or 26-to-26 grids with configurable connection costs rated at "solutions per second"... that would probably end our pathfinding troubles once and for all!

I should note that the paper didn't construct a physical network of memristors and instead constructed a simulation (not to mention asserting that such an "algorithm is superior to any existing maze solving methods", I don't know how this measures against pathfinding, though), but the idea of a a physical chip to do this it attractive. Why the small numbers though? I can't find sizes for current memristors, but they're not going to hit consumer market in such a chip if they are macro scale, so by the time one is made we should be able to fit some hundreds, if not thousands, on a chip, even accounting for infrastructure effecting walls and result reading.

I hate you. xkcd is drawn by a lazy asshole. It is not a good comic.

You're in luck! There's a website for you and people that think like you: http://xkcdsucks.blogspot.com/

(Actually, I drop by there too; it's nifty to get another take on things like this.)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Felblood on March 06, 2011, 08:00:31 pm
Carping about highly idiosyncratic play-styles aside, room based nodes have a lot of advantages and very few drawbacks (such as requiring us to all own coprocessors that haven't been invented yet).

They provide easy hooks for workshop-to-room relationships that players can leverage intuitively. Currently, a workshop works best with a built in stockpile, and stairs to matching stockpiles above an below, but checking for items within the path node first would make for the same efficiency without the bizarre architecture. (If you don't currently build optimal workshops, that would make it easier to learn, if you ever wanted to.)

Treating hatches and floodgates as doors for purposes of recalculation would provide for three dimensional separations and a level of water system awareness.

I'm already placing locked doors over unused mine  shafts, to prevent them from bogging down pathing, this would allow me to leave those doors unlocked. (I don't remember my numbers, but I did test that this had an effect on complex exploratory tunnels near population centers.)

Even if the system only recognized player designated areas, like burrows, zones and rooms, the potential gains would be respectable. Even just cataloging "dead end" rooms, with only one exit, would be a considerable boon.

Crafty players already place doors over bedrooms (regardless of how many occupants they have) and workshops, so that moody dwarves, thieves, wild animals or riots can be contained by locking a couple of doors. Low framerates would serve as a reminder to do so.


That said, like so much else, it isn't perfect.

The largest drawback that I see is actually the four way intersection. Some forts place a door at the corner where four walls meet, connecting four nodes with a singe door. To compensate, the code simply needs to allow for this, for example, treating the door themselves as nodes.
Code: [Select]
...O...
...O...
...O...
OOO+OOO
...O...
...O...
...O...

Additionally, treating stairs as nodes has some merit, but many forts use large blocks of stairs, which would lead to tracking an awful lot of stairs and possible memory problems.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 07, 2011, 10:01:25 am
I should note that the paper didn't construct a physical network of memristors and instead constructed a simulation (not to mention asserting that such an "algorithm is superior to any existing maze solving methods", I don't know how this measures against pathfinding, though), but the idea of a a physical chip to do this it attractive. Why the small numbers though? I can't find sizes for current memristors, but they're not going to hit consumer market in such a chip if they are macro scale, so by the time one is made we should be able to fit some hundreds, if not thousands, on a chip, even accounting for infrastructure effecting walls and result reading.

The problem with this is that a simulation of memresistors doesn't actually run the same way that a real array of memresistors runs.  A simulation of memresistors has to have your CPU individually model the actions of every single memresistor, which would be worse than simply flood-fill pathfinding. 

If you could take all the advantages of a memresistor without having to actually build a memresistor with no additional cost, then who would want to build a memresistor in the first place?

Crafty players already place doors over bedrooms (regardless of how many occupants they have) and workshops, so that moody dwarves, thieves, wild animals or riots can be contained by locking a couple of doors. Low framerates would serve as a reminder to do so.

I think this is what I have the biggest problem with...

Your choice of where you build doors should not be based upon how you want to exploit the pathfinding program into doing what you want.  You should build doors, "physical constructs" in the DF world, to control physical flows, not to handle meta-game exploits of the way dwarves "think".

We already have a nod towards player control of pathfinding, and that's in traffic designations.  Traffic designations are free, because you don't have to build anything to tell dwarves "this is a bedroom, don't path through it", you just need to make sure people understand it's a bedroom, something architecture the game currently isn't capable of recognizing would probably be best capable of conveying. 

I think node-based pathfinding is a great way to make pathfinding as a whole work better, but either make the computer figure out where the nodes are by itself, or by giving the player an ability to designate, in some hybrid of burrow and traffic-zone-style, the nodes themselves. 

Constructs that are physically built for physical purposes should not have meta-game exploit purposes. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: zilpin on March 07, 2011, 11:47:50 am
...
I think node-based pathfinding is a great way to make pathfinding as a whole work better, but either make the computer figure out where the nodes are by itself, or by giving the player an ability to designate, in some hybrid of burrow and traffic-zone-style, the nodes themselves. 
Constructs that are physically built for physical purposes should not have meta-game exploit purposes.

I agree with your point, overall.
I would further propose that, instead of making the user designate "nodes", the algorithm simply use defined Rooms as the node, and remember paths between them.  After all, you already had to make that bed a Bedroom, that chair an Office, that table a Dining Room.
Hallways are already designated with high-traffic, though I wish there were a few more options for traffic (High, Medium, Normal, Low, Restricted, Forbidden).
Designating one-way tiles would also help, but that's just dreaming.  Right now I create one-way paths using hacked ramps.

Still, I would prefer Toady spent his time on bug fixes than re-writing or adding anything.


Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on March 07, 2011, 12:53:20 pm
I disagree NW... 

1: Using stairs and doors to optimize pathfinding isn't meta, the pathfinder is simply recognizing them for what they are.  Barriers to separate contiguous areas.  Their effect is the same in game as it is for the player.

2: Optimization of processor time doesn't yield indeterminate solutions.  You are findind the answer faster, not finding a better answer.  Since df is turn based, there is no problem with that.

3:  Players already do ridiculous things to speed up pathfinding, from restricting dwarves to their rooms to laying out traffic zones to killing and skinning hundreds of cats a year.  Putting doors up to separate areas hardly seems worse.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 07, 2011, 01:03:37 pm
I disagree NW... 

1: Using stairs and doors to optimize pathfinding isn't meta, the pathfinder is simply recognizing them for what they are.  Barriers to separate contiguous areas.  Their effect is the same in game as it is for the player.

Wait, what?  Since when are stairs used as barriers to separate areas?  Stairs are used as connections between areas, and I, personally, use more vertical hallway space than horizontal.  Why should a vertical shaft NOT be seen as a hallway that connects to multiple different branching paths?

2: Optimization of processor time doesn't yield indeterminate solutions.  You are findind the answer faster, not finding a better answer.  Since df is turn based, there is no problem with that.

I have no idea how this relates to anything I said...

3:  Players already do ridiculous things to speed up pathfinding, from restricting dwarves to their rooms to laying out traffic zones to killing and skinning hundreds of cats a year.  Putting doors up to separate areas hardly seems worse.

And we shouldn't have to.  Toady doesn't give us any direction on how to do these things, they are all guesses (and usually wrong guesses), and all means of meta-exploit we shouldn't have to do, if the game was better optimized. 

I really don't think what this game needs is a piece of code that optimizes cat-skinning, what this game needs is code that minimizes cats' impact on the game's framerate.  (And Toady, in talking about farming, has said things along the lines of how pests in farms would help stop people from killing all the cats in their fortresses - as in he wants to find a way to stop the cat butchering, the way he found a way to stop the mermaid butchering.)

If the game can parcel out nodes and pathfind from those nodes, then it's a great thing, and we should find ways to do that, but the idea that we should force players to only build their forts in one specific way, or the game will punish them for their deviant stair placement or door arrangement is a completely backwards way of designing a game.

If this is really supposed to be a fantasy sandbox, the game should adapt to the player, you should not force the player to play with only the toys you want them to play with in the way you want to force them to play with them.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on March 07, 2011, 01:26:27 pm
1:  barriers to separate = borders to different, not obstacles to keep apart.  My bad, should've been clearer.

2:  just covering the big potential objections, and code that gives an in-game advantage to players who optimize is a big one.

3  People do crazy stuff already to optimize their forts.  You can't stop that.  What you can do is make the optimizations make sense in game as well as out.  The fact that people with badly laid out forts don't benefit isn't a punishment, any more than fps caps over 10 aren't a punishment for people with slow computers. 

Besides,  I don't think 'use doors to separate areas' is really that onerous of a restriction.  I wasn't suggesting making cat death easier, just pointing out what people already do in order to get fps.

Save a kitten, support pathfinding improvements.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Shades on March 07, 2011, 01:43:08 pm
Besides,  I don't think 'use doors to separate areas' is really that onerous of a restriction.

The point is that for a lot of forts it might not help at all, certainly none of the forts I make, which means you've added a lot of code for no good reason. This leads onto the point I think NW_Kohaku was getting at that your adding more ways players can try to optimise their fort rather than solving the problem. I don't think he wanted to stop players choosing to optimise, that after all is up to them, but just to avoid adding more code that only helps those that do and encourages you to.

Stairs would make more sense for my forts, probably, but doesn't sound like it would for NW's as he builds more vertical forts. Either way it doesn't sound like it's a general solution.

Of course I'm still not convinced path finding is the main cause of the frame rate loss, and if it is a single threaded A* search on such a small map should not be taking so long which implies it can be replaced without effecting too much.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on March 07, 2011, 02:48:47 pm
So you don't have a front door to your fortress and have the whole fort on one level?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Shades on March 07, 2011, 03:15:31 pm
So you don't have a front door to your fortress and have the whole fort on one level?

I don't havea front door, my only doors are bed rooms and my fort is in detacted sections each section is mostly one level.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 07, 2011, 04:26:11 pm
3:  Players already do ridiculous things to speed up pathfinding, from restricting dwarves to their rooms to laying out traffic zones to killing and skinning hundreds of cats a year.  Putting doors up to separate areas hardly seems worse.

To put this bluntly: A fort that doesn't build doors or butcher stray cats at all should have just as many FPS as a fort that does.

This isn't game play or meta, but proper game design. The only reason butchering cats and building doors everywhere is necessary right now is because it's a workaround for a bug that cripples game play.

Traffic zones are explicitly designed to alter pathfinding, so a fort that uses them properly should run more smoothly than a fort that doesn't, which in turn should run smoother than one that does, but incorrectly (like making all your major hallways restricted, and all your bedrooms high traffic).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on March 07, 2011, 05:57:52 pm
3:  Players already do ridiculous things to speed up pathfinding, from restricting dwarves to their rooms to laying out traffic zones to killing and skinning hundreds of cats a year.  Putting doors up to separate areas hardly seems worse.

To put this bluntly: A fort that doesn't build doors or butcher stray cats at all should have just as many FPS as a fort that does.

This isn't game play or meta, but proper game design. The only reason butchering cats and building doors everywhere is necessary right now is because it's a workaround for a bug that cripples game play.

This.

Now, there is nothing wrong with using the structure of the forts people build in order to help pathfinding efficiency. We have to - or otherwise live with a system that is completely unbiased and thus completely unintelligent. But the biases, the heuristics we put in can be more or less well-designed and more or less general with regard to the range of forts they work well in. If our heuristc is "use doors" then it's going to work poorly for a fort that has no doors, or that places them differently from how we assumed. If our heuristic is "find choke points" the it's going to work poorly for a fort with lots and lots of uniformly wide tunnels. If we elect to let the player set nodes himself the solution will be as intelligent - or as dumb - as the player can be bothered to be. Any combination that tries to make the best of many different methods will work well for a wider range, probably at the cost of a bigger overhead and (thus) worse performance in cases that aren't covered.

This is not to criticize or propound any specific option. I just want to point at the trade-off we must deal with. We will never find a solution that deals optimally with all possible forts. A player who digs a Labyrinth of Knossos on every z-level can't expect good FPS and we can't design for his benefit. Can we design for players who don't want doors? Probably; should we? Whose Dwarf Fortress are we going to bias for?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 07, 2011, 09:23:38 pm
Why is it that vertical hallways should be treated differently from horizontal hallways?  Especially when people have differing ideas on what constitutes a room?  I like multi-floor "rooms", even if the game doesn't recognize them as such. (And I don't use stonesense, either, I just keep a very good image of my fort in my mind.) There is nothing logical about having a bias for mostly-flat fortresses which only have one central hallway.

You're talking about how "players already optimize" in just one particular way, but I certainly don't play that way, and it seems to me that what you are basing this on is, "I play this way, so everyone else should, too."  How do you know how many people play that way, and how do you know that people will want to play that way?

Do something for me - rebind your up and down z-level keys to 5 and 0, and play like that for a while.  I have a theory that all this obsessively horizontal building is an artifact of people simply not wanting to use > and < to go up and down since it takes a repositioning of the hands to do so.

If they are only playing that way specifically because they want to optimize, then we can optimize for whatever crazy-ass methods we want, and those people are going to do whatever is optimal, anyway, so why should we keep things exactly the same just because this is what people are doing because they feel they have to do it, regardless of how much they like it right now?

Again, I'm not saying that we shouldn't be using nodes, but that we shouldn't be doing strange things like assuming we could never have anything but a single central stairwell fortress design, and punishing any player who designs another type of fort.

Rooms/nodes, however, should be defined in ways that don't have to do with doors.  This IS possible, and it is possible by using (hopefully, eventually multi-level) either zoning abilties in the game, or the game being able to naturally infer from narrow chokepoints where the nodes connect.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on March 07, 2011, 10:04:46 pm
Horizontal is different because A: It's all on one screen, and B: digging out a square allows you to move horizontally and still put stuff there, which is something you can't do with stairs.  Think about B for a minute.  If you want to go up or down stairs, that's all you can do with a space.  I'd like to see what you are thinking of as a two story room.  It's either a room with a high ceiling, or two rooms with stairs between them.  In the first case, pathfinding to the second z level is unnecessary (unless you think we shouldn't optimize for people who stay on the ground?).  In the second case, the stairs make a natural dividing point between rooms.  Even if you are building something like the old human taverns, where it's a big two story building with a hole in the middle, it's good for the pathfinding algorithm to know if it needs to use the stairs or not.  It may be 'all one room' to the human eye, but that doesn't mean you won't see speed improvements by the pathfinding algorithm thinking of it as two.  Note: pathfinding algorithm.  Just because the computer is thinking of it one way behind the scenes, doesn't mean anything.  Unless you are building a room where every square that doesn't have furniture has stairs; If you are arguing that that case is just as valid a target for optimization as any other, we'll have to agree to disagree.

I'm basing players' optimization on actually listening to what other people talk about doing.  I've got a fast enough computer that I don't need to kill cats to play the game at speed.  So, I'm making no assumptions about what other people do.  Cruise on over to the Dwarf Mode forums, see what people say... Kill cats, build doors to lock your moody dwarfs in, build bridges to block off the outside (something else I don't do), kill excess dwarves. 

The algorithm isn't 'optimized for a single shaft design'.  It's optimized for large cut out areas being connected by narrow passageways.  I'm willing to bet that the majority of forts exhibit that kind of behavior.  I also think optimization should focus on the majority of forts, because nobody is coming up with anything too bright for the general case.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 07, 2011, 11:33:01 pm
What about vertical hallways?  How is that not a vertical room?  Why should they be treated differently from horizontal hallways?

Also, why can't I have multi-story rooms at some future point?  Why not have a sloped room, with ramps in it?  Why not have a mezzanine with eight separate stairwells in eight corners of an octagonal balcony in a dining hall?

It makes no sense not to consider rooms with ramps, or long spiral inclines as somehow a set of unconnected tiles while anything flat is a hallway unless it has doors.  That's not the way most people build forts.  And the way that you keep mentioning, as if everyone uses drawbridges to close off sections of the forts, isn't the most popular method of building a fort - it's something people advertise because they feel it isn't done enough.

Besides which, there's no reason to build the game around the exploits people have built around the game's current status.  If you change the game's pathfinding algorithms, once again, they will change to adapt to the new situation.

You keep thinking that all single-tile chokepoints are covered in doors or stairs, but that's not the case.  You just need to make the game search for the actual chokepoints, instead of harping on this misconception that all stairs and doors are single tiles.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on March 08, 2011, 09:14:55 am
Why are you so upset at the thought of the processor thinking of a room as something different from what you think of a room?

That's all I'm seeing.  No argument that it would behave worse for you, just that what I'm calling a room doesn't match your definition, as if what you (or I, or any other meatbag) thinks of as a room matters in the slightest for pathfinding.

Who cares if the pathfinder cuts your Escherian construction into 3-4 rooms in the.background?

I've explained why (I think) arbitrary nodes are a bad idea.

It's also naive or disingenuous to claim that blocks of stairs, lines of ramps, etc couldn't be handled as a single entity, seeing as we've already covered that case.

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 08, 2011, 09:42:38 am
Why are you so upset at the thought of the processor thinking of a room as something different from what you think of a room?

That's all I'm seeing.  No argument that it would behave worse for you, just that what I'm calling a room doesn't match your definition, as if what you (or I, or any other meatbag) thinks of as a room matters in the slightest for pathfinding.

Who cares if the pathfinder cuts your Escherian construction into 3-4 rooms in the.background?

I've explained why (I think) arbitrary nodes are a bad idea.

It's also naive or disingenuous to claim that blocks of stairs, lines of ramps, etc couldn't be handled as a single entity, seeing as we've already covered that case.

The increasingly personal nature of your statements aside, you actually haven't covered any of those things as a single entity, and have been specifically arguing against handling ramps and blocks of stairs as a single entity. 

You have been arguing that we should be hitting players who do not use stairs sparingly and doors as means of designating traffic flow with lower FPS on purpose, as a means of forcing players to make certain types of fort layouts, simply because you are convinced your particular way of designing forts is popular because you once saw someone agree with you.

I also don't see any reason why arbitrary node definition, or at least, a different style of manual definition or interpretation are infeasable.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on March 08, 2011, 10:31:59 am
It appears I owe you an apology.  I was convinced that we'd had a long debate about using doors double thick to keep water out and long cooridors full of doors versus a path around with no doors, but I can't find it.

I never called out grouping contiguous area dividers as a single one, so my harrassing you about it was totally off base.

In my own defense, you did falsely accuse me of assuming everyone played like me.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 09, 2011, 03:55:50 am
I'll throw my ideas about the subject and I don't think someone mentioned them but they aren't that revolutionary.

I think the easiest improvement on pathing is to put a constraint on how long each mob can hog cpu per frame on pathing. This is rather simple to implement but may cause the dwarf/mob to stand there for a while.  The dwarf or mob can also take a guess that the path they are on is good and start traveling . Because A* start at the source and not destination the dwarf can keep a back-path if he didn't travel too long . You may see the dwarf running  running around his start position until he gets on the correct path.

Adding the feature "stop and think" or "thinking on your feet " may save people with weaker CPU a lot of trouble .

I also had a similar idea to the "areas" that were mentioned here so dwarfs would go from Area to Area rather than from point to point.

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: JanusTwoface on March 09, 2011, 09:11:10 am
It might help, but there is a definite cost to storing where you were in the path finding and the reloading that every frame (or however often). It might work, but I think the ideas which automatically make larger areas with stored paths will probably be more benificial.

A thought on those lines: could pathing be done in a manner similar to how network traffic is routed?
- Each boundary between zones (however those are decided) keeps a routing table for how to get to each general area of the fort.
- Each path finding dwarf gets to one of these checkpoints and tells it their destination.
- The routing table gives them the next part of their journey.
- They use A* (on a much shorter path) to get to the next routing station.

Thoughts?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Jeoshua on March 09, 2011, 10:07:09 am
That sounds like a  hybrid of brute-force pathfinding and nodal pathfinding.

I like it.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on March 09, 2011, 10:21:46 am
That's pretty much what we've been talking about.  The hard part is coming up with how to do the nodes in a way that will support outdoors, inside a fortress, in a cavern, etc.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 09, 2011, 10:40:50 am
That's pretty much what we've been talking about.  The hard part is coming up with how to do the nodes in a way that will support outdoors, inside a fortress, in a cavern, etc.

You need to deal with mazes,* large open spaces, spaces with 1 entry, 2, and 20.

*A "maze" is defined as 1-2 tile wide corridors that zig-zag a lot, possibly including multiple valid paths to the destination.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: JanusTwoface on March 09, 2011, 10:56:20 am
That's pretty much what we've been talking about.  The hard part is coming up with how to do the nodes in a way that will support outdoors, inside a fortress, in a cavern, etc.
Right. The node idea has been discussed quite a  bit, both here and in the Pathfinder Project. But I think the idea of routing tables is new(ish). I'm actually curious how that'd work in practice. I may throw together a proof of concept. :)

You need to deal with mazes,* large open spaces, spaces with 1 entry, 2, and 20.
Large open spaces seem like they're not really a problem. Set aside a tunable parameter for how large of groups actually will form and divide it into a grid of that size. Up to the (unlikely) possibility of including the entire outside as a node in a region where your fortress is entirely underground with minimal wildlife that needs pathing.

Mazes I'm not so sure about. I think it's a matter of scale again. Smallish mazes would probably be a single node. It'd be quicker to solve them with A* then storing and reading paths. Larger mazes... Hmm...
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 09, 2011, 11:18:46 am


bisection and powers of 2 are your friends:


1. create an data structure with  256X256 block of the map on each z level
2. for each block in the map recursively split recursively into 4s according to number of directions you can travel.
3 . after splitting zones up build a connection map between zones.
4. build a function to quickly decide which spot is in which zone.
5. add update scheme
6. you are set with many small Ns with best-case runtimes.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: JanusTwoface on March 09, 2011, 11:54:57 am
1. create an data structure with  256X256 block of the map on each z level
Why on each z-level? As NW_Kohaku was talking about, it would be nice to treat the z-axis equivalently (or at least weighted) to the x and y for people that build vertically. (And I'm sure he's not the only one).

2. for each block in the map recursively split recursively into 4s according to number of directions you can travel.
So... a quad tree (http://en.wikipedia.org/wiki/Quad_tree). :)

5. add update scheme
This is the hard part. How/when does this run? This has to be more efficient then the current pathfinding we have, otherwise it's not worth changing.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Nikov on March 09, 2011, 12:08:29 pm
I'd like to be able to paint hallways similar to high traffic zones, which dwarves path to, path along ignoring side passages and even perfectly open space, then path off of once they are at the closest point to their destination. Of course I'm not a computer science person and better methods might exist, but that was the idea I had a while back to make haulers go around the dining room. Naturally painting vertically is an option.

And +1 for defining rooms with vertical space. I want my greathall's vaulted and engraved 5z ceiling to count for something.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Granite26 on March 09, 2011, 01:02:59 pm
As far as value and dwarf perception go, multi-z level rooms make sense.  It doeen't make sense to consider high ceilings from a pathfinding perspective.  Hell, you should be able to define your grand dining hall with a ramp to the king's table, a 5 z level ceiling, and a balcony area overlooking the whole thing with stairs in each corner, all as one room from the dwarfs' perspective.  That doesn't mean the pathfinder can't cut it up into 3 rooms from it's perspective.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 09, 2011, 02:52:27 pm

2. for each block in the map recursively split recursively into 4s according to number of directions you can travel.
So... a quad tree (http://en.wikipedia.org/wiki/Quad_tree). :)

Cool ,it has a name - so i guess it's not as hard to implement if someone else thought about it.. I noticed there is a 3d version of it called octtree

5. add update scheme
This is the hard part. How/when does this run? This has to be more efficient then the current pathfinding we have, otherwise it's not worth changing.
it's not really hard if you go through the rules of how you make eache zone like a zone has to have 7  (open area ) or more dirrections or 3 or less  (path ,intersection,dead end). you can either update as dwarves go along it or run zone updates in the background.

The general idea is to reduce the number of nodes  while also segmenting pathing in a way that the size of the map would not affect the game . performance. if for example you got a map size

small example get from O to X current  pathing would  take 9 steps and won't gain much other than dividing the movement into smaller steps
Code: [Select]
#########
###+X+++#
O##+###+#
+##+###+#
++++++++#
#########

Code: [Select]
A . B .
##.###.####
##.#+X.+++#
O#.#+#.##+#
.......   C
+#.#+#.##+#
++.+++.+++#
##.###.####
 D. E .

. separator
O start position
X end position
# wall
+ floor

Weights 
A 1 (can be merged with D)
D 2
E 3
C 6
B 2

path  we are looking for is A to B and best path is A->D ->E ->B and A * will find it pretty fast . the number of steps are 4 while we do have the intermidiate steps inside the small zone which usual have very short runtime. If we merge A and D we would reduce main search making it  length  3 . This will change the execution (from 9 step search then 9 steps) to
frame 1 : search for path from A ->B , returns A-> D ->E->B then search for path to A->D then move 1 step south
frame 2:  when reaching D search for a path to E then move south east
frame 3: move east
frame 4: search for a path from E to B then move step north east
frame 5: move north
frame 6 : search for a path to destination move ne

Due to the fact this  example is very small the gains would be very minor but if instead of 9 steps you need to move 100 steps You will gain a lot.  If this 100 step path would be divide it into 10 step initial search (smallneighbor list ),  then 9 steps  walk then another 10 step search  etc it would be a lot less CPU than doing a 100 step search and then going on the path. This will also save the big penalty on  path recalculation  . The cache penalty on long paths is also pretty bad especially when changing Z levels.

 
I can probably implement some kind of javascript simulator to do this on map data . I like JS cause it runs on every platform and it's easy to access.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 09, 2011, 06:41:05 pm
So, this article on memristors and maze solving (http://www.technologyreview.com/blog/arxiv/26467/?nlid=4196) came across my feeds a few days ago. The paper it reports on is a surprisingly easy read (and the pictures at the end are enlightening), so consider reading it.[...]

Sorry, coming late to this particular thread, and still working through, but... as said immediately afterwards (and I don't think disproved, later on, otherwise I'm going to look silly) this is a real-world parallelisation that doesn't map well to a computational environment.  It can be emulated (in a multi-core situation, even, which might speed it up, minus overheads) but an arbitrarily large array in simulation would need an arbitrary amount of parallelisation to do much the same 'instantaneous' solving as the real-world construct does.

Quantities of various End-Encoded DNA single-strands can be mixed up to make a massively parallel 'calculator', from which all 'valid paths' (sets of suitably attached DNA strands that feature any required intermediate points, and both required end-points) can be extracted and then the best path (the shortest composite strand) can be itself be extracted from these solutions (doubly-so) to 'read' the solution.

And there's another good way of solving various pathfinding problems, with string.  Lay out a 'net' (in several senses of the word) composed of suitable lengths of string knotted together with the others at the correct node.  Grab your start point with one hand.  Grab your end point with the other hand.  Lift and pull tight.  The taught length of en-knotted string-lengths is your best path.  Set back down on the floor (avoiding tangling) and you can repeat the process for any other path.  Or, if you haven't inter-twined disconnected sections, discover if a path is impossible by having two (or more) nets separate out when you lift and pull.

But the process of emulating these in a computational environment isn't trivial.  The quickest solutions might indeed abstract the process back into the non-trivial pathfinding solution (rather than try to model each and every catenary and dangling thread under gravity, or going through a whole Brownian Motion thing for the DNA example).

But I've still got to read more thread, so I shall see how the conversation progresses.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 09, 2011, 07:09:50 pm
This isn't game play or meta, but proper game design. The only reason butchering cats and building doors everywhere is necessary right now is because it's a workaround for a bug that cripples game play.

I'd just like to s/bug/condition/ in this statement.

While it may not be the absolute optimal method (as often argued) it's a consequence of the current condition of the DF universe.  You might as well say that the Creator[1] created a 'bug' that one cannot travel faster than light in our own universe.

Of course, there's something to be said about the analogy that the dwarfs might still be running on chemical reaction rockets instead of some kind of future-tech which would allow us to more easily approach c in interstellar travel.  And perhaps there is an optimisation available within the constraints of the physical universe that would allow us to make FTL/instantaneous travel, much as there might be a trivial (e.g. constant-time, and short at that) function available to pathing Dwarfs so that they don't have to think so long (in player-time) before finding their best path.  But in both cases there needs to be some great new insight about the nature of space/information before such solutions can be considered.

And despite my machine being not particularly the best (worldgen and fort-save times are far longer than I'd like) I can't honestly talk about "crippling".  I tend to run complex forts (without any particular nod towards meta-gaming the known pathing optimisations that are possible) and the number of free stones (not locked away) is often large in my various midi-projects (verging on mega-).  Perhaps my expectations aren't high enough.  Perhaps the general slowness of other aspects (unnoticed by me, as I'm used to it) means that I'm happy with the slowness of path-recalculation.

About the only time I properly notice pathing-lag is the significant pause when traders or immigrants arrive.  (Which also usefully can clue me in on more sneaky invaders, and perhaps might let me meta-game a preparation for such nasties visible arrival, if I let myself.)  But that pause is far less than the seasonal-save pauses, even then.


This is not to say that I'm not interested in finding a more optimal solution (note my contributions in that other thread).  And apologies if all I've put towards this thread, so far, is objections.  I don't want to repeat various bits (of my own, or of others) of the other thread that I consider constructive, because that would indeed just be repetition.



[1] If any, and I've stated my beliefs on that enough times not to want to divert this thread in that direction.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 10, 2011, 03:46:51 am
This isn't game play or meta, but proper game design. The only reason butchering cats and building doors everywhere is necessary right now is because it's a workaround for a bug that cripples game play.

I'd just like to s/bug/condition/ in this statement.

While it may not be the absolute optimal method (as often argued) it's a consequence of the current condition of the DF universe.  You might as well say that the Creator created a 'bug' that one cannot travel faster than light in our own universe.

I don't think that sed is appropriate. This is definitely a bug.

To play a more accurate analogy, it would be as though time itself slowed down when too many people gathered in a city. Unlike the speed of light issue, which we can definitely measure in-universe, such an effect would be as unmeasurable to us as the pathfinding slowdown would be for our simulated dwarves.

Alternatively, I should be able to mod my dwarves to have [SPEED:-1], which would cause them to appear at their destination before they left. In fact, in the time prior to this event, you should see before-images of the dwarf walking backwards towards the dwarf, and upon merging both disappear (the dwarf having arrived at the destination several seconds ago (That's right, tachyon dwarves (But I digress))). I'm not entirely sure what this thinking does to crafting. I'm having flashbacks to the backwards time episode of Red Dwarf, though.

And despite my machine being not particularly the best (worldgen and fort-save times are far longer than I'd like) I can't honestly talk about "crippling".  I tend to run complex forts (without any particular nod towards meta-gaming the known pathing optimisations that are possible) and the number of free stones (not locked away) is often large in my various midi-projects (verging on mega-).  Perhaps my expectations aren't high enough.  Perhaps the general slowness of other aspects (unnoticed by me, as I'm used to it) means that I'm happy with the slowness of path-recalculation.

To be completely honest myself, I tend grow bored of a fort shortly after initial setup; right when I start plotting out the MOST EPIC FORTRESS EVER CONCEIVED™ and remember that building large (complex and therefore interesting) structures is still a PITA, and thus am rarely affected by this myself.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 10, 2011, 11:02:39 am
To play a more accurate analogy, it would be as though time itself slowed down when too many people gathered in a city. Unlike the speed of light issue, which we can definitely measure in-universe, such an effect would be as unmeasurable to us as the pathfinding slowdown would be for our simulated dwarves.
Even before I read the second sentence, I was going "well, maybe it is like that..."

All jokes about life being more leisurely in the country, because they've got plenty of time while the city tries to get things done, if we're being simulated and certain conditions (large groupings of interacting consciousnesses, if that's relevant, but of course I think it'd be more like large groupings of interacting atoms, which make each and every star a computational nightmare on their own) take a lot of Oomph, but the simulation doesn't notice the world.  As you say.

The universe could be being 'simulated' by an exact 1:1 scale model of the universe being 'run' (which is a bit arbitrary when it comes to such an extreme) or via a single 'head' Turin machine.  Or indeed like this (http://xkcd.com/505/), which is essentially the same as the latter (and, ultimately, the former).

But if the universe is being strictly simulated in a linear fashion, things can't happen before their causes.  This is probably not the reason behind the speed limit of 'c' in such a scenario (which may be a feature of the modelling technique being used, only necessarily a 'bug' by your definition).  If the universe is being calculated in a way truly alien to us, perhaps there is some computational reason behind the old frames-of-reference problem (twins' paradox, etc), but it may be as hard to speculate about that as someone living on a Conway's Game Of Life grid would have in trying understanding a circular ripple.  So that way There Be Dragons.

Quote
I should be able to mod my dwarves to have [SPEED:-1], which would cause them to appear at their destination before they left.
Um, no.  DF works linearly, and while there's no technical reason why Toady could not allow instantaneous travel (one blink, at location A; next blink, at location B... or possibly same blink disappearing from A even while appearing at B) finding an agent at location B prior (even by one blink) even to the decision to leave location A is not possible, as is.

(If DF were actually to run a multi-pass look-ahead system of calculating movements, covering a 'blink range' sufficient to encompass a given amount of time travel prescience, then it may delay the 'T-zero' blink output until it has worked out T+1 decisions, found out that Dwarf42 wants to have already been somewhere else at T-zero, re-try T-zero with both pre-move and post-move Dwarf42, ensure that the presence of the latter Dwarf42 doesn't change the mind of the former, and then 'release' the T-zero blink in order to re-calcuate for new T-zero (was T+1) and T+1 (was until now the unknown future and still uncalculated).  Otherwise, if latter Dwarf42 manages to do something (e.g. pull a level, assuming that this effect were immediate on the accessibility of the faster-than-time path being used[1]) that would have prevented the former Dwarf42 from making that trip, there'd be a "Dwarf42 cancels time-jump: Disturbed by Paradox" or similar, and the T-0 release would occur without such a trip.  And you could have a blink range of T0..7 to allow for a series of backwards jumps, but Dwarf42 couldn't actually make more consecutive backwards jumps than the range allows, not without restarting the whole fort from a previous save-point and recalculating, which I'm not sure is what anybody wants.  Imagine in a mature fort, Dwarf42, Legendary in every art, craft, skill and martial art there is, making hundreds, thousands or millions of SPEED:-1 steps back in time to be around at the very start of the fort, potentially changing its whole history.  Imagine a Berserk Dwarf42, of the same military prowess, doing the same, and actively wiping it out as a site.  Killing himself, his parents or, indeed, his grandparents in the process.  Or if not that, at least making a site so different so that there'd be no Dwarf42 the Peasant immigrating shortly thereafter.  I don't call it a bug that this cannot happen (although I think it would be interesting if something of a limited nature of this kind could do so, it would have to split 'alternate branches in time', though, if it doesn't do a whole-history recalculation to wipe out paradoxes, or applies a handwavium fudge of some other kind).  As such, I don't call it a bug that one cannot call function that in (say) seven iterations of a simple loop cannot find the best (or even a reasonably best) path between absolutely any point and absolutely any other point.  The limitation is informatical, which is not to say that a LogN function might not be available where an N.LogN function is currently used (or whatever the order of overhead actually is).  But a bug would be something incorrect, not merely suboptimal.)

TL;DR; - I don't expect to see the Urist McPicard Manoeuvre happening anytime soon.


To be completely honest myself, I tend grow bored of a fort shortly after initial setup; right when I start plotting out the MOST EPIC FORTRESS EVER CONCEIVED™ and remember that building large (complex and therefore interesting) structures is still a PITA, and thus am rarely affected by this myself.

For the last few versions, I've rarely got beyond year 3 or 4, and approaching 100 dwarfs or so (nowhere near the habitually init-revised cap of 300, and 150 kids) before my slow progress (most of the delay is my micromanaging things, although the interminable wait for my the dozen or so Seasonal Saves (my own petard, by which I hoist myself)) gets overtaken by the next version needing trying out (from scratch), or the realisation that I didn't EPIC it enough and wanting to start again...  So I know what you mean.  Although as the pathing algorithm hasn't significantly changed for quite a long time (and I do tend to accumulate an awful lot of spare stones, which is part of the original complaint here, IIRC) so I hope you still don't mind me making my own representations on the subject.



[1] Player interaction in-between T0 and T+1 is another issue.  In the cached T+1 time-slot, Dwarf42 decides he's jumping back to T0 to craft something, but just as T0 becomes 'real', with Dwarf42 now in both places and T+1/+2 now about to be calculated as the new T0/+1, the player unsets Dwarf42's craftsdwarf assignments.  This cannot be applied to pre-jump Dwarf42[2]the only logical situation is that post-jump Dwarf42 finds him or herself having to find something else to do.  Regardless, a tachyonic dwarf could not keep moving backwards in time, and would have to actually bide a wee while awaiting reality to catch them up, at some point.  Which sort of puts the mockers down on a SPEED:-1 dwarf or indeed any negative number in there.

[2] Actually, it can in a one-jump scenario, he could just fade out and "has never jumped back, honest guv".  But imagine a multi-step jump scenario, which is then allowed to continue for part of that multi- before the correction is made that disperses the possibility of the jump having occurred.  You could again Marty McFly him, but it leaves echoes of effect from him having been there and altered others' behaviour.  Not that this isn't usable in some way, but it feels very unsatisfactory to me.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 15, 2011, 08:34:38 am
I started messing around with "node grouping" . In generally I want to write a small program to dynamically generate rooms. I wrote a very simple JS program and put it  here (this free host has trackers but no ads)
http://niseg.0adz.com/test_maze.html

ps: clicking the floors  ('+')toggles them  to walls ('#') and back.

The current thing only count the neighbors and display them which isn't that useful.

My current idea is based on breadth first search. I'm thinking about a combination of "search depth" and number of neighbors in order to find choke points and use them as new starting points for my search. After i find those points I can group the other nodes into rooms. The rooms can be farther reduced by the same algorithm to a region map.

here is my idea
given this maze where + is floor and # is wall X is starting point
Code: [Select]
##################
#++++++++++++++++#
###########+######
#+++#+++#++++++++#
#+++++++#+++#++++#
#+++#+++++++#+++X#
##################

this is the same maze with numbers which signify the "depth" of a breadth first search

Code: [Select]

##################
#++++++987666789+#
###########5######
#+++#+++#76543222#
#++++++9#765#3211#
#+++#++98766#321X#
##################

You'll notice as I you get farther away from the X you get bands of numbers which show the distance between  X and that spot. After inspecting the search steps you can see choke points at 4 and 8 and one at 5 which is harder to find  . Those are generally  are good spots to start a new search and to setup a "room".

What I hope is the next iteration I'll generate this map automatically . Using the search I can probably find dead ends(I think i finished the search part) . I'm don't remember much about graph theory but I'm digging into the subject .

Any suggestions are welcome. Feel free to do whatever you want with the code ; it's rather simplistic and messy . I do need an optimization on search ;) (marking visited nodes with 2,getting rid of silly search and then revert to 0s ).

I've now thought of a way to define rooms - by checking for connections between similar depth rooms like the 6s which are clearly disjoint which makes the 5 point between them a good spot to make a split like the 4 and 8. I also have a the general issue of where to start the search and how to limit the depth.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 15, 2011, 11:53:29 am
You'll notice as I you get farther away from the X you get bands of numbers which show the distance between  X and that spot. After inspecting the search steps you can see choke points at 4 and 8 and one at 5 which is harder to find  . Those are generally 

You forgot to finish your thought, there...

Anyway, the problem with a breadth-first search like this is that every time something like water flows over the area, a door is locked, or someone channels a floor, you'd have to do another breadth-first search.  That's painful.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 16, 2011, 01:39:34 am
You'll notice as I you get farther away from the X you get bands of numbers which show the distance between  X and that spot. After inspecting the search steps you can see choke points at 4 and 8 and one at 5 which is harder to find  . Those are generally 
oops kinda finished it
You forgot to finish your thought, there...
oops kinda finished it. They are good starting point and splitting points.
Anyway, the problem with a breadth-first search like this is that every time something like water flows over the area, a door is locked, or someone channels a floor, you'd have to do another breadth-first search.  That's painful.

The idea is not to replace pathing with BFS it would be silly. BFS was chosen  in order to join nodes into a region. the depth of the search is gonna be limited and it would only require changes when a path is blocked off or things like that then all you'll need to do is check if a path still exist from the region affected to its listed neighboring regions.

You'll still use A* or whatever you want to move from region to region but you won't have to do go through a very long N and you'll be heading toward the general direction of your target but you won't make mistake due to the fact you are using a region map.

finding a way to chop the map into regions is the complicated part.

Another optimization i can think of is improve heuristic function runtime. I once had a trick to find a decent rootfinding guess  ( I totally avoided rootfinding and used the guess ) my guess consists of counting leading zeros and them shifting the number in half. In general I would generally avoid the sqrt in general the multiplication is bad enough.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 16, 2011, 10:25:48 am
The idea is not to replace pathing with BFS it would be silly. BFS was chosen  in order to join nodes into a region. the depth of the search is gonna be limited and it would only require changes when a path is blocked off or things like that then all you'll need to do is check if a path still exist from the region affected to its listed neighboring regions.

No, that's exactly what I meant - you're doing a flood search every time you need to update the connectivity map.

If you are only updating the nodes you are currently partitioning off, that does help, however.  It does mean that you need to be careful about making sure you take into account all ramifications, and you will probably need to mess with the neighbor nodes to make sure all the paths they expect to be open are still open, as well.

Another optimization i can think of is improve heuristic function runtime. I once had a trick to find a decent rootfinding guess  ( I totally avoided rootfinding and used the guess ) my guess consists of counting leading zeros and them shifting the number in half. In general I would generally avoid the sqrt in general the multiplication is bad enough.

They don't use sqrt right now - as far as I can tell, they just functionally use the largest of the three distances, x, y, or z.  Since diagonals are free, 3 spaces directly to the east and 3 spaces east and 3 spaces north are the same distance away, 3 spaces. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on March 16, 2011, 10:35:01 am
They don't use sqrt right now - as far as I can tell, they just functionally use the largest of the three distances, x, y, or z.  Since diagonals are free, 3 spaces directly to the east and 3 spaces east and 3 spaces north are the same distance away, 3 spaces. 

I thought I remembered someone verifying that diagonal movements were weighted correctly and took sqrt(2) times as long as straight moves.

Edit: Diagonal movement is weighted correctly (http://www.bay12forums.com/smf/index.php?topic=30026.msg913704#msg913704) when it takes place, but the A* heuristic is Manhattan distance (sum of distance rather than max).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 16, 2011, 11:58:26 am
They don't use sqrt right now - as far as I can tell, they just functionally use the largest of the three distances, x, y, or z.  Since diagonals are free, 3 spaces directly to the east and 3 spaces east and 3 spaces north are the same distance away, 3 spaces. 

I thought I remembered someone verifying that diagonal movements were weighted correctly and took sqrt(2) times as long as straight moves.

My impression as well, from The Other Improved Pathfind Thread (TM).  Yeah, I could search for it.  No, I haven't been doing.

Not that this is the point, but while Manhattan distances mean a diamond shape of "equal distance", and diagonal=1 enhanced Manhattan means square-shaped "circles", diagonal=2^0.5 still won't give you a circular 'circle'.  It'll be correct (within a unit or so) at orthogonals and diagonals, but at all angles in-between you'd potentially be not getting as far as a 'true' radius for the same steps.  Which leads onto the whole issue of paths from corner-tile-to-corner-tile across a 4x5 tile area are all 4 steps[1] but there's four different routes that can be taken that are exactly equivalent:

Code: [Select]
01... 0.... 0.... 0....
..2.. .12.. .1... .1...
...3. ...3. ..23. ..2..
....4 ....4 ....4 ...34

...and the larger the area, the more routes.  Which is why I quite liked (in the previous thread) the idea of convex zones that can keep a track of a single measure from all access points[2] to all other access points.  These convex zones would be defined as having at least one barrier-immune path available to cross from all relevant edge-points to all other relevant edge-points without being impeded.  (A pillar in the middle of a 3x3 room would fully impede corner-to-corner diagonal travel (two unit steps with a root-2 step in-between), and impede centre-edge to centre-edge cardinal travel (two root-2 steps instead of two unit-steps), but wouldn't have bearing upon any other journey.

A very simple example says that a "corner-junction" 3x3 room with doors at (say) centre-West and centre-South would still allow the same journey (from one doorway, step onto SW corner, then to other doorway) regardless of any piller (central or side-connected) except for having one in the SW corner on only point of contact that this 3x3 would otherwise have to be involved in.  This is an absurdly simple example, of course, but shows us a convexity complication.

W-E travel from centre-west to centre-east doorways bounding the 3x3, having a central pillar, could be accomplished by entering from the doorway square either at a diagonal (NE,SE) or directly (E) then stepping to the side of the pillar (E and E for the "pre-diagonalled" step, NE or SE if they first stepped on the horizontal) for a choice of four different routes, and then a further pair of route-choices (diagonal and horizontal or vice-versa) to get into the opposite doorway.  Whichever of these eight routes is taken, the step-time = 2x(1+root(2)).  It could be treated as a modified convex zone.  Everyone has to go that distance across it, regardless of how they accomplish it.  And what if one had a string of such rooms?  (Including corner-connector type rooms as already discussed.)

This is a fairly common type of dig-out construction for me (at least until I open the area out), closely followed by that of 5x5 rooms.  (Later on, I may open out the doorways to make them more of corridors, which would change the dynamic, of course.)  The rooms may have workshops in them (essentially representing a certain 'pillar' configuration for each workshop type, ignoring those that would actually block certain door exits in the first place).  Each room would be an easy zone to map, and together they'd be a meta-zone where passing into the workshop-corridor at one end one should be able to know that, regardless of the exact pattern of side-steps[2], they've got a fixed distance.  And that they don't need to worry about the middle bit for now, just use that information in their initial route-finding algorithm and if this turns out to be the favoured way (indeed, a possible one!) then when they get to the room, meta-room or, perhaps meta-meta-room, work out which of the many otherwise identical routes they are now going to take.


I'd relate this to the "Pinch-points" thread, except there's a bit of an exception to that rule.

Code: [Select]
A####
 # #
1+ #
2+ +4
3+ +5
 # +6
 # #
####B

Depending on whereabouts in the room from the left you enter, and depending on the whereabouts in the room to your right you are going to depart, it's entirely possible that two different routes (door 2 to door 4, or door 3 to door 5) could be as easy to navigate.  Being forced to make  side-steps in an otherwise horizontal journey might encourage you along one particular of these.  Or a journey from entrance A to entrance B could have you diagonally moving 1..4 or 2..6, for the exact same journey.

So in one, there's a pinch-point (not seen, but dictacted to by the outside) and in the other there are pinch-points two-tiles wide (you can easily find ones even wider, or even discontinuously distributed, say where a pillar-and-gap repetition occurs).  Now.  How to abstract those?  If one could, it could be advantageous, but is the overhead in searching for that kind of feature too expensive?


[1] 5.24-and-a-bit. time-units under the root-2 schema, where a non-gridded distance would be 5.

[2] Important only, perhaps, in some future Additionall Improved Pathfinding technique which can say to itself, while working out the merits of different meta-paths with different on-route characteristics, "That area's busy, but there are plenty of opportunities to side-step and avoid crawling, unlike a single-tile tunnel".  In fact, forced side-steps at the advantage of avoiding differently-sidestepping oncoming traffic might be better than straight-through single-tile tunnels where oncoming traffic slows you down to a (literal) crawl.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 16, 2011, 04:57:59 pm
I did a small change to my program by enabling BFS from top left floor node. it did crash on me during development including an infinate loop hopefully I fixed the bugs . Use it at your own risk (at worst it will crash your browser or halt it). I disabled edge wall toggling so it should be more stable. I bet you can still find a way to kill it. 
http://niseg.0adz.com/test_maze.html

the old one was renamed to
http://niseg.0adz.com/test_maze1.html
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 16, 2011, 08:37:40 pm
They don't use sqrt right now - as far as I can tell, they just functionally use the largest of the three distances, x, y, or z.  Since diagonals are free, 3 spaces directly to the east and 3 spaces east and 3 spaces north are the same distance away, 3 spaces. 

I thought I remembered someone verifying that diagonal movements were weighted correctly and took sqrt(2) times as long as straight moves.

Edit: Diagonal movement is weighted correctly (http://www.bay12forums.com/smf/index.php?topic=30026.msg913704#msg913704) when it takes place, but the A* heuristic is Manhattan distance (sum of distance rather than max).

Unfortuantely, I don't see anything in there talking about any proof that moving diagonally takes 1.4 times as long as moving horizontally, especially since DF movement diagonally does not have any evidence of moving slower than horizontal movement.  I'd have to ask G-Flex if he still believes that, and if he has evidence of that statement.

Distance in DF is calculated in terms of concentric cubes - just look at how constructions list the distances to the potential building materials, or the impact of noise.  Diagonals are considered an equal distance to horizontals. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on March 17, 2011, 08:35:37 am
Unfortuantely, I don't see anything in there talking about any proof that moving diagonally takes 1.4 times as long as moving horizontally, especially since DF movement diagonally does not have any evidence of moving slower than horizontal movement.  I'd have to ask G-Flex if he still believes that, and if he has evidence of that statement.

After running around in the arena a bit with a stopwatch, I'm going to retract my earlier assertion and agree with you. I feel like the idea that diagonal movements cost more has been "around," so I don't think G-Flex just made it up out of nowhere (any more than I did when I just asserted it), but I'm convinced it's wrong.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Reelyanoob on March 17, 2011, 01:53:18 pm
What about player-created paths?  Not traffic designations, but set point A to point B paths that creatures can incorporate into their calculated paths.  Only the player actually understands his or her fort's layout well enough to optimize pathfinding within it.  Or optimize it for aesthetics so they'll actually use the nice paved roads, or if the player wants the manic little beard transports to be sure to wander past all the nice calming statuary.

I thought that was the point of traffic designations?  How would you go about doing that without traffic designations?

Traffic designations only alter the costs of nearby cells, favouring A* pathing in certain directions.

The idea of manually setting control points is to have a pre-stored section of a path. So, you find the nearest control point, and calculate the nearest control point to your destination. If they're the same, you use normal path finding, if they're not you path to the first control point, follow the stored path to control point 2, and then path to the destination. It'd be best if you could manually link the control points into a network, then dwarves could sample the path from node to node to find the way to any destination very quickly.

Actually it might be better to be able define the search nodes on the scale of whole rooms (similar to burrow designations). Because with the "control point" system as i mentioned it above sometimes a dwarf would backtrack for no reason (since sometimes the destination square would be close to a node on the other side). Pathing into a region should alleviate that possible problem

Another option to storing whole paths is to store a series of waypoints sampling the path, then pathing from one waypoint to the next as you go - this could be used in the control point system eg storing portal/doorway locations between adjacent nodes
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 17, 2011, 02:23:36 pm
What about player-created paths?  Not traffic designations, but set point A to point B paths that creatures can incorporate into their calculated paths.  Only the player actually understands his or her fort's layout well enough to optimize pathfinding within it.  Or optimize it for aesthetics so they'll actually use the nice paved roads, or if the player wants the manic little beard transports to be sure to wander past all the nice calming statuary.

I thought that was the point of traffic designations?  How would you go about doing that without traffic designations?

Traffic designations only alter the costs of nearby cells, favouring A* pathing in certain directions.

Partly incorrect.  Traffic designations don't make A* favor pathing certain directions but through certain areas.

And the advantage of node points is better than traffic designations, as the idea is to give A* more shortcuts.  Traffic areas reduce the number of processing cycles because A* checks fewer tiles.  Pathing node points cause A* to get from one area to another without having to check ANY of the tiles in between.

Effectively, using node-points would cause there to be a wormhole in the map (as far as A* is concerned) with a "traffic cost" of 1/2/5 (depending on traffic settings of the end point) so that A* can skip across the fort with few itterations.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 17, 2011, 02:52:50 pm
Starver:

I've been looking over some of the previous pathfinding threads recently, and I think this link to hierarchical annotated A* pathfinding (http://harablog.wordpress.com/2009/02/05/hierarchical-clearance-based-pathfinding/) is something you should probably check out. (credit: link provided by Footkerchief here (http://www.bay12forums.com/smf/index.php?topic=42678.msg789659#msg789659).)

The article basically talks about how to cut up a map into a multi-tier pathfinding system, but then also strip out the superfluous data.  If a 3x3 clearance pathway exists, and several 1x1 clearance pathways exist, then you only need to record the 3x3 pathway as part of the map, for example. 

I still want to do a bit more research before I really try to put out a cohesive plan, but from what I have read Toady talking about on this, the real problems he has with most of these is making sure that the hierarchical systems would not take up too much memory overhead, and could react to dynamic changes in the map's features without taking up more time than updating the connectivity map does already.  I believe focusing debate upon matching those two criteria may lead to more potentially persuasive suggestions to Toady.



Traffic designations only alter the costs of nearby cells, favouring A* pathing in certain directions.

The idea of manually setting control points is to have a pre-stored section of a path. So, you find the nearest control point, and calculate the nearest control point to your destination. If they're the same, you use normal path finding, if they're not you path to the first control point, follow the stored path to control point 2, and then path to the destination. It'd be best if you could manually link the control points into a network, then dwarves could sample the path from node to node to find the way to any destination very quickly.

Actually it might be better to be able define the search nodes on the scale of whole rooms (similar to burrow designations). Because with the "control point" system as i mentioned it above sometimes a dwarf would backtrack for no reason (since sometimes the destination square would be close to a node on the other side). Pathing into a region should alleviate that possible problem

Another option to storing whole paths is to store a series of waypoints sampling the path, then pathing from one waypoint to the next as you go - this could be used in the control point system eg storing portal/doorway locations between adjacent nodes

I can see that, and I've been reading up more on A* and pathfinding in general, so I think I have a better understanding of the probem now than I did at that point, but the problem I have with manual control is that people don't really use traffic designations already.

Now, I could reluctantly agree with a "designate a room" system where you manually paint rooms, designate bedrooms or other "dead ends", while at the same time designating "hallways" that encourage pathing, and use a manual sort of tiered nodal pathing structure in that way.  The thing is, ideally, this should be automatic.  What if someone is a newb, and doesn't understand it, or if someone just forgets to paint rooms after a period of time, or other problems?  Yes, they would eventually be forced into painting pathfinding systems, and it would be more powerful and flexible than encouraging use/exploit of doors and z-level changes to control pathing, but I really see an automation of this sort of very dry, technical control of AI as being the sort of thing that should be automated.  Especially since something like a flooding of part of these rooms would necessarily have to cut some of these hallways into pieces when they could no longer maintain connectivity.

As I said in the upper half of this post, I'm trying to come up with a good way to dynamically update a multi-tiered connectivity map for less than the cost of a connectivity map upadate in the current system.



Ninja response quasi-edit:

Partly incorrect.  Traffic designations don't make A* favor pathing certain directions but through certain areas.

And the advantage of node points is better than traffic designations, as the idea is to give A* more shortcuts.  Traffic areas reduce the number of processing cycles because A* checks fewer tiles.  Pathing node points cause A* to get from one area to another without having to check ANY of the tiles in between.

Effectively, using node-points would cause there to be a wormhole in the map (as far as A* is concerned) with a "traffic cost" of 1/2/5 (depending on traffic settings of the end point) so that A* can skip across the fort with few itterations.

Not to disagree, with what you are saying, but to illustrate it, the hierarchical AA* (http://harablog.wordpress.com/2009/02/05/hierarchical-clearance-based-pathfinding/) has a good demonstration of this:

Spoiler (click to show/hide)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 17, 2011, 04:58:23 pm
I've seen that article before.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 17, 2011, 05:00:21 pm
The HAA* looks  pretty good and it's generally what I was thinking about.  I'm more thinking about an arbitrary split too instead of my complex BFS  aimless BFS idea. My Idea is not really about speeding up the algorithm but spreading  by splitting the large pathing problem to many smaller pathing problems.

I improved my little test program that I'm checking BFS for splinting of rooms . I added a path count on each possible paths left for each node onc reached . I then color coded the output to :
3+ paths = green
2  paths = yellow
1  path  = orange
0 path = red (not necessarily a dead end .
it looks like this now:
Spoiler (click to show/hide)

I'm thinking of making  a parallel bfs function  start from a few central spots so they compete on grabbing territory This would probably require me to mark owned rooms for each search . This way I can Easily find connections by collisions  of the BFS . This bfs method is still problematic since it doesn't make square rooms but that can be fixed  in a later stage by node exchange;)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Jeoshua on March 17, 2011, 06:27:31 pm
It doesn't need to make square rooms, it needs to make logical paths.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 17, 2011, 07:43:24 pm
It doesn't need to make square rooms, it needs to make logical paths.

Yes, pretty much.  It needs to be able to store a map of "highways" that represent the best places to funnel traffic down.  Whenever a dwarf needs to go a long distance, it needs to get to the nearest entrance to the "highway", follow the highway along to the local area that their destination is in, and get off and switch back to local movement to get to the specific destination they want to go to.

Cutting the map up into "square rooms" is just an intermediate step in making this sort of map, since the game needs to have some sort of way of breaking the vast amounts of map data down into managable chunks.

Basically, what we really need, however, is a system that only needs to do this sort of breaking the map up once, right at the start, and then allows the game to dynamically respond to the changes in the map, tile by tile, by checking only for local changes to the "highway" system that the game builds, and making changes only as necessary to maintain the integrity of the highway system.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: dwarf_sadist on March 17, 2011, 11:47:01 pm
What there needs to be is a table or something for the AI to remember common routes. So when one dwarf finds the quickest way from dinning room to booze stockpile, the computer remembers it for the next time when 50 other dwarfs all start searching for booze at the same time. That way the computer does not have to calculate how best to walk the 37 steps x 50 for each dwarf. Instead, it checks (Stored path + extra distance) * 50 dwarfs.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: zilpin on March 18, 2011, 08:04:31 am
I'm pretty sure Toady already does this.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 18, 2011, 08:21:52 am
I'm pretty sure Toady already does this.

I'm pretty sure he doesn't.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 18, 2011, 08:59:02 am
Indeed.  People (some of them, anyway) aren't very upset about any necessary time take to make any particular path-finding search, except for the fact that it needs to be done every time.  Some very common paths could easily be cached, except:



I suppose in some parts it depends on whether you want to accept a possibly sub-optimal path (especially as that would add an extra possibility or two to the "Dwarfs are Stupid" list) for fast game-playing, or whether you'd rather have a perfect path, every time.

You can add to either (or both?) of these two other requirements:

Firstly the possibility of needing to learn paths, which can either be done by Artificial Stupidity.  The computer knows the perfect path, but the agent knows that it shouldn't know the path so will work with what it does and then work to improve its knowledge, possibly by haranguing another nearby agent for the "information", a.k.a permission to realise that heading along one particular tunnel will take them to where the stone to be dumped is.

Secondly, dynamic response, architecture interaction and patience.  Not just "new path has opened, recalculate!", but "well, the bridge is up now, and it takes a long time to walk around the alternate route, but there's a pressure plate I can stamp on to lower the bridge for a moment, and if I'm quick (...although you can imagine the self-inflicted bridge-launchings and atom-smashings this might also cause[3]) I can get across and save myself a lot of walking".  Or the knowledge that magma-falls start and stop.  Or plain and simple sequential lever-operation to make an airlock-like route open.


Whatever, if there's limited/learned knowledge of routing for friendly agents, hostile ones are going to have the same possibilities to bustle their way through, a bit like certain friendly trader-nations can negate traps they know about after they've been pushed into becoming hostile.   Which is not to say that a "kill me!" dummy lever couldn't be added to kill off the more experimental of enemies, alongside the regular one for actually gaining entry. :)

[1] There are arguments for getting a selection of suitably known "to get there, starting from not-quite-here paths, run the "from here" path search until you encounter a point upon one or other of the paths then using the remainder of the cached route.

[2] "Hug the left" or "Hug the right" rules (possibly cultural as to which one gets adopted!) would help, here, and I think the current "which complex diagonal route to take" agent-pathing routine does give a taste of that.  Apart from dwarfs with different travel speed capabilities, it would mean you'd get an orderly progression of westward-bound dwarfs on one side of a corridor and eastward bound ones on the other side, for example.

[3] Sort-of-Mechanics suggestion: Klaxon.  In the above circumstances, link a lever (or other input) to both a bridge and a klaxon.  Klaxon has a quicker response than the bridge and blares out, and the dwarfs find out/learn/already know what this means and immediately vacate any danger area.  Other uses: general alarms (could even be tied directly into with military alerts, e.g. "enemies at south entrance!  Military get read, straight from pressure-plate activation", civvies get to safety!"), disturbing noise-makers (when you really want to annoy nobles), alarm-clocks for sleeping dwarfs ("come on, trader, get out of bed and get to the depot, before they leave!"), creature scarers ([CAN LEARN] or [INTELLIGENT] creatures get to ignore them, eventually, but at least at first they can be used to either repulse wildlife/etc or if set off behind them drawn them further into a zone you want them to be in.)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 18, 2011, 09:50:36 am
There's basically no way you're going to be able to do something like having a dwarf learn that he's going to step on a pressure plate, and then will have only 100 frames to get across the bridge before it is raised.  That requires an abstract understanding of cause and effect that is way beyond the game's current level of AI sophistication.

Having dwarves "hug right" is a good idea, something I was thinking about regarding "highways", where you don't need one-way tiles, just three or four or five-tile wide "highway" hallways, where dwarves naturally hug right, and then step to the left to "pass" slower-moving dwarves the way that a car on the highway will pass slower traffic in the real world.  (Assuming we aren't dealing with island drive-on-the-left cultures.)

Doing this sort of thing isn't standard A*, however, you basically need to have the game recognize that you are dealing with a several-tile-wide "hallway" when you create something like that.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: ullrich on March 18, 2011, 12:21:04 pm
What would be much, much simpler, and provide an optimal solution, as well as running very fast, would just be wavefront pathing.

An explanation of wavefront in there:
Spoiler (click to show/hide)

Basically you can generate a "pathing" map of the entire map, that only needs to be altered when something physical changes the walkable tiles (i.e. bridge, locked door, etc).

Then the dwarf simply finds out is goal tile, and uses the associated map for that tile to find the cheapest adjacent tile.

It would be a massive improvement in speed at the cost of memory space, although may cause a "chug" when paths have to be recalculated (in general wont happen often, unless you have a repeater).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 18, 2011, 12:35:17 pm
Except that it only works for any given goal.  It's also really CPU intensive as it ignores no tiles and every creature with a unique goal would need to build a weight-map.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 18, 2011, 02:03:06 pm
That wave front thing sounds like Breadth first search from the destination. My current program is similar to that - it find the first open upper left corner and  iterate through the whole maze aimlessly( I didn't tell it to find something yet) .  The problem with this kind of algorithm is that it's extremely inefficient especially if you don't limit your depth . This isn't going to work on a multi layer complicated maze like DF , we are talking about 192~X192~ per level for 4X4 embark .

The only reason I'm using breadth first search is to group nearby nodes so map segmentation would be logical rather than arbitrary. I recently made the BFS function have the ability to be iterative and soon I'll do a multiwave from multiple blocks (might share the visit array then I can scan for "mountains") .

I just need to add easy maze load save like ?maze= with a hexadecimal or b64 value . Then after it's somewhat more functional I can start experimenting all sort of pathing methods  ;) .

So far I only added wall toggling on edges . I'm keeping it as simple as possible while being somewhat functional .

I'm might have mentioned it before but without a clear working algorithm like a computer program I doubt anything would come out of this thread.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 18, 2011, 04:23:35 pm
I just need to add easy maze load save like ?maze= with a hexadecimal or b64 value . Then after it's somewhat more functional I can start experimenting all sort of pathing methods  ;) .

You should do that. I'll add a mode that outputs to that format to this little script I made yesterday that generates random maps (https://gist.github.com/876876).

I'm might have mentioned it before but without a clear working algorithm like a computer program I doubt anything would come out of this thread.

True. I really need to study this stuff more.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 18, 2011, 04:57:24 pm
I just need to add easy maze load save like ?maze= with a hexadecimal or b64 value . Then after it's somewhat more functional I can start experimenting all sort of pathing methods  ;) .

You should do that.
I just did  :D  but the output is really long with hex but if you are well versed in binary you could almost see the maze  ;) .
example:
http://niseg.0adz.com/test_maze.html?maze=0080008000800000FFF7008000000080EFFF008000010080FFF7008000000080

I can change that to B64 -the conversion is the same just 6bits at a time instead of 4 (did it on a damage calculator for infantry online). B64 would be 43 chars instead of 64. I might add some run length encoding into it but I think it's too much trouble for this narrow purpose (We aren't trying to rewrite DF in JS ). 



I'll add a mode that outputs to that format to this little script I made yesterday that generates random maps (https://gist.github.com/876876).
Python stuff ewww . I can probably convert that to JS - I can read pretty much any computer language ;). As I mentioned I like JS because it's easy to code in (for C coders) and runs on any web browser. I did notice that on mobile browser my page isn't working too well (not critical from my point of view but I might be able to fix it). I also added a code section generator to convert the maze into forum post-able (there is probably something like this in existence already that does the same thing).

I'm might have mentioned it before but without a clear working algorithm like a computer program I doubt anything would come out of this thread.
True. I really need to study this stuff more.

People at work saw my Algorithm book out and had memories . Learning is important part of my job. I usually remember what I learn but I only think we covered half that book ;).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: PartyBear on March 18, 2011, 05:23:52 pm
Except that it only works for any given goal.  It's also really CPU intensive as it ignores no tiles and every creature with a unique goal would need to build a weight-map.

I think the idea might be for every tile to store a map of the distance to every other tile from the beginning.  If the maps never had to change, it would work well, but of course we can dig and build to drastically change the landscape, and to work perfectly, every single tile would have to recalculate its map every time you did something like lock a door or dig a tile, which would take a very long time.

But maybe it wouldn't have to work perfectly.  It should be possible to prioritize which tiles get their maps recalculated.  Priorities could be based on whether the tiles are associated with active jobs, how critical those jobs are, whether the tiles have items on them, whether the tiles are part of a stockpile, building, room, or burrow, and of course when a dwarf following an outdated map hits a dead end (on a side note, I like the realism that particular wrinkle could add).  Recalculating low priority maps could be done at low CPU priority, as well, or when the simulation is paused.  That kind of thing sounds like asking for multithreading again, though.  This pathing method would probably benefit even more from multithreading than the existing method, actually.

Also, only parts of the maps should actually change.  For example, if you cause a new tile to be walkable, you only have to look at the lowest cost tile adjacent to the new tile for the new tile's cost, and then calculate starting from there.

I can't say that all that would actually be enough to save your FPS, and it probably wouldn't be.  I'm just throwing it out there.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 18, 2011, 05:31:23 pm
But the major problems with nodal/hierarchical pathfinding, as far as Toady has expressed them, are the need to recalculate connectivity with every map change and not having to take up too much additional memory.  If you're going to try to come up with a better pathfinding system, you have to start off with the argument of why whatever it is you are talking about is better capable of reacting to unexpected changes to the shape of your map than standard A* with a connectivity map is.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 18, 2011, 06:01:03 pm
I think the idea might be for every tile to store a map of the distance to every other tile from the beginning.

No, bad puppy, no cookie.  That's an O(n^2) function with regards to memory.

There are approximately 230,400 tiles for a 1x1 embark, and you want each of them to hold a copy of the entire map
(assuming 1 byte of storage to track tile location and distance, a 1x1 embark at the listed size would require 53,084,160,000 bytes of information, or 50,625 MB of information, and you want that information in RAM)

((A 2x2 embark would be 810,000 MB, and a standard 4x4 would be 12,960,000 MB, and the maximum 16x16 falls in at 3,317,760,000 MB (3164 TB)))
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: PartyBear on March 18, 2011, 06:28:15 pm
Yeah, I knew the memory requirements were nutty, even though I didn't bother to actually calculate them (so thanks for that), but I liked the thought experiment anyway.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Andeerz on March 18, 2011, 06:46:18 pm
Me too, PartyBear!  For what it is worth, I am very appreciative of different strategies (no matter how obscenely implausible and practical they are) being presented if not for giving a solution, then for giving some much needed food for thought!  I am also very appreciative of well reasoned "tests" of such strategies as presented (though I'm not appreciative of arrogant delivery... not that my opinion really matters here :P) by Draco18s.  Gives me and likely other readers of this thread some good stuff to think about... 

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 18, 2011, 07:10:58 pm
Well, for myself, I think this is what makes me most pause and give thought:

If the maps never had to change, it would work well, but of course we can dig and build to drastically change the landscape, and to work perfectly, every single tile would have to recalculate its map every time you did something like lock a door or dig a tile, which would take a very long time.

If I'm going to argue for dynamic hierarchical map generation, then that means that the system will need to react quickly and with little need to recalculate based upon a door being locked (or denying access to animals), and the best way to do that would be to make doors a node all to their own.

Doing this would mean locking a door would simply mean disconnecting that door's node from everything else. 

I don't like it, but making doors nodes leads to the Granite26-suggestion of reshaping the nodes based upon where the doors are as a matter of course.  (Although I still think a more dynamic system is necessary so that it isn't all loaded on door placement, and there should still be a recognition of "vertical hallways" like stairwells.)

More dramatic changes (like channeling out a hole in the floor) would still require a recalculation, but if you start from "local cells", and only work on their relation to other local cells, running things through a "highway system", then you can hopefully dramatically cut down on how many recalculations you need to do on changes to the map, just to local connectivity, and whether you can still make the assumption that different modes of transport can still path through a given cell.

Otherwise, there might be a need to not cut out all the redundant pathways in a Hierarchical AA* mapway, since a blocked path would necessitate looking for detours, but you should still be able to maintain the "highway" map for a fairly low overhead compared to the cost of the current connectivity map. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 18, 2011, 08:15:16 pm
Python stuff ewww .

Careful, thems' fightin' words.

Faux offense aside, what don't you like about it? (PM me or something, no need cluttering this thread with a programming language discussion, too!)

People at work saw my Algorithm book out and had memories . Learning is important part of my job. I usually remember what I learn but I only think we covered half that book ;).

Least you got a book. I have... Wikipedia?

So I looked up what IP routing was doing (reasoning that since most of the graph is unknown before-hand there's some voodoo magic going on), but it turns out it tends to use the same methods we've been looking at... with the added benefit of being highly distributed, so each node can store routes to common destinations.

I don't like it, but making doors nodes leads to the Granite26-suggestion of reshaping the nodes based upon where the doors are as a matter of course.  (Although I still think a more dynamic system is necessary so that it isn't all loaded on door placement, and there should still be a recognition of "vertical hallways" like stairwells.)

You have got to find a better term for that.

I'm starting to think that just about all can be done is to split the pathfinding code out into a child thread so at the very least it doesn't block the game.

Aside from doors, don't forget burrows. These will slice up any 'rooms' that are created quite easily. Imagine your poor dwarf being told by the node-traversal algorithm that he can get somewhere (because his node connects to that node, obv., optionally through some intermediary nodes) but he can't get to the exit of his node that leads to that path, since it's not in the burrow. Now our dwarves act like cats trying to path through a pet-locked door, too...
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 18, 2011, 08:57:30 pm
Aside from doors, don't forget burrows. These will slice up any 'rooms' that are created quite easily. Imagine your poor dwarf being told by the node-traversal algorithm that he can get somewhere (because his node connects to that node, obv., optionally through some intermediary nodes) but he can't get to the exit of his node that leads to that path, since it's not in the burrow. Now our dwarves act like cats trying to path through a pet-locked door, too...

As pointed out recently (if not this thread, then somewhere else, in which case apologies and just take this as information instead of re-telling), Burrows aren't "you may only step on these tiles", but are mechanisms to say "if the item you're looking at isn't in the burrow(s) you're in, forget about that job".  If the target location (tile with a bit of rock, or place to eventually put that rock[1]) is inside the burrows for a given agent, that agent will gladly walk across non-burrow tiles to get from the first bit to the last, exactly the same as if there was no burrow, just the same old pathing algorithm with good reason to send them that way.


And, regarding the "having no way to tell that the pressure plate will allow travel" issue, whoever it was now who responded directly to that last post of mine, I'm also very much of that opinion.  I was just trying to break the problem down into various different solutions.  Primarily "always have a quick route" vs "always strive for the best route", but with additional 'add-on' items of having both Artificial Stupidity and more advanced Architectural Awareness that could be tacked onto either solution (or a happy medium that doesn't go so slowly, and also does tend to hit the 'best' route 7 or 8 times out of 10, so giving the players the balance of speed and accuracy they crave.

Both the AS and the AA would always add something to the load (the first may have to prune omnisciently-known details from the master-map, whatever that might contain, according to whether the agent involved is supposed to be ignorant of them; the second would need a more comprehensive route-finding programme with at the very least a limited 'T'-dimension on top of the current X,Y,Z dimension being examined for viable paths), so they're more speculation.  Although I think at least the AS could be done, in a more shortcutted way, yet still allowing the agents to exhibit obvious ignorance until new paths are learnt.  AA is a bit further out there.

Prior to that I'd really rather like instead to have a net of connections which has "fly", "climb short walls", "jump gaps" and even "bridge a gap" flags (or counters, e.g. with a limited number of bridging ladders available to an invading squad) which allow overlapping node-maps that represent better paths for particular types or quality of agents moving across the map, and explores the possibility of the defences-in-depth (which I currently establish purely out of moral/aesthetic reasons) to become both useful and even needed to be further refined to proof them against the as yet unencountered enemies with even more tricks up their sleeves than I can currently imagine.



[1] Although I think that bit of code is faulty (or could be written better), the number of times it appears to want to start a job but then has to spawn a notification complaining that the destination is unreachable.  If it was unreachable, you shouldn't have even considered picking up that stone that you'd have to dump somewhere not within your current set of burrow zones...
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 18, 2011, 09:06:18 pm
I thought burrows simply cut off where dwarves were able to take up tasks, but they could path through areas outside their burrows?  Basically, if you told a dwarf that they were part of a small burrow, and they started outside of that burrow, they would have to have some way of pathing to get into that burrow to even start with. 

Doing a pretty quick test, if you make a burrow that has a few "islands" of burrow area with a gap of non-burrow area, dwarves will go through areas outside their burrow to reach areas that are inside their burrow.  Burrows have no effect on pathfinding code, just upon what jobs or items they can "see" to take up.

Anyway, suggesting multithreading pathfinding is very, very common, and Toady has pretty clearly said he isn't interested in it.



ah, nevermind, heavily ninjad.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 18, 2011, 09:24:51 pm
ah, nevermind, heavily ninjad.
But you actually tested it (I just went off memory of past experiences), plus explained it far more succinctly.

I actually prefer your reply, but it might be considered petulant to now delete my own.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 18, 2011, 09:45:02 pm
No need to delete it, it doesn't harm anything being there...

Prior to that I'd really rather like instead to have a net of connections which has "fly", "climb short walls", "jump gaps" and even "bridge a gap" flags (or counters, e.g. with a limited number of bridging ladders available to an invading squad) which allow overlapping node-maps that represent better paths for particular types or quality of agents moving across the map, and explores the possibility of the defences-in-depth (which I currently establish purely out of moral/aesthetic reasons) to become both useful and even needed to be further refined to proof them against the as yet unencountered enemies with even more tricks up their sleeves than I can currently imagine.

That's actually a part of the Hierarchical AA* (http://harablog.wordpress.com/2009/02/05/hierarchical-clearance-based-pathfinding/) type of code - you can store pathways, and include flags for what sorts of movement types are allowed to use those pathways.  You might store a long path for regular walkers, but have a short path for fliers across a chasm.  It's just that node's connection carries a "fliers only" flag. Or, you can store a "can jump a single gap" or "can climb one z-level of wall" type of pathway, instead. 

Oh, wow, I just thought about how horrible a mess the digging/tunneling enemies pathfinding code will be without having some sort of code built specifically around allowing that sort of thing to occur.  A* is just not really built for "you can ignore one otherwise impassible wall if you want to" types of pathfinding.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 18, 2011, 10:08:11 pm
Oh, wow, I just thought about how horrible a mess the digging/tunneling enemies pathfinding code will be without having some sort of code built specifically around allowing that sort of thing to occur.  A* is just not really built for "you can ignore one otherwise impassible wall if you want to" types of pathfinding.
I see it as digging-capable ground-hugging squads (much as bridging-capable squads, also without intrinsic flight) arriving with the inherent ability/tendency to route across 'N' tiles of otherwise unwalkable terrain.

A version of the HAA* which allows path-search to tunnel through 'N' tiles of earth, or cross 'N' ditches (but not across a single ditch of width 'N', unless N==1 of course :) ) could say "Ah, diggers, you may set about tunnelling through those tiles, and you bridgers can set about bridging those ditches...  But no more!".

And then it gets a complicated mess when an attacking squad actually has so many bridging ladders (courtesy of suitably equipped squad members) and so much willingness to dig through so much ground (courtesy of some sappers, whose energies may sap, and possibly after only N/2 tiles of various rocks instead of N of soil) and both hierarchies have to be examined, with not just a single "distance from source" (or "to destination") flag per examined tile, but one for each "used X bridges, used Y digging efforts" to reach them.

Still, I think it could be done.  I've still got some of my unpublished experimental scripts (from when the Other Pathing Thread was actively running) sitting around on either this machine or the one upstairs, and I'd sort of started hacking this ability into one particular one.  Maybe I'll dig up what I've got and get it actually working.

(Certainly, they're not as quick as their non-complex plain-old-A* companions, but as I hadn't really tried any of the obvious optimisations it's possible I can make them not too much slower, and with additional partial-path caching added in they could be something worthwhile (converted from my test-script format into something properly executabley encoded, of course).  I must get my finger out, this time round.)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 18, 2011, 10:08:37 pm
I just did  :D  but the output is really long with hex but if you are well versed in binary you could almost see the maze  ;) .
example:
http://niseg.0adz.com/test_maze.html?maze=0080008000800000FFF7008000000080EFFF008000010080FFF7008000000080

I can change that to B64 -the conversion is the same just 6bits at a time instead of 4 (did it on a damage calculator for infantry online). B64 would be 43 chars instead of 64. I might add some run length encoding into it but I think it's too much trouble for this narrow purpose (We aren't trying to rewrite DF in JS ). 

My script now (also) creates a link to that page with the maze (not really a maze, but whatever) properly encoded.

Still available at the same location: https://gist.github.com/876876

Also, DF in javascript would be epic, and should be considered.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: ullrich on March 18, 2011, 11:04:20 pm
That wave front thing sounds like Breadth first search from the destination.

Wavefront and Breadth are not the same, wavefront doesn't actually store nodes (it doesn't need to keep a closed set) so its more efficient.

Basically you have 2 extremes memory and processing speed:
1) Wave front = max speed, massive set and static memory (you don't generate new pathing maps EVER, they are all generated already and you simply change the maps value as the terrain changes). Also it does not need to re-expand the entire map on terrain transition as walls/un-walkable squares get a value such as -1 that results in it getting ignored and will prevent further expansion.

Alternatively just 1 single pathing map could be kept and the values re-propagated for each creature, while this sounds really bad, and in terms of nodes is higher it uses a much simpler expansion logic than breadth first or A* so potentially expanding say 2x as many nodes could be done faster in wavefront than A*, especially in dead end cases since wavefront dead end cost is minimal.

2) A* = best memory usage (min), decent speed.
All these really fancy algorithms discussed in this thread will likely take longer to run and get functioning properly if made automatic then a simple heuristic improvement would result in improvement of the current manhatten A*. As I said previously in this thread the cross product manhatten heuristic can provide massive node expansion reductions by adding tie-breaking to tiles:
End in a Room, 1 entrance, close.  Opposite Side of Map, multiple paths.  Opposite Corners of Map, multiple paths. 
Breath-First376250488
A* (Manhattan)7781340
A* (Vector)4872117

From this we get 62.3%, 88.9%, 34.4% of the number of nodes generated to complete the path.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 19, 2011, 09:34:15 am
Python stuff ewww .

Careful, thems' fightin' words.

Faux offense aside, what don't you like about it? (PM me or something, no need cluttering this thread with a programming language discussion, too!)

No offense intended I am just too used to C-like languages . I saw someone at work that uses awk - I was surprised but it does have its uses.



Least you got a book. I have... Wikipedia?

Its a pretty famous book most CS major know.  I learned complexity of algorithm with it . It's big and white and it's also very expensive ( I think it cost me like 80$).

So I looked up what IP routing was doing (reasoning that since most of the graph is unknown before-hand there's some voodoo magic going on), but it turns out it tends to use the same methods we've been looking at... with the added benefit of being highly distributed, so each node can store routes to common destinations.

Ip routing is a pretty simple system where the network is divided into segments and the router is in charge of sending them foward. the clients are pretty simplistic and don't do much routing while routers generally know "who know how to get to the destination" . The paths are also pretty short. It's also kind of highways and intersections.


Anyways my idea is based on the fact that  pathing algorithm has an  exponential worst case complexity (k^N) which are generally worst than N^k. There is still a way to reduce the runtime by converting a problem into many smaller problems:
consider constant a which is room size and variable x number of rooms
if complexity N= ax  and your complexity is k^N if you can convert the problem from k^(a*x) to k^x+x*k^n you'll have a better runtime . This basically means you can convert the problem to x room traversal + x problems of moving from one room to another.

You are still using A* but you say "what happens when a room changes ?" you don't really need to regenerate the whole map. It's like redrawing the map of the USA when Florida connect two roads. The only one that's affected is the local area ( neighboring towns). If for example Tampa is effected and you want to get from Los-Angeles  to Tampa most of your way  would be identical except in the end.. My solution doesn't require you to know the "paths" from one room to another it just requires you to know if such path  exists. This gives a dwarf a whole lot of freedom of movement even though he's  using a "map".    If a dwarf or whatever finds out some room have been blocked he'll then update that room and its neighboring rooms and find a new path.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 19, 2011, 05:39:23 pm
I didn't read the whole thread so excuse me If someone already said what I'll say.
The current most efficient pathfinding method use "navigation mesh". This method is generaly used in non-tile based map, but only because it's easier to use each tile as a node , not because it's more efficient. here are the basics:

-First we "cut" the map in convex polygons (rectangle in our case)
-We represent this polygons with a graph , each polygon is a node, 2 nodes are connected if the polygons they represent are touching. ( so a node will often represent more than 100 tiles)
-We use A* on this graph, this will give us the list of polygons our path go through.
-Then we use the funnel algorithm (here is a link http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html )

At this point we should have a set of points where our dwarf just need to go in straight line between each points. But what is a straight line between 2 points in tile based map? Well , we could define it as going in diagonal (starting form the 1st point) until reaching one of the two coordonates of the 2nd point , then going in "true" straight line (horizontal or vertical) for example.

IF the map was static , I think this method could easily be 100 times (depending on the fortress shape) faster than the actual method.
But the map isn't static, it's true, but the map is changing only 1 tile by 1 tile. We could create a function that will add a node to our graph each time a dwarf dig 1 tile, and merge 2 rectangles if they share an entire side, this function should also check each time a door is closed or a wall build if there is change to do in the graph. I don't think this function is very hard to make, and probably not very CPU expensive. So I have hope this method could still be at least 10times faster than the actual method.

Each part of this method is very easy , and shouldn't take more than 100 lines.
There is tons of ways to represent a graph (http://en.wikipedia.org/wiki/Graph_(data_structure) give the most common)
I hope toady will make something about it , his game is fucking great , if he doesn't want to dive in the pathfinding, maybe if he could just give the format he uses to represent the map and coordonates , and the format he wants for the output path , I'll be glad doing this for him.
Forgive my poor english.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 19, 2011, 06:17:51 pm
-First we "cut" the map in convex polygons (rectangle in our case)
-We represent this polygons with a graph , each polygon is a node, 2 nodes are connected if the polygons they represent are touching. ( so a node will often represent more than 100 tiles)
-We use A* on this graph, this will give us the list of polygons our path go through.
-Then we use the funnel algorithme (here is a link http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html )

One minor tweak: instead of convex polygons, convex polyhedrons (rectangular prisms). Under normal circumstances, there'd be no difference since most forts are mostly 2d floors with very few 3d rooms, but if it considers vertical space first, it should end up with nodes for uninterrupted stair columns (as well as air space, which may be useful later for flight). May want to limit polyhedron size so that any single node doesn't cover half the z level or every bit of open space above the tallest peak, however; Perhaps to map block size, which is some 16 tiles, so 16x16x16 at worst. That would also limit rebuilding the nodes.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 19, 2011, 06:37:25 pm
-First we "cut" the map in convex polygons (rectangle in our case)
-We represent this polygons with a graph , each polygon is a node, 2 nodes are connected if the polygons they represent are touching. ( so a node will often represent more than 100 tiles)
-We use A* on this graph, this will give us the list of polygons our path go through.
-Then we use the funnel algorithme (here is a link http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html )

One minor tweak: instead of convex polygons, convex polyhedrons (rectangular prisms). Under normal circumstances, there'd be no difference since most forts are mostly 2d floors with very few 3d rooms, but if it considers vertical space first, it should end up with nodes for uninterrupted stair columns (as well as air space, which may be useful later for flight). May want to limit polyhedron size so that any single node doesn't cover half the z level or every bit of open space above the tallest peak, however; Perhaps to map block size, which is some 16 tiles, so 16x16x16 at worst. That would also limit rebuilding the nodes.

Yes, you are right, using polyhedrons would greatly improve pathfinding if it comes through a hundred stairs. Though for the size limitation I don't realy see the utility, I think there will still be the same amount of nodes rebuilding even with a size limit , or maybe I am missing something?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 19, 2011, 07:10:17 pm
-First we "cut" the map in convex polygons (rectangle in our case)
-We represent this polygons with a graph , each polygon is a node, 2 nodes are connected if the polygons they represent are touching. ( so a node will often represent more than 100 tiles)
-We use A* on this graph, this will give us the list of polygons our path go through.
-Then we use the funnel algorithme (here is a link http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html )

One minor tweak: instead of convex polygons, convex polyhedrons (rectangular prisms). Under normal circumstances, there'd be no difference since most forts are mostly 2d floors with very few 3d rooms, but if it considers vertical space first, it should end up with nodes for uninterrupted stair columns (as well as air space, which may be useful later for flight). May want to limit polyhedron size so that any single node doesn't cover half the z level or every bit of open space above the tallest peak, however; Perhaps to map block size, which is some 16 tiles, so 16x16x16 at worst. That would also limit rebuilding the nodes.

Yes, you are right, using polyhedrons would greatly improve pathfinding if it comes through a hundred stairs. Though for the size limitation I don't realy see the utility, I think there will still be the same amount of nodes rebuilding even with a size limit , or maybe I am missing something?

You're probably right on the rebuilding thing. I was mainly thinking that limiting the size of an individual node would also limit the volume that an A* or whatever would have to cover for internal navigation, especially since this method makes it easy to delay calculation of later parts of the path (for example, to when the creature gets to that node).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Soralin on March 20, 2011, 03:38:02 am
But if your rectangular prisms are just made of open space, you don't even need A* for internal navigation, you can just walk in a straight line.

And rebuilding a node is rather easy.  I mean, if you stick a block in the middle of a big flat rectangle, you can just split it into two wide rectangles, and two narrow rectangles that fill the space that the original one did.  No need for global rebuilding or anything like that.  And removing the object would just work the other way around, generate a new tile, and see if you can merge it with a nearby rectangle (one edge is the same size as the adjoining rectangle), and repeat until you're done.

I wrote up a post on something like this (although without the funnel stuff, just A* from node to node) at http://www.bay12forums.com/smf/index.php?topic=42678
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 20, 2011, 04:15:30 am
But if your rectangular prisms are just made of open space, you don't even need A* for internal navigation, you can just walk in a straight line.

And rebuilding a node is rather easy.  I mean, if you stick a block in the middle of a big flat rectangle, you can just split it into two wide rectangles, and two narrow rectangles that fill the space that the original one did.  No need for global rebuilding or anything like that.  And removing the object would just work the other way around, generate a new tile, and see if you can merge it with a nearby rectangle (one edge is the same size as the adjoining rectangle), and repeat until you're done.

I wrote up a post on something like this (although without the funnel stuff, just A* from node to node) at http://www.bay12forums.com/smf/index.php?topic=42678
yep, that's the idea with a convex shape, we know the shortest path between every 2 points of the shape is the straight line, so there is no internal pathfinding to do.
And you are right the node building function could work with just the ability to add a node , merge 2 nodes , and split a node, and that's it. So pretty easy and not much calcultation to do.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 21, 2011, 12:46:36 am
But if your rectangular prisms are just made of open space, you don't even need A* for internal navigation, you can just walk in a straight line.

I am currently putting another dent in my wall with my forehead. So frigging obvious that I needed someone else to point it out to me...

The worst part is that while I was writing that I was thinking that flying creatures could just straight line when they're in those now-rather-pointless 16x16x16 nodes...

Just one question: since nodes only contain tiles that can be walk, flown, or swum to/in, things like constructions would obviously be excluded from them, as well as blocking tiles in workshops, locked doors, grates, etc. If you consider this system to be two levels of addressing specifically for path finding, then those objects are not addressable because they are not in nodes. But building destroyers need to get to those to destroy them, and dwarves need to get to them (as well as natural walls) to deconstruct or dig. Ideas?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 21, 2011, 05:08:34 am
I played with my BFS function this weekend(in Israel Sunday is a work day) and managed to mess it up - luckly i use my website as "backup" and it's such a basic function it's not a big deal. I'll probably rewrite it especially due to its inefficiency .

My plan was to create rooms by doing an incremental BFS .  I found an easy way to do it. BFS uses a queue of nodes and pushes new nodes it visits . All i need to do to have mutiple starting points is push multiple nodes (starting points) at the beginning  and then I might be interested to mark the "starting point" when I visit node. Then I'll get a "ridge map" I'll use to slice up the map into rectangles.

I'm worried about an arbitrary slice up getting conditions where you get illogical room setups like this :
Code: [Select]
012345_67
1#  # |
|-----+---------
2#  # |
3#####|##
4#  # |
5
We are humans so we can see the rooms should be sliced between 3,4 while a computer without a proper algorithm can't "see" it( I'll give credit for my wife which was also a CS major).

I might just add A*algorithm for runtime checking. I am also looking into getting this silly JS from a c structure  to a more of object oriented structure. The program I made is fairly simple and JS is really easy to learn . JS can also load website  hosted files local files is a problem..
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 21, 2011, 08:22:17 am
[...]since nodes only contain tiles that can be walk, flown, or swum to/in, things like constructions would obviously be excluded from them, as well as blocking tiles in workshops, locked doors, grates, etc.[...]
Not really helping matters, here, but in a world where it is considered important to deal with the needs of all possible pathers[1], walk-through, fly-through and swim-through[2] tiles/nodes might need to be joined by dig-through and deconstruct-through.  Which could end up with every single tile (leastwise all those that have been revealed to the agent[3]) having to be a member of at least one convex volume/node-map/whatever.

But, that is definitely complicating things.

(BTW, one less complication that such extended thoughts about pathing brings about is that ghost-travel could ignore the tile status completely.  Or, rather, be restricted to a historical layout, i.e. a path (or a small set of them) laid out at the time of 'deceasement', regardless of whether they now have to go through walls or other barriers, cross now unbridged chasms, haunt their way through flowing magma and running water with no impedance whatsoever.)



[1] Which it may not be.  If you have a troupe of invaders with digging or deconstruction ability, but only rarely would you get one, you could make a special-case pathing (if necessary, brute-force, tile-by-tile search without much reference (if any) to the established nodes.  However, you just know that if they're made a special case, someone will rue the incompatible code later on, right? :)

[2] Split into surface-swim-to and whole-volume-swim-to, possibly.  If not also something for creatures that water gives no impedance (or fear of drowning, at least for a while), but can't actually swim, so that their routing nodes would be on the bottom of rivers, reservoirs, etc, essentially treating wet ditches as if they were dry, etc...  And then double all of those to differentiate between water-swim and magma-swim.

[3] Another complication there.  Hostile diggers might be mapped as coming out of as yet unrevealed caverns.  And at the same time the possibility of a goblin sapper team tunnelling away a short-cut into a fortress and hitting your pre-filled "magma cavity wall" trap would be funny as well.  Really, this point is probably moot until omniscient pathfinding is no longer the norm, though.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 21, 2011, 10:57:27 am
Do it like this:

Find all walkable tiles, cluster into nodes (we'll treat workshops differently in a moment).
Then find all swim-able tiles, cluster into additional nodes with the "swim only" modifier (tiles that are in both, which I think is 3/7, are their own node).
(Do the same for magma).
Then find all remaining empty tiles, cluster into nodes, with the note "fly only."
Connect all neighboring nodes, the node connections will also carry the walk/fly/swim flags.
Done.

Now your volumes of sky are their own node, but dwarves can't path through it ("fly only").

Workshops we treat like this:

3x3* node centered on the workshop which splits the larger "room" node, which is then split thus:
1x1 node in the center as the destination (and walkable) (this aids pathfinding, as only the center tile is the workshop as far as item and locations).
Outside tiles are then removed if they are non-walkable, remaining are grouped as appropriate.

*For non-3x3 buildings, which exist, the node would be the building's size.  The job-location node is split out as normal, followed by the subtraction of non-walkable spaces.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 21, 2011, 12:13:29 pm
Do it like this:

Find all walkable tiles, cluster into nodes (we'll treat workshops differently in a moment).
Then find all swim-able tiles, cluster into additional nodes with the "swim only" modifier (tiles that are in both, which I think is 3/7, are their own node).
(Do the same for magma).
Then find all remaining empty tiles, cluster into nodes, with the note "fly only."
Connect all neighboring nodes, the node connections will also carry the walk/fly/swim flags.
Done.

Now your volumes of sky are their own node, but dwarves can't path through it ("fly only").

Workshops we treat like this:

3x3* node centered on the workshop which splits the larger "room" node, which is then split thus:
1x1 node in the center as the destination (and walkable) (this aids pathfinding, as only the center tile is the workshop as far as item and locations).
Outside tiles are then removed if they are non-walkable, remaining are grouped as appropriate.

*For non-3x3 buildings, which exist, the node would be the building's size.  The job-location node is split out as normal, followed by the subtraction of non-walkable spaces.
You could maybe apply the flag system to workshops too,  that will prevent dwarves to pass through them, except those who have a job to do in it.
Then every tiles could be represented by a graph representing walkable/non-walkable/swimable/flyable/other(all types of workshops) cuboid.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Uristocrat on March 21, 2011, 02:01:44 pm
(BTW, one less complication that such extended thoughts about pathing brings about is that ghost-travel could ignore the tile status completely.  Or, rather, be restricted to a historical layout, i.e. a path (or a small set of them) laid out at the time of 'deceasement', regardless of whether they now have to go through walls or other barriers, cross now unbridged chasms, haunt their way through flowing magma and running water with no impedance whatsoever.)

Ghosts have no reason to path to begin with.  They can walk through everything, so you just do a straight line path.  Or maybe you want them to pretend they were alive, in which case you can just cache a few paths just for them based on how things were when they died and have them wander the fortress in exactly the same way (even if it changes or someone builds a wall in the way).  They are ghosts, after all.  As far as they're concerned *all* tiles are walkable, so a straight line is always going to be the fastest way.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 21, 2011, 05:06:55 pm
(BTW, one less complication that such extended thoughts about pathing brings about is that ghost-travel could ignore the tile status completely.  Or, rather, be restricted to a historical layout, i.e. a path (or a small set of them) laid out at the time of 'deceasement', regardless of whether they now have to go through walls or other barriers, cross now unbridged chasms, haunt their way through flowing magma and running water with no impedance whatsoever.)

Ghosts have no reason to path to begin with.  They can walk through everything, so you just do a straight line path.  Or maybe you want them to pretend they were alive, in which case you can just cache a few paths just for them based on how things were when they died and have them wander the fortress in exactly the same way (even if it changes or someone builds a wall in the way).  They are ghosts, after all.  As far as they're concerned *all* tiles are walkable, so a straight line is always going to be the fastest way.

More or less what I meant.  More or less in the order I said it.  But I was probably too obtuse in the manner I did so. :)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Uristocrat on March 21, 2011, 05:23:10 pm
More or less what I meant.  More or less in the order I said it.  But I was probably too obtuse in the manner I did so. :)

Yeah, I just meant that it was only necessary (at most) to cache a few routes for them.  You shouldn't need to worry about rebuilding your overall map data to suit them.  Waste of time and memory :)

The best way to speed up a computer is to give it less work to do.  Eliminating stuff that creates complications is one way of doing that.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 21, 2011, 07:49:45 pm
Do it like this:

Find all walkable tiles, cluster into nodes (we'll treat workshops differently in a moment).
Then find all swim-able tiles, cluster into additional nodes with the "swim only" modifier (tiles that are in both, which I think is 3/7, are their own node).
(Do the same for magma).
Then find all remaining empty tiles, cluster into nodes, with the note "fly only."
Connect all neighboring nodes, the node connections will also carry the walk/fly/swim flags.
Done.

Here's something I've been thinking about, however - if you are drawing a map where you only make local updates, not global ones, odds are, you're going to start with a wide open field and some caverns and a functionally wide open HFS.  You can basically start by just drawing a big grid over the land surface, and cutting up "rooms" every 12x12 set of tiles or something.  Basically, everything starts out connected (excepting rivers or cliffs), so it should start out as a big grid with some unconnected grids down in the caverns.  Obviously, you have to make separate rooms when you cannot path from one corner of these starting "rooms" to another, and may have to split things up if there are two different z-levels stacked over one another on the surface somehow or in caverns, but basically, it should look like a grid layed out over a varied set of slopes with some inaccessable tiles here and there because of trees or cavern walls.

Then, the instant you start digging into the earth, you basically start modifying or creating new rooms.  If we go with doors creating their own nodes, and segregating rooms, we might have a situation where there is an entrance way, then the door nodes, then the hallway behind it, with all the little rooms or warehouses sprayed off of it.

If you just go by trying to make up 12x12x12 cubes, and looking for what paths are blocked (while having to make doors and drawbridges and floodgates and the like their own nodes, since they can be locked), then you'd wind up naturally adding bits and pieces into the simple starting map gradually.  (Maybe, you'd need to have some sort of sanity check mop-up, maybe at the new year's, with all those other checks and calculations that make the whole thing take a long time processing, anyway, that another second checking to optimize the connection map wouldn't really be noticed.) 

The map would probably wind up looking similar to Granite26's idea, with most of the inside-the-fort stuff being determined by doors and based upon z-levels, but it would have the capacity to react to having water or multi-z-level rooms (like if we eventually get proper flying unit pathing).

We just need to have a stored connectivity map that works in those area-nodes levels at that point, with an assumption we can A* to anything "local" within those nodes.  Simply having a current location in the same node as a destination inherently implies not only connectivity, but a very short and probably direct pathfinding call.  Then we can throw away the current version of the connectivity map, which makes the hierarchical nodal pathfinding structure capable of competing head-to-head with the current A* connectivity map in terms of memory - only the fact that you will need duplicate layers of connectivity maps for things like "flying only" or "water-based movement possible" or "swim only" really drags it down.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 21, 2011, 09:34:51 pm
Obstensibly, yes.  You'll be starting with a base map that doesn't need to take into account things like workshops, but I'm saying that when a workshop is built, it should do certain things to the node map.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 22, 2011, 08:08:43 am
Do it like this:

Find all walkable tiles, cluster into nodes (we'll treat workshops differently in a moment).
Then find all swim-able tiles, cluster into additional nodes with the "swim only" modifier (tiles that are in both, which I think is 3/7, are their own node).
(Do the same for magma).
Then find all remaining empty tiles, cluster into nodes, with the note "fly only."
Connect all neighboring nodes, the node connections will also carry the walk/fly/swim flags.
Done.

Here's something I've been thinking about, however - if you are drawing a map where you only make local updates, not global ones, odds are, you're going to start with a wide open field and some caverns and a functionally wide open HFS.  You can basically start by just drawing a big grid over the land surface, and cutting up "rooms" every 12x12 set of tiles or something.  Basically, everything starts out connected (excepting rivers or cliffs), so it should start out as a big grid with some unconnected grids down in the caverns.  Obviously, you have to make separate rooms when you cannot path from one corner of these starting "rooms" to another, and may have to split things up if there are two different z-levels stacked over one another on the surface somehow or in caverns, but basically, it should look like a grid layed out over a varied set of slopes with some inaccessable tiles here and there because of trees or cavern walls.

Then, the instant you start digging into the earth, you basically start modifying or creating new rooms.  If we go with doors creating their own nodes, and segregating rooms, we might have a situation where there is an entrance way, then the door nodes, then the hallway behind it, with all the little rooms or warehouses sprayed off of it.

If you just go by trying to make up 12x12x12 cubes, and looking for what paths are blocked (while having to make doors and drawbridges and floodgates and the like their own nodes, since they can be locked), then you'd wind up naturally adding bits and pieces into the simple starting map gradually.  (Maybe, you'd need to have some sort of sanity check mop-up, maybe at the new year's, with all those other checks and calculations that make the whole thing take a long time processing, anyway, that another second checking to optimize the connection map wouldn't really be noticed.) 

The map would probably wind up looking similar to Granite26's idea, with most of the inside-the-fort stuff being determined by doors and based upon z-levels, but it would have the capacity to react to having water or multi-z-level rooms (like if we eventually get proper flying unit pathing).

We just need to have a stored connectivity map that works in those area-nodes levels at that point, with an assumption we can A* to anything "local" within those nodes.  Simply having a current location in the same node as a destination inherently implies not only connectivity, but a very short and probably direct pathfinding call.  Then we can throw away the current version of the connectivity map, which makes the hierarchical nodal pathfinding structure capable of competing head-to-head with the current A* connectivity map in terms of memory - only the fact that you will need duplicate layers of connectivity maps for things like "flying only" or "water-based movement possible" or "swim only" really drags it down.
see my post here http://www.bay12forums.com/smf/index.php?topic=76278.msg2091518#msg2091518.

I would like that everyone stop posting their idea on how to do pathfinding cause THIS is the best method (see navigation mesh).
Instead try to point out:
-what we may have forget to take in consideration (like workshops or the need to represent all the tiles, even the unwalkable)
-how to easily implement one part of this method, or improving the current idea of implementation.(like using 3d shape instead of 2d, using a flag system for easily representing the different types of nodes)
This is only like this we'll have a serious suggestion that Toady may try to read.
I don't have a good english , so I would want that someone who understand the method post a summary each time someone post a potential improvement.

Here is the first summary:
-We represent the map with rectangular cuboid of tile of the same type (walkable/swimable/digable/flyable/magma/workshops)
-the map can now be represented as a graph where a node is a cuboid , and 2 nodes are connected if the cuboids they represent are touching.
-we use A* on this graph, this will give us a "basic" path, we'll know through what cuboid the path come, not what tiles.
-We have to use the funnel algorithm to knowing the exact path (http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html).
-At this point we have a set of points leading to destination , the dwarf only need to go in straight line between each points (There is no internal pathfinding, rectangular cuboid are CONVEX, the shortest path between 2 points is without any calculation the straight line)
-A straight line is defined as going diagonal (starting from starting point) until reaching one of the two coordonates of the destination then going horizontal or vertical.
-Each time a change is done on the map (digging, closing a door, building a wall etc...), we have to (slightly) change our graph.
-A function than can do this only need to be able to:
    -add a node
    -merge 2 nodes (if 2 cuboids have a common side)
    -split a node (when we build a wall for example)
    -changing the type of a node(digable->walkable)

With this method the entire map could be represented whith only few hundreds nodes instead of millions with the current method. And the more important thing, if we only look at the fortress (not the entire map), I think almost all pathfinding occur here, a friendly designed fortress could be represented with a dozen of nodes, and with only a depth of 4 nodes: the surface (surroundings by fortification) , the stairs , the main hall , all the other rooms linked to the main hall.
And finding a path in this type of graph is very fast.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 22, 2011, 11:17:45 am
see my post here http://www.bay12forums.com/smf/index.php?topic=76278.msg2091518#msg2091518.

I would like that everyone stop posting their idea on how to do pathfinding cause THIS is the best method (see navigation mesh).
Instead try to point out:
-what we may have forget to take in consideration (like workshops or the need to represent all the tiles, even the unwalkable)
-how to easily implement one part of this method, or improving the current idea of implementation.(like using 3d shape instead of 2d, using a flag system for easily representing the different types of nodes)
This is only like this we'll have a serious suggestion that Toady may try to read.
I don't have a good english , so I would want that someone who understand the method post a summary each time someone post a potential improvement.

Here is the first summary:
-We represent the map with rectangular cuboid of tile of the same type (walkable/swimable/digable/flyable/magma/workshops)
-the map can now be represented as a graph where a node is a cuboid , and 2 nodes are connected if the cuboids they represent are touching.
-we use A* on this graph, this will give us a "basic" path, we'll know through what cuboid the path come, not what tiles.
-We have to use the funnel algorithm to knowing the exact path (http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html).
-At this point we have a set of points leading to destination , the dwarf only need to go in straight line between each points (There is no internal pathfinding, rectangular cuboid are CONVEX, the shortest path between 2 points is without any calculation the straight line)
-A straight line is defined as going diagonal (starting from starting point) until reaching one of the two coordonates of the destination then going horizontal or vertical.
-Each time a change is done on the map (digging, closing a door, building a wall etc...), we have to (slightly) change our graph.
-A function than can do this only need to be able to:
    -add a node
    -merge 2 nodes (if 2 cuboids have a common side)
    -split a node (when we build a wall for example)
    -changing the type of a node(digable->walkable)

With this method the entire map could be represented whith only few hundreds nodes instead of millions with the current method. And the more important thing, if we only look at the fortress (not the entire map), I think almost all pathfinding occur here, a friendly designed fortress could be represented with a dozen of nodes, and with only a depth of 4 nodes: the surface (surroundings by fortification) , the stairs , the main hall , all the other rooms linked to the main hall.
And finding a path in this type of graph is very fast.

For someone who starts off by saying that he didn't read the thread, you're pretty quick to tell people not to post their thoughts on the subject because your ideas are the best.   ::)  What you've posted is basically a repeat of what others have said, except in a few cases that don't make much sense, like the funnel algorithm.

In case you didn't notice, I've been posting in this thread before, and was only talking about how the way in which this gets put into memory, because simply having fast pathfinding is NOT the only goal here - it also has to conserve memory and respond to dynamic changes extremely well.  What you quoted wasn't a new idea, it was the same idea we've been talking about where I was disucssing how it could best fit those constraints on dynamic map changes.

(And to anyone else, what good ideas are there on ways to make a map react better to something like flooding with water as tiles individually flood or empty of water?  For that matter, how do we handle things like digging or bridging in pathfinding cheaply?)

Anyway, just drawing cubes over the map is problematic as long as it is entirely possible for players to not have any vertical access between most areas of the map (such as the central stairwell method of fortress design).  In order for these nodes to work, you need to have any "local" pathfinding capable of finding the other tiles in the same node without leaving the node.  If you then have something like two or three minor hallways with rooms branched off of them, with no access through rooms to other hallways, you would need to make the one-tile tall functional square nodes smaller and skinnier, still, since you wouldn't be able to path from one hallway to another without first finding the major access hallways in other nodes.

I don't see any benefit to using funnel algorithm, which might make sense in a game with floating point location values, but seems like wasted cycles spent on "path smoothing" in a game that has no need for path smoothing.  DF just needs to move diagonally when it can and horizontally when it can't.  There are no other considerations that need to be taken into account.

The game already prefers diagonals, since they are functionally free (or rather, cost no more than a horizontal move), which means that point on preferring diagonals is pointless.

The changing of the node structure based upon locking doors or digging is exactly what I was talking about finding the best ways to accomidate in that last post.  (You did read it, right?)

You also have to be aware of how the node changes aren't something as simple as "it's water now" - each individual tile will have to become flooded, and the game will likely be checking for which portions of the map are being flooded without a good system for how this will actually be updated.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 22, 2011, 11:51:30 am
Quote
In order for these nodes to work, you need to have any "local" pathfinding capable of finding the other tiles in the same node without leaving the node.

The nodes being defined as a convex volume of space with no obstructions you don't need local pathfinding: it's a strait line.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 22, 2011, 12:47:54 pm
For someone who starts off by saying that he didn't read the thread, you're pretty quick to tell people not to post their thoughts on the subject because your ideas are the best.   ::)  What you've posted is basically a repeat of what others have said, except in a few cases that don't make much sense, like the funnel algorithm.

In case you didn't notice, I've been posting in this thread before, and was only talking about how the way in which this gets put into memory, because simply having fast pathfinding is NOT the only goal here - it also has to conserve memory and respond to dynamic changes extremely well.  What you quoted wasn't a new idea, it was the same idea we've been talking about where I was disucssing how it could best fit those constraints on dynamic map changes.

(And to anyone else, what good ideas are there on ways to make a map react better to something like flooding with water as tiles individually flood or empty of water?  For that matter, how do we handle things like digging or bridging in pathfinding cheaply?)

Anyway, just drawing cubes over the map is problematic as long as it is entirely possible for players to not have any vertical access between most areas of the map (such as the central stairwell method of fortress design).  In order for these nodes to work, you need to have any "local" pathfinding capable of finding the other tiles in the same node without leaving the node.  If you then have something like two or three minor hallways with rooms branched off of them, with no access through rooms to other hallways, you would need to make the one-tile tall functional square nodes smaller and skinnier, still, since you wouldn't be able to path from one hallway to another without first finding the major access hallways in other nodes.

I don't see any benefit to using funnel algorithm, which might make sense in a game with floating point location values, but seems like wasted cycles spent on "path smoothing" in a game that has no need for path smoothing.  DF just needs to move diagonally when it can and horizontally when it can't.  There are no other considerations that need to be taken into account.

The game already prefers diagonals, since they are functionally free (or rather, cost no more than a horizontal move), which means that point on preferring diagonals is pointless.

The changing of the node structure based upon locking doors or digging is exactly what I was talking about finding the best ways to accomidate in that last post.  (You did read it, right?)

You also have to be aware of how the node changes aren't something as simple as "it's water now" - each individual tile will have to become flooded, and the game will likely be checking for which portions of the map are being flooded without a good system for how this will actually be updated.

Ok I read the whole thread , and like I thought it was mainly the same idea as the current pathfinding with some tweaks.
For what I can read of your post you didn't get almost every part of my method.

No there is no problem with fortress without vertical access.
No there is no need of any internal pathfinding , a cube is convex , which mean that for any two points of the cube the straight line conecting this two point is also include in the cube. Just in case a cube can be a 1x1x1 tile, which means this method is in the WORST case localy as fast(slow?) as the current method.
I think you just don't understand the funnel algorithm, it's an algorithm which take a bunch of touching convex polygons (with our start point in the first one and the end point in the last one), and returns you a bunch of straight lines conecting the 2 points, these straight lines ARE the path.
The function that take care of the changing of the map only do local changes not global, so it is very cheap in calculation.
I think the fluid system is as simple as "it's water now" (with an index of 1 to 7), I think the fluid system just need to know what is the "fluid index" of every tiles to work, but I may be wrong on this one.
Ho and the navigation mesh is known to be the (actual) best pathfinding method.

Edit: http://www.ai-blog.net/archives/000152.html here is a nice site explaining and showing some nice example of nav mesh.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 22, 2011, 02:02:45 pm
Ok I read the whole thread , and like I thought it was mainly the same idea as the current pathfinding with some tweaks.
For what I can read of your post you didn't get almost every part of my method.

No there is no problem with fortress without vertical access.
No there is no need of any internal pathfinding , a cube is convex , which mean that for any two points of the cube the straight line conecting this two point is also include in the cube. Just in case a cube can be a 1x1x1 tile, which means this method is in the WORST case localy as fast(slow?) as the current method.
I think you just don't understand the funnel algorithm, it's an algorithm which take a bunch of touching convex polygons (with our start point in the first one and the end point in the last one), and returns you a bunch of straight lines conecting the 2 points, these straight lines ARE the path.
The function that take care of the changing of the map only do local changes not global, so it is very cheap in calculation.
I think the fluid system is as simple as "it's water now" (with an index of 1 to 7), I think the fluid system just need to know what is the "fluid index" of every tiles to work, but I may be wrong on this one.
Ho and the navigation mesh is known to be the (actual) best pathfinding method.

Edit: http://www.ai-blog.net/archives/000152.html here is a nice site explaining and showing some nice example of nav mesh.

And yet, I think the problem is you're still not understanding what we are talking about...

Whether you call it a nav mesh or not, this is still functionally the same thing we have already been talking about, except for the fact that we are dealing with non-floating-point cubic tiles.  You're coming into the thread, saying we should drop everything, and work on "your system", and then describe "your system" as being almost exactly what we were talking about (except that your is based upon floating-point distances), anyway, and then try telling us how much better your system is.

Also, no, it's not as simple as "it's water now".  The entire node doesn't instantly fill with water.  Only individual tiles fill with water, certain levels of water at a time, and do so sequentially - that means that at one point, there will be water in some of the tiles in one node, and not in other tiles in the node, and you are going to have to start splitting that node up and testing to see whether it fits in with other nearby nodes.  There is an interface point (3/7 water) where swimming creatures and walking creatures can both occupy a tile.  That means those tiles are probably going to be in their own individual nodes, and checking to be put in with other nearby nodes rather frequently, as water sloshes around randomly.  In a situation with 3/7 and 4/7 water in a basin, the 4/7 water is going to be cutting off land access every time that 4/7 water depth shifts around, and that means the nodes are going to be cut up and merged very rapidly with one another.  That's a potentially costly set of calculations to make, and something that can be optimized. 



EDIT:
Since I probably need to go into further detail as to why "Funnel" isn't helpful - first off, the mesh system and polygons and linear pathways you are talking about are for floating-point-distance pathing.  This is a grid-based game.  The funnel pathfinding where you calculate how many meshes you can path down in a straight line is unneccessary calculation, since as long as you can assume connectivity without explicit pathfinding, there is no reason to have to worry about pathing around corners, anyway.  There is no need to worry about making the "smooth line" or avoiding "zig-zagging" in the way that pathfinding is taking place already, so spending extra calculations to look ahead several nodes to make a straight line between the nodes is pointless. 

Further, there is a problem you are ignoring when talking about all this - the pathfinding you are linking to assumes large open areas with clusters of obstacles and relatively few moving units.  DF is a game where units cannot move through one another easily - collisions require both units to stop (or in pile-ups, everyone to stop), a unit to try to pathfind a sidestep, or failing that, everyone but one unit has to stop everything to let one unit advance one space. 

Try having dwarves pick up a pile of random objects like stones left over from tunneling when you only have a one-tile-wide hallway for them to access it, and you'll immediately see the problems with the traffic pileups. 

Consider a major pathway where the overall shape of the path units must take is a "U", starting or ending in the northwest and northeast with dwarves needing to go back and forth repeatedly, but needing to travel along a major hallway that connects portions of the fortress from east-to-west.  Every dwarf travelling to and from those points would automatically hug the northern wall of the major hallway - colliding with every single other dwarf who is coming from the direction of their destination.

This was why I was advocating a "Highway" system - it may be slightly less dwarf-walking-distance efficient, but it manages to be much more efficient overall for the problem at hand, because if you assume that dwarves prefer walking along the right-hand path of a hallway, only deviating from that path to "change lanes" by stepping to the left in the highway to pass a slower moving walker, you can assume that in any hallway wider than one tile, you can at least prevent most head-on-collisions until traffic density is such that dwarves are going to be repeatedly attempting "passing" maneuvers.   

This still assumes pathfinding automatically at everything but local "inside the node" start and end points, based purely upon the node's connectivity, but it manages to solve other problems the game needs to solve with pathfinding, as well.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Symmetry on March 22, 2011, 05:17:25 pm
I dunno, a discrete nav mesh approach is quite attractive.  It's just dividing the map into easy to path blocks and pathing between them, which has been suggested a million times.  The "funnel" algorithm would end up utterly trivial when implemented on discrete rectangles, and it nicely handles the odd case people usually struggle to explain when two large zones touch at more than a single tile.

Dodging other walkers becomes easy if we only allow dodging to another square in the same segment.  Yes this means there are times when dodging would help and we can't do it with the solution, but the pure simplicity of it will make it quick and under player control. five wide corridors will work still.

The water problem is large.  I think it is best to use a sticky approach, where water is walkable until it hits 5 deep, then it becomes impassable until it hits 3 deep.  The actual water itself would work as now, but for the purposes of long distance pathfinding we can simplify things a bit perhaps.  It's fairly pointless to plan a detailed path in advance if it goes through these volatile areas anyway.

However there are problems.  The way the zones are created and coalesced has a huge effect on pathfinding.
For example a corridor with cubby holes could be represented (at least) two ways.  Letters represent pathfinding zones:

Code: [Select]
A B C D
XXXXXXXX


Code: [Select]
B D F H
ABCDEFGH

The second case is a bit of a disaster I think?

I apologise if I'm tearing this thread even more off subject, I've not read the whole thing as although I think it's hugely important to the game I really don't think I can solve the problem.  And I get frustrated because I want the source code to generate traffic statistics and try optimisations on it myself :D
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 22, 2011, 05:26:58 pm
Whether you call it a nav mesh or not, this is still functionally the same thing we have already been talking about, except for the fact that we are dealing with non-floating-point cubic tiles.  You're coming into the thread, saying we should drop everything, and work on "your system", and then describe "your system" as being almost exactly what we were talking about (except that your is based upon floating-point distances), anyway, and then try telling us how much better your system is.
there isn't any post (except the one of soralin in an other thread) relating to my method , but I don't care this is not MY method , this is just the most efficient method, I didn't invent it.
I don't know why you are talking about float, I never mention it. we use rectangular cube AxBxC where A,B,C are integers.
Also, no, it's not as simple as "it's water now".  The entire node doesn't instantly fill with water.  Only individual tiles fill with water, certain levels of water at a time, and do so sequentially - that means that at one point, there will be water in some of the tiles in one node, and not in other tiles in the node, and you are going to have to start splitting that node up and testing to see whether it fits in with other nearby nodes.  There is an interface point (3/7 water) where swimming creatures and walking creatures can both occupy a tile.  That means those tiles are probably going to be in their own individual nodes, and checking to be put in with other nearby nodes rather frequently, as water sloshes around randomly.  In a situation with 3/7 and 4/7 water in a basin, the 4/7 water is going to be cutting off land access every time that 4/7 water depth shifts around, and that means the nodes are going to be cut up and merged very rapidly with one another.  That's a potentially costly set of calculations to make, and something that can be optimized. 
You have a point here, even if you still don't understand a node represents a cube of tiles of the SAME type, that means there is only tiles with x/7 water in the same cube, so there is no problem for the walking thing, but it could be a lot of node rebuilding during a flood so maybe it could be improved. Though the complexities of the subroutines that add a node , merge 2 nodes , split one or change the type of a node are constant, so the complexity of the function will be linear to the amount of change (if there is 10 changes to do , it'll take as much time as doing 10 times 1 change), so I don't think it's a big deal.
Since I probably need to go into further detail as to why "Funnel" isn't helpful ...
I think I need an example.
Code: [Select]
##################
#+++++#+X++#+++++#
#+++++#++++#+++++#
#+++++###+##+++++#
#++++++++++++++++#
#######++++#######
#+++++#++++#+++++#
#+++++#++++#+++++#
#++++++++++++++++#
#######++++#######
#+++++#++++#++Y++#
#+++++#++++#+++++#
#++++++++++++++++#
##################
this will be represented by something like that:
Code: [Select]
##################
#22222#1X11#77777#
#22222#1111#77777#
#22222###a##77777#
#22222b6666c77777#
#######6666#######        1
#33333#6666#88888#        |
#33333#6666#88888#    2-b a c-7
#33333g6666d88888#       \|/
#######6666#######    3-g-6-d-8
#44444#6666#55Y55#       / \
#44444#6666#55555#    4-f   e-5
#44444f6666e55555#
##################
where 1,2,3,4,5,6,7,8,a,b,c,d,e,f,g are the nodes of the graph, X and Y the points we try to find a path for. X is in 1 , Y in 5.
the A* will tell us , the path go through 1->a->6->e->5, but this is NOT the path, you have all the necessary information to easily find it , but you don't have it yet , you need the funnel algorithm (which is a very simple algorithm with integers mesh) to find out the exact path:
Code: [Select]
##################
#+++++#+X++#+++++#
#+++++#++++#+++++#
#+++++###A##+++++#
#++++++++++++++++#
#######++++#######
#+++++#++++#+++++#
#+++++#++++#+++++#
#++++++++++++++++#
#######++++#######
#+++++#++++#++Y++#
#+++++#++++#+++++#
#+++++++++BC+++++#
##################
Wich means go in straight line from X to A , then go in straight line from A to B , then go in straight line from B to C , then go in straight line from C to Y. You cant skip this step, knowing by wich cube you have to go through is not enough. This algorithm is extremly fast , and the A* has been through only 4-5 nodes instead of about 50 with the current method. I hope I've been clear and my post is understandable.

EDIT:
However there are problems.  The way the zones are created and coalesced has a huge effect on pathfinding.
For example a corridor with cubby holes could be represented (at least) two ways.  Letters represent pathfinding zones:

Code: [Select]
A B C D
XXXXXXXX


Code: [Select]
B D F H
ABCDEFGH

The second case is a bit of a disaster I think?
yes you are right, there is multiple possibilities to represent the same zone, and some are more optimized than other, I can't see right now a way to find out how to represent it optimaly, maybe if someone have an idea. But even a non optimized representation is at least as fast as considering each tile as a node, so it's totally worth it.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 22, 2011, 05:32:39 pm
As for water: it's easy.  Any tile with water in it is its own node.  You don't merge it with adjacent nodes until one of two conditions is reached:

1) Tile contains no water
2) Tile is marked as non-flowing

As for corridor division:
It's long been a problem of nav-mesh generation,* however, given the rules we've decided upon for nodes being added to a corridor, it wouldn't occur often.**
The only thing we need to do it insure that it NEVER happens under our current rules set is to say that when a tile is merged and there are two or more existing nodes it could be merged with, always choose the larger one.

*If you've ever messed with the Source engine (TF2, L4D, HL2 mapping) you'll know about Hint brushes.  They act as designer-defined boundaries of the visibility leaves (visibility in the Source engine is almost exactly the method we're discussing here: convex volumes).  They're created by carving out geometry from an initial cube, and the "carve" function isn't very smart.  However, since we're working with discrete tiles and doing a split/merge on a per-tile basis, we don't need "hint brushes."

**You'd have to intentionally try and break it, as if you dig the corridor first, then the niches, you'll get the first solution.  You'd have to dig 1 tile of corridor, then the nitch, then the neighboring tile and even then it'd depend on how the engine decided to do the merge.  With my above rule, provided that our corridor is 2 tiles deep (as far as node-size is concerned) before digging a nitch, the nitch will never create a node that breaks the hallway into multiple nodes.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Symmetry on March 22, 2011, 05:54:13 pm
yes you are right, there is multiple possibilities to represent the same zone, and some are more optimized than other, I can't see right now a way to find out how to represent it optimaly, maybe if someone have an idea. But even a non optimized representation is at least as fast as considering each tile as a node, so it's totally worth it.

I don't think it will be, at least not quite.  When you know the size of every node and you know where the neighbours are, and you know each node has the same number of neighbours, it's much easier to write a decent data structure.  Or just use the main map one which I believe is what DF does.  When nodes have properties like width and height and depth, and can have many more neighbours, the algorithm will be less efficient.  Maybe we still win, maybe not.  Depends on implementation and memory efficiency etc.

That said a hardcoded shortcut data structure / code path for dealing with doorways would probably make up the difference.

I see what you mean about the way the nodes grow draco18s.  I also think our coalesce algorithm will need to be capable of cascading coalesce operations, splitting neighbours in order to create large blocks.  Think of the permutations possible at a T junction.

But anyway, I guess you're both right.  The improvement (assuming a decent implementation) will be so big these become interesting questions rather than problems.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 22, 2011, 06:05:28 pm
I don't care this is not MY method , this is just the most efficient method, I didn't invent it.
I don't know why you are talking about float, I never mention it. we use rectangular cube AxBxC where A,B,C are integers.

It's the method you were arguing we should follow and stop making suggestions for other methods.  It's your argument, your method.

And I'm talking about floating point values of positions because all those references and suggestions you are making are designed upon floating point distance and positioning.  You seemingly aren't taking the time to recognize the differences this causes.

I think I need an example.

this will be represented by something like that:
Code: [Select]
##################
#22222#1X11#77777#
#22222#1111#77777#
#22222###a##77777#
#22222b6666c77777#
#######6666#######        1
#33333#6666#88888#        |
#33333#6666#88888#    2-b a c-7
#33333g6666d88888#       \|/
#######6666#######    3-g-6-d-8
#44444#6666#55Y55#       / \
#44444#6666#55555#    4-f   e-5
#44444f6666e55555#
##################
where 1,2,3,4,5,6,7,8,a,b,c,d,e,f,g are the nodes of the graph, X and Y the points we try to find a path for. X is in 1 , Y in 5.
the A* will tell us , the path go through 1->a->6->e->5, but this is NOT the path, you have all the necessary information to easily find it , but you don't have it yet , you need the funnel algorithm (which is a very simple algorithm with integers mesh) to find out the exact path:
Code: [Select]
##################
#+++++#+X++#+++++#
#+++++#++++#+++++#
#+++++###A##+++++#
#++++++++++++++++#
#######++++#######
#+++++#++++#+++++#
#+++++#++++#+++++#
#++++++++++++++++#
#######++++#######
#+++++#++++#++Y++#
#+++++#++++#+++++#
#+++++++++BC+++++#
##################
Wich means go in straight line from X to A , then go in straight line from A to B , then go in straight line from B to C , then go in straight line from C to Y. You cant skip this step, knowing by wich cube you have to go through is not enough. This algorithm is extremly fast , and the A* has been through only 4-5 nodes instead of about 50 with the current method. I hope I've been clear and my post is understandable.

Again, the problem I'm saying you seem to be having is that you're drawing distinctions between what I am talking about and what you are talking about that don't really exist.  The difference between the sort of hierarchical node system and a nav mesh is largely nominal.  It doesn't matter whether you call something a "node" or a "convex rectangular cuboid", so long as the code functions basically the same.

What I was talking about with a "highway" system would do exactly the same slicing of the map up into the same nodes, and follow basically the same path.  The only real difference would be that the dwarf would hug the wall when walking through 6 until it came time to start moving diagonally to hit the door.

As for water: it's easy.  Any tile with water in it is its own node.  You don't merge it with adjacent nodes until one of two conditions is reached:

1) Tile contains no water
2) Tile is marked as non-flowing

Hmm... I guess this works, although it would require an odd exception system.  As far as memory serves, water tends to basically never stop flowing, though.  If there is any unevenness in the water amounts, it will pretty much be "flowing" forever.

Dodging other walkers becomes easy if we only allow dodging to another square in the same segment.  Yes this means there are times when dodging would help and we can't do it with the solution, but the pure simplicity of it will make it quick and under player control. five wide corridors will work still.

Dodging is a problem we should try to avoid having to do in the first place, however.  People already want "one-way road" designations because of how often dodging has to take place, and how much it muddles general traffic.  A hug-the-right-wall approach solves most traffic jams innately. 

However there are problems.  The way the zones are created and coalesced has a huge effect on pathfinding.
For example a corridor with cubby holes could be represented (at least) two ways.  Letters represent pathfinding zones:

Code: [Select]
A B C D
XXXXXXXX


Code: [Select]
B D F H
ABCDEFGH

The second case is a bit of a disaster I think?

I apologise if I'm tearing this thread even more off subject, I've not read the whole thing as although I think it's hugely important to the game I really don't think I can solve the problem.  And I get frustrated because I want the source code to generate traffic statistics and try optimisations on it myself :D

This isn't a derail at all, it's exactly the sort of problem we need to be able to solve well.

A zone with a "ribbed" hallway like the one you were describing there should really be considered a single node, though.  Realistically, if you are pathing through it, you just want to follow the XXXX path unless you have a destination that is in one of those alcoves.  Nodes don't necessarily need to be rectanges every time - a "circular" node will make sense in the case of something like the image I can quickly just steal a link to from the Ironhand graphics set preview (http://www.bay12forums.com/smf/index.php?topic=53180.0).
Spoiler (click to show/hide)

The only thing that is important is that the assumptions we are going to make of the nodes will still hold true - the ability to make direct paths through them from one end to another with a single given movement type.  This is why saving the data structure as a "highway" where you record both length and width of the structure abstractly can help - you can make the highway go around a corner if you do it right, although this would probably quickly break the line of direct pathing. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 22, 2011, 06:45:08 pm
**You'd have to intentionally try and break it, as if you dig the corridor first, then the niches, you'll get the first solution.  You'd have to dig 1 tile of corridor, then the nitch, then the neighboring tile and even then it'd depend on how the engine decided to do the merge.  With my above rule, provided that our corridor is 2 tiles deep (as far as node-size is concerned) before digging a nitch, the nitch will never create a node that breaks the hallway into multiple nodes.

The one way I could easily see the 'breaking' occur is as follows:
Code: [Select]

[Dug]    [Meshed]

Start with a zig-zag

#######  #######
#.#.#.#  #b#d#f#
.#.#.#.  a#c#e#g
#######  #######

Then straighten the zig-zag

#######  #######
#.#.#.#  #b#d#f#
.......  abcdefg
#######  #######

Of course, starting from the zig-zag, digging the first 'straight' connector, e.g. the lower 'b', would have a choice between merging the "a?c" into a single zone, leaving the alcove 'b' to one side or the worst-case result of making the new cell part of the 'b'-zone.

That's codeable for.  But what if it wasn't just alcoves, but a "comb".  e.g. this was a proto-bedroom corridor, featuring (future) 1x3 bedrooms.


Code: [Select]

You may want to save a little bit on digging by only half-cutting the corridor

#######  #######
#.#.#.#  #b#d#f#
#.#.#.#  #b#d#f#
#.#.#.#  #b#d#f#
.#.#.#.  a#c#e#g
#######  #######

Now the choice is between


#######     #######
#b#d#f#     #b#d#f#
#b#d#f# and #b#d#f#
#b#d#f#     #b#d#f#
abc#e#g     aaa#e#g
#######     #######


So, is 1x4 (b) plus two 1x1s (a,c) actually still less sensible than the two 1x3s that are 'a' (was "a?c") and the original 'b'?

Maybe, but what if 'b' is ten long?  Twenty?

Ultimately, once the 'd' and 'f' non-niche bits are cut, maybe the algorithm recognises the value of a continuous 1x7 'a' (was "a?c?e?g") with branches of whatever length of, rather than branch+1 lengths and the individual and isolated 1x1s.

And using rectilinear shapes also means inefficiencies in other quarters.  What is more efficient?

Code: [Select]
aa#####
aa#####
##b####
###c###
####d##
#####ee
#####ee

aa#####
aa#####
##b####
###b### 
####b##
#####ee
#####ee

bc#####
ab#####
##b#### 
###b###
####b##
#####be
#####db



Example one is based upon squares (or cubes, but of Z=1 size) and how it would turn out.

Example two has a 'b' is a perfectly valid convex shape, which would be more efficient, but is not rectilinear.

Example three looks bad, but it's possible that (depending on what the original 'a' and 'e' rooms expand out into) could be more efficient, e.g.

Code: [Select]

######
###a##
##aa##  Not possible (although all intra-'a' travel
#aaa##    is still straight-line possible, even with
####b#    that chunk taken out, so still convex)
#####?

######
###d##
##aa##  One of the easy-splitting ways
#caa##   (c.f. also the 1x1, 1x2 and 1x3 split)
####b#
#####?

######
###c##
##bc##  Arguably more efficient,
#aab##   although really depends on what use
####b#   is made of the space.
#####?

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 22, 2011, 06:50:51 pm
Again, the problem I'm saying you seem to be having is that you're drawing distinctions between what I am talking about and what you are talking about that don't really exist.  The difference between the sort of hierarchical node system and a nav mesh is largely nominal.  It doesn't matter whether you call something a "node" or a "convex rectangular cuboid", so long as the code functions basically the same.

What I was talking about with a "highway" system would do exactly the same slicing of the map up into the same nodes, and follow basically the same path.  The only real difference would be that the dwarf would hug the wall when walking through 6 until it came time to start moving diagonally to hit the door.
well then sorry I may have misunderstood what your highway system is, and I'll reread your posts. (things like using limited 12x12x12 nodes, and "internal pathfinding" in your previous post may have induce me in error)


Nodes don't necessarily need to be rectanges every time - a "circular" node will make sense
Yeah, in theory any convex shape should do the job. (but may be difficult to represent)
I think a straight line should be defined as going diagonal then horizontal or vertical OR going first horizontal or vertical then going diagonal.
If we use only one of those definition we have a problem , the straight line [A:B] isnt the same as [B:A], which pose some problem with the convexity. with this definition the corridor problem is solved
Code: [Select]
A B C D
XXXXXXXX

Code: [Select]
B D F H
BBBBBBBB
Yes , the B shape IS convex with the definition of straight line I gave.
but a new problem come with this corridor...
Code: [Select]
A B C D
 A B C D
XXXXXXXX

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 22, 2011, 06:52:51 pm
Which basically leads us back to:

Finding the most optimal system space-filling convex solid is not an easy problem (is it NP-complete?) and you go with the fastest method that is "good enough."

Most people won't be digging zig-zag hallways, and even in the case that they do, the sub-optimal node-graph isn't significantly detrimental to A*.  The worst case scenario is still better than what we're using now.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 22, 2011, 08:31:08 pm
Let me see...

The other conditions we should try to satisfy are

Pathing vehicles is probably going to require the ability to occupy multiple nodes at once, which is tricky to code, to start with, but could be made simpler if we put the complexity on how the nodes are formed - with a recognition of how wide the pathways they will allow through them are. 

Arbitrary size vehicles, especially, can cut out many of the shortcuts that Toady was probably using on wagons (like simply making another connectivity grid, and making each obstacle count as an obstacle for the tile adjacent to itself, as well, and pathing only the center tile of the wagon through the map).

Pathing for diggers is one of those nightmare situations I'm reluctant to even start wrapping my head around.  I remember Draco doing a nice graph once, though, with pits for bridgers to put up to two bridges out as an example.  Digging is even worse, though, since there are so many more situations where just knocking down a wall can create hundreds of new potential pathways you'd have to start evaluating and eliminating.  It also basically pulls the bottom out of nodal pathways, and almost makes it easier to just use A* with a modified heuristic based upon the nodal system if you can simply punch through all the obstacles with a minor delay.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 23, 2011, 02:00:50 am

this will be represented by something like that:
Code: [Select]
##################
#22222#1X11#77777#
#22222#1111#77777#
#22222###a##77777#
#22222b6666c77777#
#######6666#######        1
#33333#6666#88888#        |
#33333#6666#88888#    2-b a c-7
#33333g6666d88888#       \|/
#######6666#######    3-g-6-d-8
#44444#6666#55Y55#       / \
#44444#6666#55555#    4-f   e-5
#44444f6666e55555#
##################
ng each tile as a node, so it's totally worth it.
The main problem  is how to come  up with that node graph ;) .

You can see your simple maze in my silly program  (http://niseg.0adz.com/test_maze.html?maze=0420042007600000FC3F042004200000FC3F042004200000FFFFFFFFFFFFFFFF)

The output of aimless bfs from top left corner looks like this:
(http://img828.imageshack.us/img828/7888/examplemaze.png)
The numbers are real distances and the colors signify number of children of a node in this complex  graph (100~nodes potential). (red 0 orange 1 yellow 2 green 3+) The computer can't really see it but we can tell that there are rooms all it sees are the numbers(distance from start) and colors(number of children) or other things that describe the graph.

You need to tell it how to convert numbers and "colors"(aka other numbers) into groups and form those groups into a reduced graph. As I mentioned before BFS might not be the right algorithm to generate those "numbers and colors".

Now after you make some rules you need to tell it how to decide between a minor and major change. If for example a tree grows in those rooms some most of them would not change the general structure of the room unless it blocks the path to it.  Also deforming the rooms by digging  does not really change the general structure of the reduced graph unless it creates a new path to a node.

Representing rooms may not be a big problem because  you can generally put corners of a polygon into the data type. We can also save entry points to in the edges  to make pathing easier .

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 23, 2011, 08:00:25 am

this will be represented by something like that:
Code: [Select]
##################
#22222#1X11#77777#
#22222#1111#77777#
#22222###a##77777#
#22222b6666c77777#
#######6666#######        1
#33333#6666#88888#        |
#33333#6666#88888#    2-b a c-7
#33333g6666d88888#       \|/
#######6666#######    3-g-6-d-8
#44444#6666#55Y55#       / \
#44444#6666#55555#    4-f   e-5
#44444f6666e55555#
##################
The main problem  is how to come  up with that node graph ;) .
Once we have the map sliced in rectangles, obtain the graph is trivial, slicing the map in rectangle is also trivial BUT slicing it optimaly is a much more difficult problem.
The first question to ask is what is an optimal representation? I think it's a representation where the "depth" of the graph (the maximal distance (in nodes) between 2 nodes) is minimal

Code: [Select]
  B D F H          A-B-C-D-E-F-G-H   is the graph representing it , the depth is 8
 ABCDEFGH
Code: [Select]
A B C D                               
EEEEEEEEEEE                           
                                              C
                                              |
                                            A-E-B   is the graph , the depth is 3
                                              |
                                              D
So the 2nd representaion is better because the depth of the graph is smaller than the first one.
I think I may have an idea , let's take my previous example
Code: [Select]
##################
#+++++#+X++#+++++#
#+++++#++++#+++++#
#+++++###+##+++++#
#++++++++++++++++#
#######++++#######
#+++++#++++#+++++#
#+++++#++++#+++++#
#++++++++++++++++#
#######++++#######
#+++++#++++#++Y++#
#+++++#++++#+++++#
#++++++++++++++++#
##################
My idea consist to take all "maximal" rectangles, here are all of them

Code: [Select]
##################   ##################   ##################
#AAAAA#GGGG#CCCCC#   #+++++#++L+#+++++#   #+++++#++++#+++++#
#AAAAA#GGGG#CCCCC#   #+++++#++L+#+++++#   #+++++#++++#+++++#
#AAAAA###+##CCCCC#   #+++++###L##+++++#   #+++++###+##+++++#
#AAAAA+FFFF+CCCCC#   #++++++++L+++++++#   #IIIIIIIIIIIIIIII#
#######FFFF#######   #######++L+#######   #######++++#######
#BBBBB#FFFF#DDDDD#   #+++++#++L+#+++++#   #+++++#++++#+++++#
#BBBBB#FFFF#DDDDD#   #+++++#++L+#+++++#   #+++++#++++#+++++#
#BBBBB+FFFF+DDDDD#   #++++++++L+++++++#   #JJJJJJJJJJJJJJJJ#
#######FFFF#######   #######++L+#######   #######++++#######
#HHHHH#FFFF#EEEEE#   #+++++#++L+#+++++#   #+++++#++++#+++++#
#HHHHH#FFFF#EEEEE#   #+++++#++L+#+++++#   #+++++#++++#+++++#
#HHHHH+FFFF+EEEEE#   #++++++++L+++++++#   #KKKKKKKKKKKKKKKK#
##################   ##################   ##################


My idea is to make a graph using this rectangles (yes they are not disjoint), a node is still a rectangle , and 2 nodes are connected if the 2 rectangles are touching (or overlaping)
so we should have this graph : (http://img824.imageshack.us/img824/6198/graphi.jpg) (http://img824.imageshack.us/i/graphi.jpg/)

then the A* should give us G->L->K->E. Using a classic Funnel algorithm, we should end up with a path, but not the shortest (we don't pass through F).
But I'm sure by doing just a little trick we should end up with the shortest path. What do you think of this?

Edit :
the algorithm finding the "maximal" rectangles is very simple:
0)- just take a random tile
1)- make the maximal rectangle starting with this tile
2)- save this rectangle
3)- look at all the tiles in this area that are touching a tile that is not in the area, take one of this tile
4)- make a new maximal rectangle starting from this tile
5)- repeat to 2) until the area cover the entire map.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 23, 2011, 09:01:27 am
the algorithm finding the "maximal" rectangles is very simple:
0)- just take a random tile
[...]
3)- look at all the tiles in this area that are touching a tile that is not in the area, take one of this tile
[...]

I'm not saying this is 'wrong', but I'm wary of aiming for optimality by starting off with a random tile, and continuing with random tiles.

Of all the possible starting/next tiles, there may be one that is the absolute worst-case (creating a very sub-optimal 'optimal' division and/ or leading down the route where the most work is put into the map compared with the savings it ends up giving).

Obviously, the alternative of trying each and every possible start tile, and each and every possible continuation tile for any given start tile and continuation tile, brings us back to the original issue of path-finding, more or less, which can be done in breadth-first, depth-first or some more clue-guided manner.

Of course, given the fact that the idea (at least at first) is that the node-structure is a "build-once, revamp the occassional segment as changes require" thing, it's perhaps not too much of a problem[1] when compared with the existing pathing system, but I'm not yet able to prove (or even strongly suggest) to my own satisfaction that there won't be a horrible car-crash of a situation where it could go horribly wrong.

Just my thoughts, not really an objection, as much as something to be aware of.

And, no, I don't have a (foolproof, and yet not resource intensive) method in mind that doesn't rely on randomness or some form of systemic bias in initiating and perpetuating the zone analysis process.  Brute forcing the entire map from every single starting point with every single possible neighbouring region would be 'ideal'[3].  But hardly easy on the processor.


(Indeed, I know what you're thinking: sometimes "perfection is the enemy of the good-enough".  But that's the way I tend to think.)


[1] Unless you're finding that certain circumstances[2] where the ad-hoc zone-merging leads onto something awkward.

[2] Off the top of my head, a generally 'l'-shaped room (i.e. square area with a significant corner untapped) that was first dug out with pillars left all across the floor, and depending on the order the pillars are removed, the zone-merging algorithm may end up giving you a different end-result zonings, some of which are going to better (for the immediate vicinity, or for connecting to neighbouring zones) than others.  However, even in this example it is right that a less-optimal solution of zones that cover many tiles still offer an advantage over search systems that are nothing more than tile-per-node types.

[3] Even then, I could foresee a situation where a more parallel-seeking solution could come up with a better overall map than any point-outwards one you might care to mention.  The best point (or group of points) to start to optimise one sub-region would mean sub-optimality on another region, and starting somewhere that would help with the latter makes the former 'wrong'.  Starting anywhere not within either region's "happy zone" means both are sub-optimal.  But, on the other hand, while starting multiple spots, like growing crystal grains, could allow such critical areas to be optimised and then simply connected, the converging zones would necessarily subject their rapidly narrowing no-man's land between them to the pinch of zone-acquisition leaving who-knows-what pathing detritus between them.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 23, 2011, 09:36:09 am

Once we have the map sliced in rectangles, obtain the graph is trivial, slicing the map in rectangle is also trivial BUT slicing it optimaly is a much more difficult problem.
The first question to ask is what is an optimal representation? I think it's a representation where the "depth" of the graph (the maximal distance (in nodes) between 2 nodes) is minimal

I spiced up your map for you  by adding some "trees "(link  (http://niseg.0adz.com/test_maze.html?maze=44A2142847620208FC3F4CA024204040FD3F04A824220808FFFFFFFFFFFFFFFF))

Code: [Select]
_0123456789abcdef
0##################
1#+#+++#++#+#+++#+#
2#+++#+#++++#+#+++#
3#+#+++###+##+++#+#
4#++++++#+++++#+++#
5#######++++#######
6#+#++##++#+#+++++#
7#++#++#++++#+++++#
8#+#+++++++#++++++#
9#######+#++#######
a#+++++#++#+#+#+++#
b#++#++#++++#+++#+#
c#++++#+++++++#+++#
d##################

You might find it  a tad harder to slice it up but it should result in the same tree.  I did notice that BFS is usually give Red corners (childless ) and when entering a room you get greens/yellows which means lots of connections.  I can probably scan for reds and backtrack to greens or follow reds to find corners .

My current BFS is not optimal . I'm planning a full code rewrite adding custom classes  which would allow more features and adding   multiple searches algorithm support .  I did a damage calculator for a game in JS it's not the best but it's fairly functional ( it parses the game files directly so updating it is really easy) . 



Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 23, 2011, 09:48:54 am
the algorithm finding the "maximal" rectangles is very simple:
0)- just take a random tile
[...]
3)- look at all the tiles in this area that are touching a tile that is not in the area, take one of this tile
[...]

I'm not saying this is 'wrong', but I'm wary of aiming for optimality by starting off with a random tile, and continuing with random tiles.

Of all the possible starting/next tiles, there may be one that is the absolute worst-case (creating a very sub-optimal 'optimal' division and/ or leading down the route where the most work is put into the map compared with the savings it ends up giving).
Every step of this algorithm find a new maximal rectangle (The decomposition in maximal rectangle is unique) , so the starting tile doesn't matter, and I may be wrong but I think this algorithm is optimal. Here is an example step by step, the "X" are the choices we look at for the next step (the tiles in the area which are in contact with at least one tile wich is not in the area), the blank represent the area we've already cover. the A,B,C... are the maximal rectangles.

Code: [Select]
##################   ##################   ##################
#+++++#++++#+++++#   #+++++#++++#+++++#   #+++++#++++#+++++#
#+++++#++++#+++++#   #+++++#++++#+++++#   #+++++#++++#+++++#
#+++++###+##+++++#   #+++++###+##+++++#   #+++++###+##+++++# 
#++++++++++++++++#   #++++++++++++++++#   #++++++++++++++++#
#######++++#######   #######++++#######   #######++++#######
#+++++#++++#+X+++#   #+++++#++++#AAAAA#   #+++++#++++#     # we choose randomly a X , there is only one.
#+++++#++++#+++++#   #+++++#++++#AAAAA#   #+++++#++++#     #
#++++++++++++++++#   #+++++++++++AAAAA#   #+++++++++++X    #
#######++++#######   #######++++#######   #######++++#######
#+++++#++++#+++++#   #+++++#++++#+++++#   #+++++#++++#+++++#
#+++++#++++#+++++#   #+++++#++++#+++++#   #+++++#++++#+++++#
#++++++++++++++++#   #++++++++++++++++#   #++++++++++++++++#
##################   ##################   ##################

Code: [Select]

##################   ##################   ##################
#+++++#++++#+++++#   #+++++#++++#+++++#   #+++++#++++#+++++#
#+++++#++++#+++++#   #+++++#++++#+++++#   #+++++#++++#+++++#
#+++++###+##+++++#   #+++++###+##+++++#   #+++++###+##+++++#
#++++++++++++++++#   #++++++++++++++++#   #++++++++++++++++#
#######++++#######   #######++++#######   #######++++####### we choose randomly a X , and call it Y
#+++++#++++#     #   #+++++#++++#     #   #+++++#++++#+++++#
#+++++#++++#     #   #+++++#++++#     #   #+++++#++++#+++++#
#BBBBBBBBBBBBBBBB#   #XXXXX XXXX      #   #XXXXX XXYX      #
#######++++#######   #######++++#######   #######++++#######
#+++++#++++#+++++#   #+++++#++++#+++++#   #+++++#++++#+++++#   
#+++++#++++#+++++#   #+++++#++++#+++++#   #+++++#++++#+++++#   
#++++++++++++++++#   #++++++++++++++++#   #++++++++++++++++#   
##################   ##################   ################## 
 

Code: [Select]

##################   ##################
#+++++#++++#+++++#   #+++++#++++#+++++#
#+++++#++++#+++++#   #+++++#++++#+++++#
#+++++###+##+++++#   #+++++###+##+++++#
#++++++CCCC++++++#   #++++++X XX++++++#
#######CCCC#######   #######    #######
#+++++#CCCC#     #   #+++++#    #     # we make the maximal rectangle from the previous Y, and starting again choosing randomly a X.
#+++++#CCCC#     #   #+++++#    #     #
#XXXXX CCCC      #   #XXXXX           #
#######CCCC#######   #######    ####### 
#+++++#CCCC#+++++#   #+++++#    #+++++#   
#+++++#CCCC#+++++#   #+++++#    #+++++#   
#++++++CCCC++++++#   #++++++Y  X++++++#   
##################   ################## 

Code: [Select]

##################   ##################
#+++++#++++#+++++#   #+++++#++++#+++++#
#+++++#++++#+++++#   #+++++#++++#+++++#
#+++++###+##+++++#   #+++++###+##+++++#
#++++++X XX++++++#   #++++++X YX++++++#
#######    #######   #######    #######
#+++++#    #     #   #+++++#    #     #
#+++++#    #     #   #+++++#    #     #
#XXXXX           #   #XXXXX           #
#######    #######   #######    ####### 
#+++++#    #+++++#   #+++++#    #+++++#   
#+++++#    #+++++#   #+++++#    #+++++#   
#DDDDDDDDDDDDDDDD#   #XXXXX      XXXXX#   
##################   ################## 

Code: [Select]

##################   ##################
#+++++#++E+#+++++#   #+++++#++X+#+++++#
#+++++#++E+#+++++#   #+++++#++X+#+++++#
#+++++###E##+++++#   #+++++### ##+++++#
#++++++X EX++++++#   #++++++X  X++++++#
#######  E #######   #######    #######
#+++++#  E #     #   #+++++#    #     #
#+++++#  E #     #   #+++++#    #     #
#XXXXX   E       #   #XYXXX           #
#######  E #######   #######    ####### 
#+++++#  E #+++++#   #+++++#    #+++++#   
#+++++#  E #+++++#   #+++++#    #+++++#   
#XXXXX   E  XXXXX#   #XXXXX      XXXXX#   
##################   ################## 

Code: [Select]

##################   ##################
#+++++#++X+#+++++#   #+++++#++X+#+++++#
#+++++#++X+#+++++#   #+++++#++X+#+++++#
#+++++### ##+++++#   #+++++### ##+++++#
#++++++X  X++++++#   #++++++Y  X++++++#
#######    #######   #######    #######
#FFFFF#    #     #   #     #    #     #
#FFFFF#    #     #   #     #    #     #
#FFFFF           #   #                #
#######    #######   #######    ####### 
#+++++#    #+++++#   #+++++#    #+++++#   
#+++++#    #+++++#   #+++++#    #+++++#   
#XXXXX      XXXXX#   #XXXXX      XXXXX#   
##################   ##################

Code: [Select]

##################   ##################
#+++++#++X+#+++++#   #+++++#++X+#+++++#
#+++++#++X+#+++++#   #+++++#++Y+#+++++#
#+++++### ##+++++#   #+++++### ##+++++#
#GGGGGGGGGGGGGGGG#   #XXXXX      XXXXX#
#######    #######   #######    #######
#     #    #     #   #     #    #     #
#     #    #     #   #     #    #     #
#                #   #                #
#######    #######   #######    ####### 
#+++++#    #+++++#   #+++++#    #+++++#   
#+++++#    #+++++#   #+++++#    #+++++#   
#XXXXX      XXXXX#   #XXXXX      XXXXX#   
##################   ##################

Code: [Select]

##################   ##################
#+++++#HHHH#+++++#   #+++++#    #+++++#
#+++++#HHHH#+++++#   #+++++#    #+++++#
#+++++### ##+++++#   #+++++### ##+++++#
#XXXXX      XXXXX#   #XXXXX      XYXXX#
#######    #######   #######    #######
#     #    #     #   #     #    #     #
#     #    #     #   #     #    #     #
#                #   #                #
#######    #######   #######    ####### 
#+++++#    #+++++#   #+++++#    #+++++#   
#+++++#    #+++++#   #+++++#    #+++++#   
#XXXXX      XXXXX#   #XXXXX      XXXXX#   
##################   ##################

Code: [Select]

##################   ##################
#+++++#    #IIIII#   #+++++#    #     #
#+++++#    #IIIII#   #+++++#    #     #
#+++++### ##IIIII#   #+++++### ##     #
#XXXXX      IIIII#   #XXXXX           #
#######    #######   #######    #######
#     #    #     #   #     #    #     #   the last steps are trivial
#     #    #     #   #     #    #     #
#                #   #                #
#######    #######   #######    ####### 
#+++++#    #+++++#   #+++++#    #+++++#   
#+++++#    #+++++#   #+++++#    #+++++#   
#XXXXX      XXXXX#   #XXXXX      XXXXX#   
##################   ##################
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 23, 2011, 09:52:18 am
Two things:

1) Please describe the Xs better.  I had to read it four times and look at the image to figure out WTF it meant.
2) Why are you making maximum rectangles that overlap?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 23, 2011, 10:01:19 am
Well, at a certain point, we are optimizing for several different priorities at once - we need to optimize the amount of time it takes to build the graph, optimize the time it takes to use the graph, optimize the memory usage of the graph, and optimize the functionality of the graph.

At some point, we can generally just say "screw it", and go with a sub-optimal graph that takes more time to path through than a purely optimal graph, just because we wanted to make the graph itself faster, and just took a reasonable guess.

I also think that having some sort of end-of-the-season stop-and-sweep-up-any-mess-in-the-graph phase to make sure that we can try to put together some optimal paths might be a nice way of getting some balance in the performance, so that long-unchanged paths can be assured of optimization would be a decent way to make sure some heavily used paths are optimized without having to jump through a more complex optimization process very frequently.



Something I'm not entirely sure we should overlook too soon, however, is ways to make some of these node non-rectangular.  It might mean having to save some extra data into memory to ensure best paths or else involve some fairly quick A* work inside the node, but let me give an example...

Someone wants to build a really fancy hallway leading up to the dining room, with plenty of statues to impress visitors of the greatness of dwarven society...

(tricky) Case A:
Code: [Select]
##################
Ω.Ω.Ω.Ω.Ω.Ω.Ω.Ω.Ω#
.................+
Ω...Ω...Ω...Ω...Ω#
.................+
Ω.Ω.Ω.Ω.Ω.Ω.Ω.Ω.Ω#
##################

(sadistic) Case B:
Code: [Select]
##################
Ω.Ω.Ω...Ω...Ω.Ω.Ω#
......Ω...Ω......+
Ω...Ω...Ω...Ω...Ω#
......Ω...Ω......+
Ω.Ω.Ω...Ω...Ω.Ω.Ω#
##################

Now, in the case A, you can do a psuedo-optimization by just drawing some nodes horizontally, one tile wide, directly past the doors.  You wouldn't be able to make it a wide hallway, but you could make the game recognize some hallways, at least.  I'm not sure how well traffic dodging will work in this situation, however. 

This requires a case of the game being able to actually make an optimal decision on how to cut up these nodes, however, in order to get optimal results.

The case B, however, will inherently screw any attempt at making an orderly straight line through the hallway over.  You're going to have to make the pathfinding program find a way to dodge occasional obstacles in otherwise straight hallways. 

Now, what I'm wondering if we could try to do is make slightly more permissive definitions of nodes than just drawing rectangles, and then going ahead and either recording an optimal path through the hallway (costs memory), or else just letting a "local A*" type of pathfinding take place (costs more processor power at the time pathfinding takes place), but at the same time, making a much simpler node graph (saving some memory and time spent searching paths through the nodes), but also taking some more complex node-generation techniques (taking more processor time when building the graph itself). 

Hallway case A, for example, could have one node taking up all three middle rows of tiles (not including the alcoves), and record that there are some obstacles in some of those middle tiles, and the whole hallway would just be a single node, and dwarves could path up and down diagonally through that hallway if they so chose, weaving in and out of those statues if there was an obstruction like a traffic congestion down by one of the statues, and they had to go around to save time.

Hallway case A might even fill to include the whole darn hallway, alcoves and all, and just have plenty of obstructions out along the sides as well as in the middle to avoid.   

Either way, you could have some sort of very basic A* pathfinding that would work very, very well, or else have a pre-saved optimal path from one exit of the hallway to another that ties up memory.

Hallway case B might have the entire hallway stored as a single node, once again, with an optimal path to and from exits based upon the sort of highway system, to avoid traffic collisions:

("<" means the "going left" path and ">" means the "going right" path)

Code: [Select]
##################
Ω.Ω.Ω.<<Ω.<<Ω.Ω.Ω#
<<<<<<Ω.<<Ω.<<<<<+
Ω...Ω...Ω...Ω...Ω#
>>>>>.Ω>>.Ω>>>>>>+
Ω.Ω.Ω>>.Ω>>.Ω.Ω.Ω#
##################
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 23, 2011, 10:13:37 am
Two things:

1) Please describe the Xs better.  I had to read it four times and look at the image to figure out WTF it meant.
2) Why are you making maximum rectangles that overlap?

I've edited my previous post with showing what X I choose each step (I call it Y).
I use these rectangles to be sure to not have a "bad" graph like:
Code: [Select]
AAB
DCB
DEE
It is a possible repesentation of a rectangle that could be trivially represented as one node.
The "depth" of the graph using maximal rectangle is minimal (but there are more connections between nodes), so it's a sure way (the representation is unique) to have a quite optimised representation..
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 23, 2011, 10:57:53 am
As far as I've read and noticed A* is a variation of BFS (Breadth First search)  where you prioritize the order in which you go through nodes by using the heuristic function.  here is one of the worst cases:
Code: [Select]
##################
#s+++++++#d++++++#
#+##############+#
#++++++++#+#+#+#+#
#+########+#+#+#+#
#++++++++#+#+#+#+#
#+########+#+#+#+#
#++++++++#+#+#+#+#
#+########+#+#+#+#
#++++++++#+#+#+#+#
#+########+#+#+#+#
#++++++++++++++++#
#++++++++++++++++#
##################

as the A * trys to take the shortest path it would check endless dead-ends.
dividing it up into rooms :
Code: [Select]
##################
#sSSSSSSS#dDDDDDD#
#A##############J#
#AAAAAAAA#G#H#I#J#
#B########G#H#I#J#
#BBBBBBBB#G#H#I#J#
#C########G#H#I#J#
#CCCCCCCC#G#H#I#J#
#E########G#H#I#J#
#EEEEEEEE#G#H#I#J#
#E########G#H#I#J#
#FFFFFFFFFFFFFFFF#
#FFFFFFFFFFFFFFFF#
##################

  G H I
         \|/
S-A-B-C-E-F-J-D

As you can see it turns The pathing algorithm to simple  path length 8 and then the sub-pathes between the nodes become a simple short paths which run in best case times .

So if you are asking if it's worth the trouble - it does . The advantages are huge compared to pure A*.  While A* is a global algorithm (runs on the whole map) the node is a local algorithm which runs on a local area. Just think about 10X10 embarks with no performance degradation.

Giving fliers the option of vector Pathing through the air would also do a lot of good . Even though A* is optimal in air it's usually not necessary in air traversal which can use a vector (rise over run - like drawing lines ;) )  which is more or less O(1).  If it hit the wall it would switch to A* and try to find it's "way in".
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 23, 2011, 12:03:06 pm
As far as I've read and noticed A* is a variation of BFS (Breadth First search)  where you prioritize the order in which you go through nodes by using the heuristic function.  here is one of the worst cases:
Code: [Select]
##################
#sSSSSSSS#dDDDDDD#
#A##############J#
#AAAAAAAA#G#H#I#J#
#B########G#H#I#J#
#BBBBBBBB#G#H#I#J#
#C########G#H#I#J#
#CCCCCCCC#G#H#I#J#
#E########G#H#I#J#
#EEEEEEEE#G#H#I#J#
#E########G#H#I#J#
#FFFFFFFFFFFFFFFF#
#FFFFFFFFFFFFFFFF#
##################

As you can see it turns The pathing algorithm to simple  path length 8 and then the sub-pathes between the nodes become a simple short paths which run in best case times .

So if you are asking if it's worth the trouble - it does . The advantages are huge compared to pure A*.  While A* is a global algorithm (runs on the whole map) the node is a local algorithm which runs on a local area. Just think about 10X10 embarks with no performance degradation.

Giving fliers the option of vector Pathing through the air would also do a lot of good . Even though A* is optimal in air it's usually not necessary in air traversal which can use a vector (rise over run - like drawing lines ;) )  which is more or less O(1).  If it hit the wall it would switch to A* and try to find it's "way in".
Do you have a method to be sure your map will be sliced like this and not like that:
Code: [Select]
##################
#sSSSSSSS#dDDDDDD#
#Q##############J#
#AAAAAAAA#G#H#I#J#
#K########G#H#I#J#
#BBBBBBBB#G#H#I#J#
#L########G#H#I#J#
#CCCCCCCC#G#H#I#J#
#M########G#H#I#J#
#EEEEEEEE#G#H#I#J#
#N########G#H#I#J#
#FFFFFFFFFFFHOIPJ#
#FFFFFFFFFFFHOIPJ#
##################
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 23, 2011, 12:06:24 pm
Mohican:
While sub-optimal, it's still fewer nodes (in the end that are saved) than the original A* path.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on March 23, 2011, 12:47:32 pm
Mohican:
While sub-optimal, it's still fewer nodes (in the end that are saved) than the original A* path.
it's true, in the end it'll still be better. But we should start expliciting all the algorithms if we want that Toady give a look.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 23, 2011, 02:16:23 pm
Um, guys?... Any response on this?

Something I'm not entirely sure we should overlook too soon, however, is ways to make some of these node non-rectangular.  It might mean having to save some extra data into memory to ensure best paths or else involve some fairly quick A* work inside the node, but let me give an example...

Someone wants to build a really fancy hallway leading up to the dining room, with plenty of statues to impress visitors of the greatness of dwarven society...

(tricky) Case A:
Code: [Select]
##################
Ω.Ω.Ω.Ω.Ω.Ω.Ω.Ω.Ω#
.................+
Ω...Ω...Ω...Ω...Ω#
.................+
Ω.Ω.Ω.Ω.Ω.Ω.Ω.Ω.Ω#
##################

(sadistic) Case B:
Code: [Select]
##################
Ω.Ω.Ω...Ω...Ω.Ω.Ω#
......Ω...Ω......+
Ω...Ω...Ω...Ω...Ω#
......Ω...Ω......+
Ω.Ω.Ω...Ω...Ω.Ω.Ω#
##################

Now, in the case A, you can do a psuedo-optimization by just drawing some nodes horizontally, one tile wide, directly past the doors.  You wouldn't be able to make it a wide hallway, but you could make the game recognize some hallways, at least.  I'm not sure how well traffic dodging will work in this situation, however. 

This requires a case of the game being able to actually make an optimal decision on how to cut up these nodes, however, in order to get optimal results.

The case B, however, will inherently screw any attempt at making an orderly straight line through the hallway over.  You're going to have to make the pathfinding program find a way to dodge occasional obstacles in otherwise straight hallways. 

Now, what I'm wondering if we could try to do is make slightly more permissive definitions of nodes than just drawing rectangles, and then going ahead and either recording an optimal path through the hallway (costs memory), or else just letting a "local A*" type of pathfinding take place (costs more processor power at the time pathfinding takes place), but at the same time, making a much simpler node graph (saving some memory and time spent searching paths through the nodes), but also taking some more complex node-generation techniques (taking more processor time when building the graph itself). 

Hallway case A, for example, could have one node taking up all three middle rows of tiles (not including the alcoves), and record that there are some obstacles in some of those middle tiles, and the whole hallway would just be a single node, and dwarves could path up and down diagonally through that hallway if they so chose, weaving in and out of those statues if there was an obstruction like a traffic congestion down by one of the statues, and they had to go around to save time.

Hallway case A might even fill to include the whole darn hallway, alcoves and all, and just have plenty of obstructions out along the sides as well as in the middle to avoid.   

Either way, you could have some sort of very basic A* pathfinding that would work very, very well, or else have a pre-saved optimal path from one exit of the hallway to another that ties up memory.

Hallway case B might have the entire hallway stored as a single node, once again, with an optimal path to and from exits based upon the sort of highway system, to avoid traffic collisions:

("<" means the "going left" path and ">" means the "going right" path)

Code: [Select]
##################
Ω.Ω.Ω.<<Ω.<<Ω.Ω.Ω#
<<<<<<Ω.<<Ω.<<<<<+
Ω...Ω...Ω...Ω...Ω#
>>>>>.Ω>>.Ω>>>>>>+
Ω.Ω.Ω>>.Ω>>.Ω.Ω.Ω#
##################
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: kaenneth on March 23, 2011, 11:23:07 pm
Um, guys?... Any response on this?
Spoiler (click to show/hide)

retangular section could also have a 'density' attribute, for example, if the number of path blocking objects is less than the square root of the area/shortest edge

valid:

Code: [Select]
..........
.......Ω..
....Ω.Ω...
.....Ω....
..Ω..Ω....
..........
....Ω.....
..........
...Ω..Ω...
..........

invalid:
Code: [Select]
..Ω.......
..Ω.......
..Ω.......
..Ω.......
..Ω.......
..Ω.......
..Ω.......
..Ω.......
..Ω.......
..Ω.......

One idea that's been stirring in my mind is to use fixed size range 'blob' fills (I just made that up, if it has some other specific meaning, or if there is already a name for this, I dunno) to define areas, that is, you pick a point, and flow out from it by picking the nearest open unclaimed open space until you've filled up to your target blob size; then spawn new blobs from the edges. If a blob falls under half the target size, it merges with it's smallest neighbor blob, if it goes over double the target size, it splits by cutting out a new blob being formed from the edge furthest from the center of mass. And blobs would not be restricted to one z-level.

So, starting with this map...

Code: [Select]

############
#..#.#.#.#.#
#..........#
#.##########
#..........#
##########.#
#..........#
##########.#
#..........#
##########.#
#..........#
############

a blob size of 8 leads to:

Code: [Select]
############
#aa#a#b#b#d#
#aaaabbbbbb#
#a##########
#ccccccccee#
##########e#
#fffffffeee#
##########e#
#igggggggge#
##########h#
#jjjhhhhhhh#
############

merging the undersized blobs (d, i, j) to their larger neighbors:

Code: [Select]
############
#aa#a#b#b#b#
#aaaabbbbbb#
#a##########
#ccccccccee#
##########e#
#fffffffeee#
##########e#
#ggggggggge#
##########h#
#hhhhhhhhhh#
############

So the connections are a-b, a-c, c-e, e-f, e-g, e-h;

I think this method would make it very easy to not only fit to irregular areas, but also adapt to local changes; a newly dug square would just get appended to the smallest neighboring blob without cascading to resectioning the entire map.

I'm going to code a version of this in a DF-like model world to validate it can always reach a stable state quickly; and that effects can't cascade more than a couple blobs. it's possible a split could orphan multiple sections section that get re-merged, triggering a re-split... it might do to just place a limit on the depth of recursion allowed in rebalancing, if a blob is a couple tiles over the alleged 'limit', it's not a big problem.

Variable blob sizes might be an interesting DF specific optimization as well; say make an tile with a built object count double for the size; and doors quardruple, so that a row of furnished bedrooms would create clusters of small blobs, while outdoor areas and empty halls would allow larger ones.

I also need to think about how to store these blobs in memory efficently... that'll probably be the problem with this approach.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Artanis00 on March 24, 2011, 01:22:14 am
Um, guys?... Any response on this?
Spoiler (click to show/hide)

I don't think anyone really gets your 'highway' concept (though I do think it would be useful). How exactly is the computer supposed to figure out where those traffic patterns go, anyway?

Regarding those hell maps, they are still better than unaided A*. The worst case scenario for the convex polygon method is still half as intensive as unaided A* (it does gain that at the cost of greater memory overhead), and looks like this:
Code: [Select]
##################
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
##################

For comparison, worst-case for unaided A* is a wide, contiguous up/down stair column, so YMMV.

Also, I have a diagonal version of the notched corridor that I'm puzzling over. Ideal packing is one large node in the bottom corner, and successively smaller nodes adjacent to it, with 1x1 nodes only between larger nodes (think Sierpinski triangle). I don't know how to get that, though. On the other hand, I don't think ideal packing is ideal for pathing (at least via the funnel algorithm), so it may not matter.
Code: [Select]
##################
################.#
###############..#
##############...#
#############....#
############.....#
###########......#
##########.......#
#########........#
########.........#
#######..........#
######...........#
#####............#
####.............#
###..............#
##...............#
##################

And kaenneth, try to keep convex nodes, otherwise intra-node navigation needs A* to work.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 24, 2011, 09:24:52 am
If we're doing convex polygons, then your diagonal hallway there IS a convex polygon, therefore can be one node.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 24, 2011, 12:22:42 pm
If we're doing convex polygons, then your diagonal hallway there IS a convex polygon, therefore can be one node.
Some forms of this discussion have been dealing with convex (i.e. all of them) rectangles, though.  Easier to work out (the simple way is, from a spot, expand N-S and E-W by varying amounts until you have the largest area you like the look of, either by total area or sum of each axis length), easier to define (TLx,TLy,BRx,BRy), easier to check to see whether a random tile is within its bounds or not ( <= compare with previously stated limits), etc.

Of course, convex polygons give a more possible optimisations.  Although this is also their problem, as you have to consider the issue with the modified Manhattan approach to distance[1] that means that these optimisations are more complicated to find, and at the same time harder to dispel in favour of a more optimal optimisations...  Which is where my own vain pursuit of algorithmic perfection is probably holding me back.  (If I dare kid myself that I have a hope in hell of attaining such an ideal!)

And the code for "Are we inside this polygon" is less simple, you have to check dot product calculations between the line defined by each adjacent pair of corner-nodes (in a consistent direction around that polygon) and the point being tested, to find that this point is on the "inside" of every single one of these.  Unless there's something more efficient that I'm not aware of.  (The main alternative is sub-dividing the convex area into a set of rectangles and triangles, and do the standard in-a-rectangle test on all orthogonal boundaries, and a vastly simplied "above/below, and left/right" test on the diagonals if it lies within an angled corner.)

You also have to ensure that your 'straight line' algorithm between two node points (for one polygon, heading in one direction, for an adjacent-fitting polygon, heading the other direction) does not either mutually bypass a tile, or mutually claim one.  Unless you're using a system in which your polygons are meant to share border tiles (for path calculation purposes, along all routeing border areas) in which case both must agree on which those bi-zone (multi-zone, at a polygon corner intersection) border tiles are.

Complexities that might make for a ☼Masterwork☼ end result, but possibly at the expense of the xTatteredx nerves of a programmer, if not setting his eyeballs !!Aflame!! during the debugging and testing process.



[1]
Code: [Select]
#######
##1..2#
##....#
#....##
##...##
##..###
##..###
##3####
#######
Even that single open space to the left is 'within' the triangle defined by the points 1, 2 and 3, and the RHS could easily be either straight down from 3, before exact diagonal to 3, or diagonally in before straight down, at the extreme limits of possibilities for that line.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 24, 2011, 01:14:39 pm
Or you could limit it to only 45 degree angle lines.  That would get you some non-grid convex shapes without having to go into complex math.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 24, 2011, 02:59:20 pm
I don't think anyone really gets your 'highway' concept (though I do think it would be useful). How exactly is the computer supposed to figure out where those traffic patterns go, anyway?

The game has to store a "path width" (which would be necessary for vehicles, anyway) for the nodes, and prefer to travel down the far right side.  If you have a three-tile-wide rectangular hallway, the dwarves would prefer to stay on the right hand side of that hallway, given their current direction of movement, hence making opposing traffic stay on either side of the hallway, the way that cars stay on the right (or left in certain countries) when driving down a road to prevent traffic collisions. 

Putting a traffic jam-solving method into the pathfinding would be a relatively minor burden on pathfinding time, provided it is set up correctly, and would give a performance boost in actual navigation when dwarves stop bumping into one another all the time, and having to pathfind around one another.

For comparison, worst-case for unaided A* is a wide, contiguous up/down stair column, so YMMV.

Isn't a giant field of up/down stairs the best case for A*?  You'd have a direct line of sight to wherever your destination is, meaning just picking the first tile that the heuristic will lead you to choose will always be the best choice, meaning you'd never have to do a double-back.

Technically, A*'s worst case is pathing to a completely blocked path or the like, where it functionally flood-fills, aborts, and tries again next frame, but the sort of thing that others were posting a couple posts ago is the next-worst, I.E. this:

Code: [Select]
##################
#s+++++++#d++++++#
#+##############+#
#++++++++#+#+#+#+#
#+########+#+#+#+#
#++++++++#+#+#+#+#
#+########+#+#+#+#
#++++++++#+#+#+#+#
#+########+#+#+#+#
#++++++++#+#+#+#+#
#+########+#+#+#+#
#++++++++++++++++#
#++++++++++++++++#
##################

This is the worst case because every time, the heuristic will trick the program into trying to go down each and every one of those dead-ends, thinking that it is a possible path to the exit.

Regarding those hell maps, they are still better than unaided A*. The worst case scenario for the convex polygon method is still half as intensive as unaided A* (it does gain that at the cost of greater memory overhead), and looks like this:
Code: [Select]
##################
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
#.#.#.#.#.#.#.#.##
##.#.#.#.#.#.#.#.#
##################



Also, I have a diagonal version of the notched corridor that I'm puzzling over. Ideal packing is one large node in the bottom corner, and successively smaller nodes adjacent to it, with 1x1 nodes only between larger nodes (think Sierpinski triangle). I don't know how to get that, though. On the other hand, I don't think ideal packing is ideal for pathing (at least via the funnel algorithm), so it may not matter.
Code: [Select]
##################
################.#
###############..#
##############...#
#############....#
############.....#
###########......#
##########.......#
#########........#
########.........#
#######..........#
######...........#
#####............#
####.............#
###..............#
##...............#
##################

And kaenneth, try to keep convex nodes, otherwise intra-node navigation needs A* to work.

Now, a giant triangle is the exact sort of convex node shape that works very well for this sort of thing.

The thing I'm asking is, is it really worth it to remove A* if we build node maps that are horribly complex because we're all using rectangles

Yes, A* uses up cycle time, but if we make a map that has 80,000 nodes in it because we have so many one-tile nodes, you're probably going to need to use A* or something to even navigate the node map in the first place, completely nullifying the point of the whole operation.

Rather, if we are going to have hierarchical node structures, we need to make the hierarchical nodes fast to search paths through, as well, and that means that it can be worth some inefficiencies in building the nodes in the first place to be able to make less 1-tile-nodes or fractured nodes like having the entire triangular room split into horizontal rectangles, where every step is pathing into the next node, anyway.

Now, for the statue hallway, ignore the fact that they are statues for a moment, in fact, ignore the alcoves, as well.

Let's just imagine a big square room with one tile of natural wall in the middle. 

Should we divide this room up into four separate nodes?  Or should it just be one big node where we give the dwarves the ability to path around the obstacle if they happen to go towards it?

Again, the problem with A* is not finding its way through mostly open areas, it's preventing A* from going down dead ends.  If you just find the dead ends and mark them off, A* works perfectly well.  That's all the hierarchical/nodal structure needs to do - zoom out to an abstract model, and find the zones that are the "leaf nodes" that are dead ends, the "branch nodes" that provide access to some local areas, and the "trunk nodes" that are the main throughfares that serve as the access points to all the other portions of the fortress. 

Now, the complexity of the system that divides up the rooms is a major sticking point - it needs to be fast enough that the computer doesn't spend more time dicking around looking for a "perfect" set of nodes than it does pathfinding in the first place, and it also needs to conserve on memory as much as it can, but these are all tradeoffs that should be balanced, rather than going for maximizing any one to the exclusion of all others. 

Or you could limit it to only 45 degree angle lines.  That would get you some non-grid convex shapes without having to go into complex math.

This is probably the simplest, fastest method of merging larger nodes.  Just make sure that there is a pathway to and from any given point in a grid using no more than a single "turn" of 45 or maybe 90 degrees.  Yeah, it means something like A* would have to be used, but as long as you have a very simple pathway from one end of a node to the other, that will never be much of a problem.

Of course, there's also a way to try and make the sort of stored pathways of a certain width, which may help with making that "highway" method of trafficking.  That means purposefully storing the width of specific nodes that you expect to get high traffic.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Symmetry on March 24, 2011, 03:55:45 pm
I don't think anyone really gets your 'highway' concept (though I do think it would be useful). How exactly is the computer supposed to figure out where those traffic patterns go, anyway?

The game has to store a "path width" (which would be necessary for vehicles, anyway) for the nodes, and prefer to travel down the far right side.  If you have a three-tile-wide rectangular hallway, the dwarves would prefer to stay on the right hand side of that hallway, given their current direction of movement, hence making opposing traffic stay on either side of the hallway, the way that cars stay on the right (or left in certain countries) when driving down a road to prevent traffic collisions. 

I'm not convinced.  How does it know the difference between a corridor and a dinning room?  If you want to move north s few squares in a room and you're on the wrong side do you run to the other side first?  It seems more like this is overcomplicating the path finding algorithm for a feature that should be handled at a higher level.

Also as a player this would drive me mad unless I have control over it.  With normal zones (whether rectangular, convex, or otherwise) we can allow the player to paint one way signs and attach the zone to the node graph with acyclic links.  I think this would be a better solution, if we do need one.

Also, using convex zones solves the path width problem quite nicely too.

Quote
Yes, A* uses up cycle time, but if we make a map that has 80,000 nodes in it because we have so many one-tile nodes, you're probably going to need to use A* or something to even navigate the node map in the first place, completely nullifying the point of the whole operation.

Yes we'll be using A* to path between nodes.  I think convex nodes will be a huge improvement and well worth it even though there will be quite a few of them, but this is the point where we need code to show what kind of difference it makes in practice.  Opinion and debate won't settle this.

Having said this, even if we allow arbitrary nodes then rectangular nodes can still exist as a special case (because they're so fast) so using them as a starting point seems fair.

Quote
Should we divide this room up into four separate nodes?  Or should it just be one big node where we give the dwarves the ability to path around the obstacle if they happen to go towards it?

Either is so much better than m*n nodes we have now that I'll take the one that's quickest to code.  And having intranode pathfinding be straight lines is a huge benefit.  Any long corridors, or open space, is pathed across instantly.  You don't even need to look.

Quote
Again, the problem with A* is not finding its way through mostly open areas, it's preventing A* from going down dead ends.  If you just find the dead ends and mark them off, A* works perfectly well.  That's all the hierarchical/nodal structure needs to do - zoom out to an abstract model, and find the zones that are the "leaf nodes" that are dead ends, the "branch nodes" that provide access to some local areas, and the "trunk nodes" that are the main throughfares that serve as the access points to all the other portions of the fortress. 

We can just add another level of heirarchy?  Using the simplest possible representation at the lowest level and having multiple self-similar levels of abstraction on top is usually a pretty good algorithm.

Quote
Now, the complexity of the system that divides up the rooms is a major sticking point - it needs to be fast enough that the computer doesn't spend more time dicking around looking for a "perfect" set of nodes than it does pathfinding in the first place, and it also needs to conserve on memory as much as it can, but these are all tradeoffs that should be balanced, rather than going for maximizing any one to the exclusion of all others. 

And simple enough to code it quickly with no bugs.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 24, 2011, 05:41:36 pm
I don't think anyone really gets your 'highway' concept (though I do think it would be useful). How exactly is the computer supposed to figure out where those traffic patterns go, anyway?

The game has to store a "path width" (which would be necessary for vehicles, anyway) for the nodes, and prefer to travel down the far right side.  If you have a three-tile-wide rectangular hallway, the dwarves would prefer to stay on the right hand side of that hallway, given their current direction of movement, hence making opposing traffic stay on either side of the hallway, the way that cars stay on the right (or left in certain countries) when driving down a road to prevent traffic collisions. 

I'm not convinced.  How does it know the difference between a corridor and a dinning room?  If you want to move north s few squares in a room and you're on the wrong side do you run to the other side first?  It seems more like this is overcomplicating the path finding algorithm for a feature that should be handled at a higher level.

No, he doesn't run to the other side.  The direction of "flow" is dependant on connections to other nodes.  If a dwarf enters a node on the west and is headed towards a node on the east, he'll dodge south to avoid obstacles, etc.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 24, 2011, 07:28:30 pm
I'm not convinced.  How does it know the difference between a corridor and a dinning room?  If you want to move north s few squares in a room and you're on the wrong side do you run to the other side first?  It seems more like this is overcomplicating the path finding algorithm for a feature that should be handled at a higher level.

Also as a player this would drive me mad unless I have control over it.  With normal zones (whether rectangular, convex, or otherwise) we can allow the player to paint one way signs and attach the zone to the node graph with acyclic links.  I think this would be a better solution, if we do need one.

Also, using convex zones solves the path width problem quite nicely too.

Well, Draco already said the most relevant point, but...

Figuring out "what are the hallways" should be a major point of a heirarchical node structure in the first place.  If the nodal structure is going to be useful, it has to use something that takes the place of A* on the second-tier to find the most efficient path through the nodes.  After all, esepcially if we are going to have situations where a map has some absurdly high number of very small, almost one-tile nodes, then pathing through the second-tier abstract node map breadth-first could wind up costing more processor power than A* itself. 

How we go about doing this is up for debate, but the thing about A* is that you can always tell if you are moving "closer" or "further away" from your destination when you are moving, thanks to the heuristic.  In an abstract node map, it's much more difficult to make that sort of heuristic take the guesswork out of whether you are moving closer to the target or not without actually looking at all of the nodes - which again, is a major problem when you have potentially thousands of nodes.

Some sort of method of getting the pathfinding function to make a guess as to which nodes are more likely to lead to a destination, and which nodes are more likely not to is an important part of this, and the fastest, simplest way of doing that is to start by marking certain nodes as leaf nodes that have only one connection or are otherwise a "dead end" (maybe it has two connections, but is functionally a dead end, anyway, like the sides of the all-diagonal rooms Artanis00 posted, although this is part of the reason why we need a larger set of nodes to prevent those sorts of situations). 

From here, it's probably best to start thinking about this like IP routing.

The branch nodes then need to start ordering themselves until you can make certain high-traffic areas the "main hallway" or "hub" nodes (like a vertical staircase node in a central staircase style fortress), which can remember which branches spin off of them, and which leaves spin off of those. 

Potentially, we can have some sort of "memory" of successful paths through a given node - if a node is pathed through, and the pathfinder successfully finds a link to the destination, then it gets a point towards prioritizing searching down that node before other nearby nodes are searched, wheras nodes that are searched that don't provide useful paths lose prioritization points, making them the last nodes to be searched.  Nodes that get enough ponits become the candidates for becoming the "trunk" nodes.

Quote
Again, the problem with A* is not finding its way through mostly open areas, it's preventing A* from going down dead ends.  If you just find the dead ends and mark them off, A* works perfectly well.  That's all the hierarchical/nodal structure needs to do - zoom out to an abstract model, and find the zones that are the "leaf nodes" that are dead ends, the "branch nodes" that provide access to some local areas, and the "trunk nodes" that are the main throughfares that serve as the access points to all the other portions of the fortress. 

We can just add another level of heirarchy?  Using the simplest possible representation at the lowest level and having multiple self-similar levels of abstraction on top is usually a pretty good algorithm.

Adding another level of hierarchy just kicks the can down the road - now this level of hierarchy needs a way to organize itself, and now you're working on an abstractly shaped node chart, so you can't use many of those tricks that work with A* or the like.  How do you pathfind through the abstract nodes without having some sort of pathfinding code to make a guess as to which nodes to try to path through?  In an abstract path, it's even harder to get a good heuristic to even tell you if you are going the right way without checking everything. 

The only way to get a good level of hierarchy in that sense that I can think of immediately is to do the IP lookup sort of pathfinding, which requires a large table of every node that the trunk nodes can path to stored in the node itself to tell the pathfinding code how many layers of hierarchy it needs to go up the chain.  That can be potentially expensive, memory-wise, if there are enough nodes to search.

And simple enough to code it quickly with no bugs.

There is no such thing as code that you can make quickly without bugs.

The target should be something robust enough that it never needs to be heavily reworked again later, which will save much more work in the long run than constantly having to update it and tweak it.  Taking the time to do it right the first time is MUCH, MUCH easier than debugging it or having to revise it later.  (Although we are unfortunately already talking about revising the pathfinding code...)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 24, 2011, 08:10:22 pm
Quote
There is no such thing as code that you can make quickly without bugs.

If you can do that, you can have MY job.
And I'm already called a genius by my coworkers.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 24, 2011, 08:17:37 pm
[...]the thing about A* is that you can always tell if you are moving "closer" or "further away" from your destination when you are moving, thanks to the heuristic.  In an abstract node map, it's much more difficult to make that sort of heuristic take the guesswork out of whether you are moving closer to the target or not without actually looking at all of the nodes - which again, is a major problem when you have potentially thousands of nodes.

I know I'm not really addressing this issue head-on, and this method includes an overhead which makes the smallest-extending nodes far less efficient (but should be ok for the largest ones, at least), but if the centre-spot[1] coordinates are recorded for each node then it gives a basis towards a "that adjacent node looks closer than this other adjacent node, and this other one looks to be a back-tracking one (but we may still have to come back to it later)" analysis along the lines of the standard A* tile-by-tile heuristic.


(From a personal POV, I'm most concerned about the node-weightings situation.  A zone with five different entrances to it may be made into a node in a search-map net, but has to remember up to 10 different 'costs' in order to convey to the route-finding algorithm how much effort it takes to get so-many X, so-many Y and so-many Z[2] nearer the target.  And that's with single-width entrances.  I'm still hung-up on a series of multi-width connections between a string of zones, where twists and turns dictate that there are better and worse paths across a zone purely due to where the zones on either side have their entrances and exits to the zones once-more-removed, or even beyond.  Sorry, please ignore this complication in my own fiddling with my own code, which isn't exactly keeping pace or mirroring the heading of everything else being discussed here, so this whole issue is probably not worth talking about.)



[1] Need not involve integer values, for X, Y or Z...  and could be mid-way between the respective limits or a true average of all contained co-ordinates.

[2] Any or all of which may be zero or even negative values.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 24, 2011, 09:32:47 pm
I know I'm not really addressing this issue head-on, and this method includes an overhead which makes the smallest-extending nodes far less efficient (but should be ok for the largest ones, at least), but if the centre-spot[1] coordinates are recorded for each node then it gives a basis towards a "that adjacent node looks closer than this other adjacent node, and this other one looks to be a back-tracking one (but we may still have to come back to it later)" analysis along the lines of the standard A* tile-by-tile heuristic.

(From a personal POV, I'm most concerned about the node-weightings situation.  A zone with five different entrances to it may be made into a node in a search-map net, but has to remember up to 10 different 'costs' in order to convey to the route-finding algorithm how much effort it takes to get so-many X, so-many Y and so-many Z[2] nearer the target.  And that's with single-width entrances.  I'm still hung-up on a series of multi-width connections between a string of zones, where twists and turns dictate that there are better and worse paths across a zone purely due to where the zones on either side have their entrances and exits to the zones once-more-removed, or even beyond.  Sorry, please ignore this complication in my own fiddling with my own code, which isn't exactly keeping pace or mirroring the heading of everything else being discussed here, so this whole issue is probably not worth talking about.)



[1] Need not involve integer values, for X, Y or Z...  and could be mid-way between the respective limits or a true average of all contained co-ordinates.

[2] Any or all of which may be zero or even negative values.

You can do that, but the thing is, we generally want to try to at least keep in mind which nodes are the dead end nodes.  Otherwise, all we're accomplishing is making A* occasionally check multiple tiles at a time in the pathfinding, and potentially adding a lot of overhead in calculation the heuristic in with that. 

I'm not sure I understand your last two sentences in your second paragraph, though.

... The best way I can think of to make this sort of search would be to try to work it somewhat like a search tree - arrange all the nodes in a totally abstract search tree format, and have the individual branches and leaves record the path down the tree to get to where they are.  When a pathfind is called, you compare the number of nodes those have in common.

For example, if we have a tree that has 10 levels of complexity, and the starting point and the destination have 8 levels of complexity in common, then you know that you only have to go "up" 2 levels from the starting point, then can start searching "down" 2 levels to find the destination point.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 24, 2011, 10:40:55 pm
You can do that, but the thing is, we generally want to try to at least keep in mind which nodes are the dead end nodes.[...]
I know, I was just addressing the "A* has an idea of what may be closer" idea.  Which wasn't quite what you were talking about, as I tried to acknowledge.

Quote
I'm not sure I understand your last two sentences in your second paragraph, though.
Well, the very last sentence was telling you to ignore the ramblings from the previous four sentences in that para.

If you're talking about the bit about having "hang-ups with a series of multi-width connections between a string of zones", then imagine something like the following:
Code: [Select]
#######     #######
#+++++#     #+++++#
#+++++#     #+++++#
#++A++#     #++B++#
#+++++#     #+++++#
#+++++#    2#+++++#
##+++#########+++##
#+++++#1+++2#+++++#
#+++++++++++++++++#
#++C+++++++++++D++#
#+++++++++++++++++#
#+++++#3+++4#+++++#
##+++#########+++##
#+++++#     #+++++#
#+++++#     #+++++#
#++E++#     #++F++#
#+++++#     #+++++#
#+++++#     #+++++#
#######     #######
Assuming that A..G represents zone names for shapes that inhabit something roughly equivalent to the whole 5x5 room they're ensconced in (and the 1x3 gaps joining them are either part of convex shapes A..G or their own individual but un-named connecting rectangles... or possibly shared-tiles belonging to both zones as part of the connectivity matrix), and that travel from X->Y means anywhere-in-X-zone to anwhere-in-Y-zone...  (By convention, letters from the top-end of the alphabet will be arbitrary designations.  There's already no particularly logical order of letters even in the bottom-end set, which will latter extend to encompass A..J anyway, but they at least relate to the features you can see or imagine being added on.)

A->E would go via C and would depend largely on where-in-A and where-in-E as to how it might have to cross C.  Ditto for B->F via D.  But C and D would have something like an "it takes five steps to cross" (by one measure of counting it, could also be six) as information associated with these nodes, when discussing A->E and B->F transits.

A->B and E->F travel would most naturally travel by 'hugging' the bends, i.e. the walls W&E of 1&2 or 3&4 respectively, as they travel through G (although a limited diagonal travel would be possible between those points for traffic purposes).  C and D would have a minimum of 1 tile stepped onto during this.  (More could be stepped on for an optimal path, depending on where the but to simplify things I'm going to assume that the the start/destination zones will absorb any extra lateral movement for this quick example.)  So C can report to a path-searching algorithm that it's willing to demand just one step, except when letting traffic transit from A->E in which case it needs to request that five steps be accounted for in any journey through it.

A->F and E->B travel would normally take a diagonal that nonetheless hugged the 1&4 walls or 3&2 walls in some way, although if starting from (say) the BL corner of zone A the movement could be diagonally through the gap and C until next to gap-wall @3, straight (or zig-zaggy!) across to hug 4 before moving diagonally into F (or even up to B if it was certain A->B attempts!).  But, again, C and D could be said to have 1 tile's-worth of stepping into in the calculations, the same as already described.

Even if you have some sort of rule (keep left/right rule, or "diagonals try to keep to the best antialiased valued tiles"), C->D travel will progress across G very variably, according to where in C and where in D are the start/destination points, but for all of these trips discussed so far (except the ones that don't pass through G at all) give G step-value of 5 (just like C,D did for those vertical-only zone transits).

But complicate things further by having a sub-critical amount of pillars in each zone (allowing them to stay "convex" for all meaningful journeys, but introducing any number of necessary side-steps at no nominal extra cost), changing the size and shape of the rooms (length-wise, changes the cost, width-wise not at all) and the offsets of the various gaps leading between the room-zones and the connected room-zones (forcing certain diagonals, perhaps, as long as this and the pillars don't change the zone's essentially convex nature, so no cost-change there), plus perhaps add in an alternate route (H,I,J) at the bottom end to tempt certain E->F end-point travel through I (by way of H and J) instead of G (by way of C and D), according to those various matters and if you've got your system of nodes that says "it takes N steps to cross X, if going from Y to Z" in the simple example, it now matters much more where in Y you start/Z you end up, or indeed if Y and Z end-points are technically just floating and V and W (the true route end-points) play a part in dictating where on the outer-edge of Y and Z a truncated version of the route through the system would pretend to start and end under other circumstances.

Erm, IYSWIM.  But I can see how that last one-sentence/multi-parenthesised paragraph is far more convoluted than my diagram.  Hopefully you get the sense.

Might be better to be doing the whole "ignore my ramblings" thing.  But was basically trying to say as how that was what was most concerning me in my own personal fiddling around with the whole routing algorithm under my own personal approach.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 24, 2011, 11:31:04 pm
OK, it's getting kind of late for me, so my mind is getting a bit fuzzy, and you kind of lose me near the end where you start talking about X and Y and Z but not really Y and Z, but V and W.  (Or where on the map H-I-J is.)

Anyway, from what I think you're saying, we're talking about how many different path distances there are to keep accurate information of path distances.

Basically, I'd just fudge this, and say that a diagonal crossing of passing through A through C to G in that graph is going to take 3 tiles (or 2 tiles if you don't count the "doorway"), measuring center-to-center.  Maybe you can path through it faster, only in one tile, even, but you just store 4 tiles distance from A to G and from E to G, and 6 (5) tiles distance from A to E as the pathing distances in C. 

Maybe it's right, maybe it's wrong, but we don't necessarily need to make the estimate for what nodes we want to path through a perfect one.  So long as its reasonably close, it shouldn't be terrible if in a few situations, the dwarves go in a slightly-less-than-optimal direction because they didn't use corner cutting in their heuristic to determine which nodes to pathfind through.

In fact, if we were doing the sort of "Highway" system I was talking about earlier, hugging the right wall going from A to B would mean that the dwarf would try to exit A on the far West side of the room, diagonally move southeast to point 3, to point 4, then diagonally northeast to the right-hand entrance of B.  (Trip takes 15 moves, starting from the edge of A.) 

The trip from B to A, hugging the right wall, it only takes 11 moves.

However, at the same time, a certain amount of inefficiency is worthwhile to stop even bigger inefficiencies, like traffic collisions.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 25, 2011, 06:39:23 am
OK, it's getting kind of late for me, so my mind is getting a bit fuzzy, and you kind of lose me near the end where you start talking about X and Y and Z but not really Y and Z, but V and W.  (Or where on the map H-I-J is.)
1) Don't worry about it, I was just trying to explain (badly, it seems) the issue I had made an off-hand comment about.
2) X, Y and Z are "any given start, middle, finish" (or possibly "...start, finish, middle", context was all anyway).
3) H,I,J were hypothetical extensions to the original grid, but in my mind they'd be laid out like:
Code: [Select]
A B
 CGD
 E F
 HIJ
The idea being that E->F travel might have been 'tempted' to go via HIJ instead of CGD, depending on where in E and F the end-points were.  (The labels were for zones only, not specific end-points within those rooms.)
...although by that time A-G were no longer strict 5x5s (give or take the transition-ways), may not have been completely open within-themselves and may have had various other unstated variances from the 'perfect' A..G model originally given.  something HIJ-ish (maybe not departing from three zones) could have represented a false-indication of shortcut, or a false-indication of being longer, depending on certain configurations the complex might have.

But don't worry about that.  Or the issue.  I shouldn't have mentioned my 'aperture' concerns at all, at least not in the context of the discussion at hand.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 25, 2011, 08:09:28 am
Just FYI:
You don't need to return the shortest path, best path, or anything other than a path.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 26, 2011, 10:24:54 am
I got in the mood for maths.  (Does that count as a "strange mood"?)

I just did a quick calculation in a spreadsheet, thinking about the difference between the top-down and bottom-up memory storage and searching methods...

Basically, if we work this like an "I.P. Search", where we organize the data structure "Top-Down", with the central "root" node functionally storing a directory of all the nodes below it, and each node below that storing a the nodes below it, then we have leaf nodes that store little data, but a root node that carries the phonebook.

Conversly, I previously mentioned organizing a "search tree" style of abstract node organization, this means that the root node stores no map of any nodes other than the ones it directly touches, but each lower-level node stores a map back to the root node.  This is a "bottom-up" data structure, with each leaf node carrying the longest abstract maps.

I was worried that the bottom up's having a map (or rather, a list) in each leaf node may be prohibitively costly in memory terms, so I went and did some math.

Each map is made of 2047 nodes (I just started with a map where each node is connected to 2 other branches to start simple, and went down 10 layers).  Each one carries its abstract map inside the data structure of the nodes themselves, although top-down and bottom-up shift the burden of carrying that map.

2^ means that each node connects to 2 branch nodes below it, 5^ means each node connects to 5 branch nodes, and 10^ means each node connects to 10 branch nodes.  This isn't a choice we make at this point - the nodes will connect to every branch node they touch, I'm just trying to get a feel for how the "slope of the pyramid" affects memory consumption.

To be able to compare fairly, I stunted the growth of the trees with more than 2 branches per node to only having 2047 nodes total.

Code: [Select]
Number of nodes per level:

Level    2^      5^       10^
0 1 1 1
1 2 5 10
2 4 25 100
3 8 125 1000
4 16 625 936
5 32 1266
6 64
7 128
8 256
9 512
10 1024


Top-Down memory Allocation:

Level 2^ 5^ 10^
0 2046 2046 2046
1 2044 2041 2036
2 2040 2016 1936
3 2032 1891 936
4 2016 1266 0
5 1984 0
6 1920
7 1792
8 1536
9 1024
10 0


Bottom-Up Memory Allocation:

Level 2^ 5^ 10^
0 0 0 0
1 2 5 10
2 8 50 200
3 24 375 3000
4 64 2500 3744
5 160 6330
6 384
7 896
8 2048
9 4608
10 10240


Sums:
Bottom-up:
2^ 5^ 10^
18434 9260 6954

Top-Down:
2^ 5^ 10^
18434 9260 6954

So, basically, it's a draw.  Or more specifically, it's symmetrical.  Why didn't I think of that?  Ah, well...

Anyway, more immediately useful, the "slope of the pyramid" helps greatly in reducing the amoung of memory this sort of data structure takes up.  Of course, we can't really affect that directly - the number of branches or leaves a node will have depends entirely on the shape of the map, although we do have a choice in the shape that nodes will take by the code we use to cut the map up into nodes entirely.

Now, since what this is storing is basically just a pointer, we're only talking about one byte per node, but this has a sub-geometric complexity growth with the number of nodes we use.  (Basically the O*Logb(O) as a growth rate, where b is the number of branches per node, which would not be uniform.)

This means that we save more memory generally by just trying to make larger convex nodes, even if they have obstacles inside of them, even if it means that we have to do local A* pathfinding inside the nodes to get from one side of the node to another.  The larger and more complex the nodes are, the longer it takes to pathfind from one end of a local node to another, but we are buying back memory with pathfinding time doing this.  So it's pretty much a judgement call.

Now, the advantage of this sort of IP-based/quasi-search-tree searching is that you can simply go up the number of branches in the tree as it takes to find the branching node that contains both the start and destination nodes, and you never have to search a single node beyond those.  (You would probably want to search for a "shorcut" between those nodes, but that would only involve checking for "touching" between the connecting branches and leaves that don't involve jumping up a level in the abstract path, but that's a trivial amount of calculation when we've already shut off so much of the rest of the map.)

We might have to still do A* for local nodes, and making larger nodes might make the node-construction and node-merging/splitting code more complex, but the amount of time you would save in long-distance pathfinding would be tremendous.  You wouldn't have to bother at all with heuristics or searching for more nodes than necessary in the abstract tier in this sort of search tree.

It should buy signfiicant speedups at the cost of a relatively manageable amount of memory consumption.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 27, 2011, 01:06:57 pm
I've been thinking about algorithms for node grouping but as usual I hit the wall with constraints :

- A room is a group of nodes that have a  impassable and passable nodes.
-  Every passable node in a room must be reachable from every other passable node in a room (this is where BFS can help)
- a room's shape must be a rectangle

here are the derived things we need to do in order to group nodes in to rooms
- arbitrary room division algorithm
- room validation - modified BFS with post-runtime scanning for unvisited nodes.
- room resizing ,merging and node trading (for both squaring and discarding impassible nodes)
- A room can overlap with other rooms. With rectangles it's unstoppable. it would take too much memory to do it in another way.

Because we are pathing we should also store have a way to describe edges. We should also consider data structures which are good for caching . It's not too critical because it would be faster than O(k^N) .

We need a function which can quickly convert x,y,z coords to node id .

I'll try to setup some demo using those rules. ;)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 27, 2011, 01:58:54 pm
Nodes don't need to be rectangles.

They can be rectangles, but don't need to be...

You can have convex shapes, like the right triangle shape, and it breaks no assumptions.

You can also have non-rectangular shapes like a circular shape.  See:
Spoiler (click to show/hide)

Now, you can make that entire circular room a node.  Depending on what sort of pathfinding you use, you can make the whole outer circle around that room be a big node, as well.  All the tiles in the node are accessable, you just need a small amount of A* pathfinding to find a route around the circular room's walls.  So long as A* is bounded into a "local node pathfinding" where the shapes are guaranteed to be simple, you can still use A* very efficiently.

After that, you don't need to have overlapping rooms.



Oh, and making a coordinate into a node id is fairly easy - just take the x-coordinate, make it the first eight bits (768 tiles are the maximum number of tiles horizontally), take the y-coordinate, make it the second 8 bits, and then make the z-coordinate the rest of the bits.

You could also do it hash-style, but this would probably be faster and cleaner.



I'm suddenly thinking of something else, as well, but that will take a diagram...
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 27, 2011, 04:04:29 pm
OK, let's go with a diagram...

Spoiler (click to show/hide)

This map depicts a "Central Staircase" "Modular Fortress".  It's the sort of fortress I try to avoid, but it's also really fast to set up and demonstrate an idea, so I'm going with that.

"X" means stairway, and "+" means door.  "S" means starting point, and "F" means finishing point.

Now, the red central staircase is the root node in this demonstration - the doors are their own nodes so that they can be locked, and that node will simply be pulled out of the map.  Each color change radiating from that central staircase represents a successively lower-tiered node, going down 8 levels to the cyan colored room.

Also note, this isn't a very large map, but it already has 9 tiers in it.

Now watch me tear a hole in my previous idea...

The problem with working with a search-tree organized node map would be that, even though the red line I drew represents the direct path from start to finish that A* would probably find, the blue line is what the search tree style of pathfinding would likely find.

I actually put in the yellow (tier 6) door south of the Finish Room (a tier 8 room) a little after I started typing this, which is why the room itself is the wrong color - it should be a yellow-green (tier 7) because it is accessable by a tier 6 room.  The change from being a tier 8 to tier 7 after having that door punched in would be a fairly easy change (you just change some pointers), so that's not a big deal, but the problem comes from the sort of situation when you have two very different routes to the same place.

The red line is a faster line.

The way that the search tree pathing works, it tends to work better for either fractally-designed fortresses or for fortresses with fairly long hallways.  The sort of fortress where everything is a big grid with interchangable hallways can screw with the pathing.

Now, previously, I said you could do a search for a shortcut by trying to cut out going up too many branches in the tree.  You can see this in the blue line where the blue line goes through the red-orange ring room around the central staircase.  There are some small lines indicating a possible place for nodes to be split.  If this is a search tree, the red-orange nodes are on equal tiers with one another, and the finish room is down the north branch's path of leaf nodes.  The west red-orange area holds the starting room.  Hence, in pathing, the starting room has to go all the way up to the central staircase node to find a common node both the starting and ending rooms share.  Then, the game can check and see that the two red-orange rooms are contiguous with one antoher, and cut the central staircase out of the equation, and make a "shortcut" between the two red-orange rooms, rather than going back up all the way to the node they have in common.

From there, it follows the branching nodes down the different hallways to the door to the Finish room, using a search tree rather than standard pathfinding to find the room you were looking for. 

Now, here's the potential problem - if we want to optimize for distance travelled, the red line (A* pathfinding) is faster.  To have the search tree find that route without using a heuristic or pahtfinding through the tree, it would require the Finish Room be a part of both the west red-orange room's leaves and also the north red-orange room's leaves.  This would cause a potentially huge jump in the amount of memory these search trees would need to take up in order to handle overlapping data.  This may be unacceptable, even in an optimal organization of the data.

Alternately, we just take Draco's statement at full value, and just return A path, even if it's not the shortest path, so long as it is a path you can calculate very quickly.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 27, 2011, 10:53:39 pm
Although personally I wouldn't use a tiered hierarchy for the nodes.  I'd use a mesh.

Under the assumption that every group of tiles has the same "edge" weight (as far as A* is concerned) it would actually return the red path:

S, door, hall (orange), hall, (pale orange), hall (yellow), door, F
As it would be shorter than:
S, door, hall (orange), "central tower", hall (orange), hall (pale orange), door, F

Depending on how the tiles are grouped.

Obviously you'd want some weighting for each grouping, but you'd have to balance between using an abnormally high value for a long skinny hallway that the dwarf only needs to walk 3 tiles to cross, or an abnormally short distance for a long skinny hallway that the dwarf needs to walk the 37 tiles down.

Although it may be possible to determine these values when the mesh is built, giving each edge a weight based on the distance, or at least one that is "close enough" that it works.

For instance, on square nodes the weight would be the side length (the only path that is longer are the diagonals, but not by much).  For rectangles (especially ones that exceed a 1:2 length to width ratio) the weight would be the distance across the rectangle perpendicular to the connecting face.  So a node connection on the long face has a weight of the length of the short face; connections would be direction independent (the node you're entering).

This would mean that the length would be artificially low if the dwarf has to cross and travel down a long hallway, but is an acceptable failure to find the "shortest" path, as all we need is a sufficiently efficient path using the fewest processing cycles as possible.

So our red path above is an approximated length 26, the blue 45 (using the node boundaries as drawn).  In reverse the distances are 23 (red) and 51 (blue).  Actual distances are 27 (red) and 34 (blue).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 28, 2011, 08:39:03 am
Nodes don't need to be rectangles.

They can be rectangles, but don't need to be...

You can have convex shapes, like the right triangle shape, and it breaks no assumptions.

You can also have non-rectangular shapes like a circular shape.
Now, you can make that entire circular room a node.  Depending on what sort of pathfinding you use, you can make the whole outer circle around that room be a big node, as well.  All the tiles in the node are accessable, you just need a small amount of A* pathfinding to find a route around the circular room's walls.  So long as A* is bounded into a "local node pathfinding" where the shapes are guaranteed to be simple, you can still use A* very efficiently.

After that, you don't need to have overlapping rooms.



Well we gotta start with something. My idea was based on using A* pathing algorithm or D* lite ( start at destination find the source). 

Anyways about room shape If we make maximum room size 16X16 we can save a bit vector (more of a bit map) of the shape of the room with 32 bytes . My little test_maze page uses that format to "save " mazes . With a "bit vector" we can save any arbitrary shaped room  in a very compact manner which can easily tell weather a node is in a room or not.
this is how it works:

Code: [Select]
\/room A  room B\/
##################
######++#++++++++#
####++++#++++++++#
###+++++#++++++++#
##+++++++++++++++#
##++++++#++++++++#
#+++++++#++++++++#
#+++++++#++++++++#
#+++++++#++++++++#
##################
as you see room A has an arc in top left corner this means. The "link" generated by the my program has a bit vector with a 1 where there is a wall so if we want to exclude the walls we just need to invert it.
The map representation in hex  is (the borders are excluded):
Code: [Select]
F900
E100
C100
8000
8100
0100
0100
0100
FFFF
Room A mask is done by removing room B and inverting bits of A ( I included the entrance to B in room A)
Code: [Select]
hex  | binarry
0600 | 00000110 00000000
1E00 | 00011110 00000000
3E00 | 00111110 00000000
7E00 | 01111110 00000000
7F00 | 01111111 00000000
FE00 | 11111110 00000000
FE00 | 11111110 00000000
FE00 | 11111110 00000000
0000 | 00000000 00000000

This way rooms can be saved in rectangles  regardless of their shape and overlaps will not happen. You can make this bitmap variable length but keeping it constant may help with cache performance.

Using 4x4 embark X200 levels that would be the bitmap would use about 1MB of space. Converting a BFS and trading node would be fairly trivial in this case.  It would take some bit manipulation but those actions are super fast .


Oh, and making a coordinate into a node id is fairly easy - just take the x-coordinate, make it the first eight bits (768 tiles are the maximum number of tiles horizontally), take the y-coordinate, make it the second 8 bits, and then make the z-coordinate the rest of the bits.

You could also do it hash-style, but this would probably be faster and cleaner.



Finding a hash for the room is a trivial problem it got to do with deciding on data structures and data organization. It's not such a big issue because as you said the X,Y,Z coordinates  of points inside the room are unique.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 28, 2011, 09:28:47 am
Well we gotta start with something. My idea was based on using A* pathing algorithm or D* lite ( start at destination find the source). 

Anyways about room shape If we make maximum room size 16X16 we can save a bit vector (more of a bit map) of the shape of the room with 32 bytes . My little test_maze page uses that format to "save " mazes . With a "bit vector" we can save any arbitrary shaped room  in a very compact manner which can easily tell weather a node is in a room or not.
this is how it works:

Code: [Select]
\/room A  room B\/
##################
######++#++++++++#
####++++#++++++++#
###+++++#++++++++#
##+++++++++++++++#
##++++++#++++++++#
#+++++++#++++++++#
#+++++++#++++++++#
#+++++++#++++++++#
##################
as you see room A has an arc in top left corner this means. The "link" generated by the my program has a bit vector with a 1 where there is a wall so if we want to exclude the walls we just need to invert it.
The map representation in hex  is (the borders are excluded):
Code: [Select]
F900
E100
C100
8000
8100
0100
0100
0100
FFFF
Room A mask is done by removing room B and inverting bits of A ( I included the entrance to B in room A)
Code: [Select]
hex  | binarry
0600 | 00000110 00000000
1E00 | 00011110 00000000
3E00 | 00111110 00000000
7E00 | 01111110 00000000
7F00 | 01111111 00000000
FE00 | 11111110 00000000
FE00 | 11111110 00000000
FE00 | 11111110 00000000
0000 | 00000000 00000000

This way rooms can be saved in rectangles  regardless of their shape and overlaps will not happen. You can make this bitmap variable length but keeping it constant may help with cache performance.

Using 4x4 embark X200 levels that would be the bitmap would use about 1MB of space. Converting a BFS and trading node would be fairly trivial in this case.  It would take some bit manipulation but those actions are super fast .

I'm sorry, I'm not sure I'm catching something, here...

What happens if the 16x16 block you cut up into rooms involves rooms that do not touch each other, and which touch entirely different nodes, here?

Also, this whole plan seems to have nothing for vertical pathfinding - how will fliers and swimmers be able to pathfind using this?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 28, 2011, 02:11:55 pm
I'm sorry, I'm not sure I'm catching something, here...

What happens if the 16x16 block you cut up into rooms involves rooms that do not touch each other, and which touch entirely different nodes, here?

The bit vector will tell which nodes within the rectangle are members of  the room .
example:
Code: [Select]
_01234567
0#######
1#+#+++#
2#+###+#
3#+++#+#
4#+###+#
5#+#+++#
6#+###+#
7#+++++#
8#######

room A is 1,1 to 3,7
room B is 3,1 to 5,7
those rooms overlap but they have a disjoint node set
binary mask for room A
Code: [Select]
100
100
111
100
100
100
111

binary mask for room B
Code: [Select]
111
001
001
001
111
001
001
011

This way two squares may overlap but not include the same nodes.

Also, this whole plan seems to have nothing for vertical pathfinding - how will fliers and swimmers be able to pathfind using this?

I don't think I accounted for that - when the dwarf/mob reach a blocked  "room"  it can try to find an alternate path when it finds out the original one is blocked - then the room can be updated to show that the connection with another node has been severed .

It's also true that a dwarf/mob would wants to go  through 100 z levels you'll have to go through 100 "rooms"  but it's not as bad because you'll have a simple traversal on each step of the way. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 28, 2011, 02:13:49 pm
You did it wrong again.

The question was for a layout like this:

_01234567
0#######
1#+#+++#
2#+###+#
3#+++#+#
4#+###+#
5#+#+++#
6#+###+#
7#+++#+#
8#######
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 28, 2011, 02:23:30 pm
You did it wrong again.

The question was for a layout like this:

_01234567
0#######
1#+#+++#
2#+###+#
3#+++#+#
4#+###+#
5#+#+++#
6#+###+#
7#+++#+#
8#######


It doesn't really matter where the walls are when we are talking which open spaces are included in each node. There is also nothing that stops us from adding walls to a room. you just change the last lines of the masks of room A and room B to  111 and 001 respectively and you get a disjoint set of nodes.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 28, 2011, 02:56:23 pm
What I'm asking relates to how you are talking about 16x16 blocks to make a node, and then talking about them as though multiple nodes are stored in the same block of data or the like...

If you have a room in the north end of a 16x16 block that accesses the north side of that node, then have a room in the south end that only has access to other nodes on the south end, and store that as "this 16x16 block has access from the south and the north", but there is no connection from the north to the south, then you would be falsely storing a notion that if you can access the north and the south from that node, that you could path from the south to the north through that node.

In other words, like this:

_01234567
0###+###
1#+#+++#
2#+###+#
3#+++#+#
4#+###+#
5#+#+++#
6#+###+#
7#+++#+#
8###+###


Where there are other nodes to the north and south.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 28, 2011, 04:09:11 pm
If you have a room in the north end of a 16x16 block that accesses the north side of that node, then have a room in the south end that only has access to other nodes on the south end, and store that as "this 16x16 block has access from the south and the north", but there is no connection from the north to the south, then you would be falsely storing a notion that if you can access the north and the south from that node, that you could path from the south to the north through that node.

In other words, like this:

_01234567
0###+###
1#+#+++#
2#+###+#
3#+++#+#
4#+###+#
5#+#+++#
6#+###+#
7#+++#+#
8###+###


Where there are other nodes to the north and south.

You can keep drawing maps it doesn't really matter if each node has a rectangle + a bit map where a 1 says "this node is in the room " and 0 say "this zone is not in this room"
so now all you got is 1,1 to 3,8 and 3,0 to 5,7

 A    B
100 | 100
100 | 111
111 | 001
100 | 001
100 | 001
111 | 111
001 | 001




 It doesn't really matter what shape room you have you can describe it with a bit vector. The 16X16 was generally an example of how to store it. with a bitmap you can actually need only 1 point and you can store winding corridors if you want to .
something like this with 3 rooms all overlapping each other in some way :
Code: [Select]
##################
#A#AAAAAAAAAAAAAA#
#A#A############A#
#A#BBBBBBBBBBBB#A#
#A#BBBBBBBBBBBB#A#
#A#BB######BBBB#A#
#A#BB#CCCC#BBBB#A#
#A#BX#CCXC#BBBB#A#
#A#BX#CCXC#BBBB#A#
#A#BX#CCXC#BBBB#A#
#A#BB######BBBB#A#
#A#BBBBBBBBBBBB#A#
#A#BBBBBBBBBBBB#A#
#A#BBBBBBBBBBBB#A#
#A#BBBBBBBBBBBB#A#
#A##############A#
#AAAAAAAAAAAAAAAA#
##################
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 28, 2011, 06:45:47 pm
The point was, what determines connectivity from one room to another?  All you're doing is storing the same data in a new way.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 29, 2011, 01:46:43 am
The bit vector only solves the shape problem. The edges of the nodes would require more data types that store edges.

Code: [Select]
typedef struct
{
int id;
int x1,y1,x2,y2; /* height and width are derived values */
unsigned int cost;
char * nodeBitVector  /* could be other data type to store this data */
iint numEdges;/* can use smaller data type to */
int * edgeList /* can either be constant or dynamically growing base type this can also be a complex type */
}
tNode;

after determining the rooms you need to do a connection graph using edges data type.
after that's done.

There is another option . You can store the nodes in  a 2 dimensional array and then use something like an 8 bit mask for open directions

example:
Code: [Select]
E F G
 \|/
H-A-B-C-D
  |
  I

EFG###
HABCD
#I####

# is empty node.
edge list :
E = SE
F= S
G= SW
H= E
A = W  NW N NE E S
B= E W
etc

Managing this data type would be complicated. but node traversal would be faster .Using nodes with edge list within them is trivial but it might cost in some cache performance and more memory. .The edge list can store a complex type with a clear destination point/points  but this is not that important. I think we are talking about 2MB on 4X4 embarks and with a node data type with 6 edges (with destination points) it's about 100 bytes per node that's about 47MB if each room is on average size 16  or 4X4  (this number should be maximized). To reach that maximum you'll practically have to dig out every level into a maze  and have 200 levels of stone/soil

This takes care of irregular shaped rooms and their connection. Dividing the map into room and their dynamic update(merge,grow,delete etc...) is another issue. I did cover some of it in my general post about the "rules".
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 29, 2011, 11:09:30 am
If we are dealing with nodes, an almost arbitrarily large number of nodes can spring off of a node.  (Imagine a hallway with small bedrooms coming off of them, divided by doors which would preferably be their own node so that they can be locked and made disconnected.) With up to 16x16 tiles, that's up to 8 bedrooms per side.  Plus stairs coming in and out.

About the data type that stores node connectivity - where is that stored, separate from the nodes themselves? (I.E. Do the nodes themselves store what they are connected to?)

And how do you traverse it?  For that node A, I would expect you would have to store at least one instance of pathing data per permutation of connections through A connecting to any of the nodes A is adjacent to.  (Plus you might need multiple types for different travel methods - fliers and swimmers and large vehicles would take different types of connections.)

While the psuedo-search tree/massively hierarchical method I was speculating on may be somewhat wonky, it does at least return a path with minimal searching of unnecessary nodes.  (I'm still thinking of ways to try to make the system work better... If I make it a floating independent data structure with freak loads of pointers, it stays light, and it is possible, if potentially very confusing, to have children of unrelated higher-tier nodes as your own node's branches.  I'm just not sure how to make that work in a cost-effective manner, yet.) 

Without such a method, the heuristic gets a little odd, although I think you were talking about using a heuristic based upon just making a node address out of hashing the xyz coordinates before, so I guess that's what you're thinking. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 29, 2011, 12:18:28 pm
If we are dealing with nodes, an almost arbitrarily large number of nodes can spring off of a node.  (Imagine a hallway with small bedrooms coming off of them, divided by doors which would preferably be their own node so that they can be locked and made disconnected.) With up to 16x16 tiles, that's up to 8 bedrooms per side.  Plus stairs coming in and out.
16X16 was picked arbitrarily in general  it's a 256bit vector of 32bytes. It gave me a ballpark figure on how much memory it would consume. in my struct it uses it as a dynamically allocated vector but the implementation is all defendant on the programmer. In a 256 bit vector you can store any rectangle that contains 256 nodes. This vector can represent a room within a 16X16 square ,a 8X32 rectangle or a 4X64 hallway .

If you only store the open spaces the node graph shouldn't take much room .

About the data type that stores node connectivity - where is that stored, separate from the nodes themselves? (I.E. Do the nodes themselves store what they are connected to?)
That's an option but it's not very desireable as it would make the memory use grow by about 1.8MB per embark square or 461KB  if you use a byte and a z level lookup table. Even if you go through a linear search and just keep a lookup table for each z you'll find your start point fairly fast. It's like 9 nodes per embark square or 144 per 4X4 embark .
And how do you traverse it?  For that node A, I would expect you would have to store at least one instance of pathing data per permutation of connections through A connecting to any of the nodes A is adjacent to.  (Plus you might need multiple types for different travel methods - fliers and swimmers and large vehicles would take different types of connections.)
I'm suggesting a pointer or pointer like connected graph  with Inner traversal of A*. First the dwarf would find the path on the upper level graph and then it would step through that graph by creating subpaths with A* . As I said (x+1)*K^W instead of K^(W*x). Flyers should also have more advance pathing like vector pathing which is much faster runtime to find a good starting point for A* .

I hope you'll find my partial response satisfactory I gotta drive home ;).

Anyways with all the parameters defined it's just a matter of implementing a demo - everyone is welcome to it ;).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Zanielyene on March 29, 2011, 01:33:07 pm
Does toady even read this thread?

I always thought caching commonly used paths would be helpful. ie: caching the path between workshops and stockpiles.

I imagine with only a few megabytes of cache, quite a few paths could be cached, reducing the load on the cpu.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 29, 2011, 01:49:04 pm
The problem there is determining a commonly used path.  You'd have to save every path request and check for frequency before you could even start saving those common paths.  And requests that are 1 tile off from a "known" request is unique, as far as the computer is concerned.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 29, 2011, 04:40:18 pm
Does toady even read this thread?
I think it's more a matter of demonstrating an alternative  and not a matter of  reading ;).

I always thought caching commonly used paths would be helpful. ie: caching the path between workshops and stockpiles.

I imagine with only a few megabytes of cache, quite a few paths could be cached, reducing the load on the cpu.
I'm not sure anyone have demonstrated that  yet many people talk about it but none gave a practical implementation. the paths are dynamically generated and there are just too many possibilities . There was the idea of highways but it would again mean generating an overlaying map.
 
It all comes down to creating a map to  prevent the cpu of using tunnel vision. It's stuck in the maze and it won't move until it finds a path out. With a map It would be easier for it to tell the way and avoid looking through known dead ends.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 29, 2011, 09:22:24 pm
If you work with nodes, you could possibly start working with a "commonly used node" idea.  Either a "I'm specifically going from this node to this node" type of concept, where you would have to store the start and end points, although this is typically memory-wasteful, or by just weighting the node every time it is used.

I was talking earlier about weighting nodes - by using a counter where you bias a node so that the computer is more likely to search for a connection using a given node before any other if they have a high bias in their counter, and adding to that bias each time the connection does turn out to path through the node, and then subtracting from that bias counter every time you cannot path through that node to the destination, you will wind up with "major artery" types of nodes (like major hallways) rising up high in their bias counters, and paths that only lead to dead ends winding up with negative scores. 

Doing that sort of thing can help you rebalance what nodes you try to path through in some methods of pathfinding.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 30, 2011, 06:43:12 am
So you are suggesting a new node weighing scheme .   Claiming that a path exists to any destination using a "beaten path ". This way major nodes would be most visited node. If you the number of nodes to N you can cache (N-1)^2 paths from popular nodes.

Then pathing algorithm would be like this :
1. find minimal heuristic score of all popular nodes from the destination and source
2. find a path from the closest popular node closest to the destination
3. if such a path exist find a path to the popular node closest to you.
4. use a predefined path to the node closest to destination.
5. use pre-calculated path to destination.

This can work well for path caching. you can also give the user the option to pin their popular nodes rather than the OS to do it. This can allow pathing to run faster  with a relatively minor cost and low complexity to implement. It does have a pitfall.
side view
Code: [Select]
S_A_B
##X#X
##X#X
##X#X
##X#X
##X#X
##C#D
#####


C is closer to D but the path from C to D is much longer than the path from B to D. As we all know heuristic can lie. we can try to limit it and make it look for a better candidate It might be less expensive than doing the long path.

Considering this and storing paths by moves N,S,E,W,U,D gives 26 posibilities and if you remove the vertical diagonals  it's 10. Using 4 bits to represent  you can do 200 step path in 100 bytes . You can also add run length encoding for repeated steps. Using this figure you can (without run length ) fit 5242 paths per 1MB which can store the connections between 102~ major nodes.  for 200 nodes you'll need about 4MB and for 1000 you'll need 100MB.

I guess this is a good alternative to a complex room scheme.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 30, 2011, 09:52:08 am
Considering this and storing paths by moves N,S,E,W,U,D gives 26 posibilities and if you remove the vertical diagonals  it's 10. Using 4 bits to represent  you can do 200 step path in 100 bytes .

Well, that gets back to the problem I was talking about before about how nodes make connections -

The problem is, you can't store nodes as strict "N, NW, E, SE, S, SW, W, NW, U, D" types of connections - you need a virtually arbitrary number of connections to any given node. 

Especially if you are going to make it possible for a 2x128 hallway to be a single node, there could be potentially over a hundred different nodes sticking off of that one hallway node in the form of stairs going up and down and different narrow rooms that are their own nodes sticking off that hallway.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 30, 2011, 10:32:26 am
Considering this and storing paths by moves N,S,E,W,U,D gives 26 posibilities and if you remove the vertical diagonals  it's 10. Using 4 bits to represent  you can do 200 step path in 100 bytes .

Well, that gets back to the problem I was talking about before about how nodes make connections -

The problem is, you can't store nodes as strict "N, NW, E, SE, S, SW, W, NW, U, D" types of connections - you need a virtually arbitrary number of connections to any given node. 

Especially if you are going to make it possible for a 2x128 hallway to be a single node, there could be potentially over a hundred different nodes sticking off of that one hallway node in the form of stairs going up and down and different narrow rooms that are their own nodes sticking off that hallway.

My comment was related to path caching /highway generation and which has a much different scheme than my original suggestion of problem reduction.

My original  suggestion  was to build a map of smaller areas from the original map and navigate it changing
 the complexity from O(f(W*x)) to O(x*f(W)+f(M)).

here is a small example to clarify
Code: [Select]
##################
#+++++#++++#+++++#
#++A++#++B+#++C++#
#+++++###+##+++++#
#++D+++++E++++F++#
#######++++#######
#+++++#++++#+++++#
#++G++#++H+#++I++#
#++++++++++++++++#
#######++++#######
#+++++#++++#+++++#
#++K++#+J++#+++L+#
#++++++++++++++++#
##################
room division
Code: [Select]
  B   C
  |   |
A-D-E-F-C
    |
  G-H-I
    |
  K-J-L

path caching ,highway N=A+L+B where L>> A (much greater ) and L>>B. M is number of nodes that make the highway gives a O( f(A)+f(B) +2*M ) the search of M can be reduced to log M by ordering the nodes. Node placement either using a statistic scheme or manual placement.
Code: [Select]
A-B 2SE,3E,1NE,N,stop
A-C 2SE,7E,2NE,E,stop
A-D 2S,stop
.
.

There are now two different  solutions well defined solution  (I hope ) which reduce the complexity of Pathing. There is  generally more advantage to creating a map over path caching but mapping is tougher to implement.  Path caching is fairly simple to implement once you decide on a node placement scheme but the paths you'll get as results won't be ideal and may require some "smoothing".
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 30, 2011, 11:14:33 am
You're still not getting it.

How would it work in this situation?

#########
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on March 30, 2011, 11:46:26 am
You're still not getting it.

How would it work in this situation?

#########
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####


which method and what constraints?

Path caching require some start point and end point selection  and a node placement scheme. Maze solving isn't the point it's teaching the computer to do it.

I can probably write a JS path caching demo pretty quickly . I got a 5 hour bus drive tomorrow (going to Eilat ) so I can probably even do a room method demo.

What a path caching scheme would do is simply place nodes in different spots, find the path from each node and save it and then use the saved paths to reach the destination.

a room divider would pick somekind of constraint on room size and start slicing the map arbitrarily , do room validations and split them when needed . after that map neighboring rooms . Then it might go through a room merge stage if needed. Pathing would be done by deciding which room you are in, finding a path on the map and then take that path using A* as subpath.

Path caching would take some validation too and if the path you are given tell you to go through a wall you'll have to recalculate it. I also think my estimate was bad because the pathes are 2 way so the paths in the cache can be stored in half the memory.
 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 30, 2011, 12:04:15 pm
You're still not getting it.

How would it work in this situation?

#########
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####


which method and what constraints?

Path caching require some start point and end point selection  and a node placement scheme. Maze solving isn't the point it's teaching the computer to do it.

I can probably write a JS path caching demo pretty quickly . I got a 5 hour bus drive tomorrow (going to Eilat ) so I can probably even do a room method demo.

What a path caching scheme would do is simply place nodes in different spots, find the path from each node and save it and then use the saved paths to reach the destination.

a room divider would pick somekind of constraint on room size and start slicing the map arbitrarily , do room validations and split them when needed . after that map neighboring rooms . Then it might go through a room merge stage if needed. Pathing would be done by deciding which room you are in, finding a path on the map and then take that path using A* as subpath.

Path caching would take some validation too and if the path you are given tell you to go through a wall you'll have to recalculate it. I also think my estimate was bad because the pathes are 2 way so the paths in the cache can be stored in half the memory.

OK, let's do it like this...

#########
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####


Let's call the middle hallway "A".  Let's then call each room "B" through "I", and connecting to some other node "J" to the south.  The middle hallway would be a very long "A" node, with the following forks:


B\ /C
D-A-E
F/ \G
H/|\I
  J


Now, we have 9 horizontal connections to "A" in a method that only allows for 8 horizontal connections - in this case, two different nodes are "southwest" and two different nodes are "southeast" of "A".

Keep in mind, if we allow hallway nodes to be 4x64 tiles, then we could potentially have much longer hallways with much more rooms sticking off of them, plus many different stairwells, creating potentially hundreds of connections to a single node.  But you're only talking about 10 connections to a single node.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on March 30, 2011, 12:06:56 pm
OK, let's do it like this...

#########
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####
#..#.#..#
#.......#
#..#.#..#
####.####


Let's call the middle hallway "A".  Let's then call each room "B" through "I", and connecting to some other node "J" to the south.  The middle hallway would be a very long "A" node, with the following forks:


B\ /C
D-A-E
F/ \G
H/|\I
  J


Now, we have 9 horizontal connections to "A" in a method that only allows for 8 horizontal connections - in this case, two different nodes are "southwest" and two different nodes are "southeast" of "A".

Tada.  Hence why you can't say "a node can only have 8 horizontal connections (+2 for up/down)."

which method and what constraints?

Your most recent example.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: DrDada on March 30, 2011, 03:16:15 pm
What about the thing this guy said?
...
Question: Has Toady ever mentioned taking the principle of stigmergy from the ACO scheme in order to dynamically modify the PATH_COST value for tiles as dwarves travel over those tiles? My thought is that since we can already improve framerate by manually designating High Traffic Areas, perhaps inserting some code to dynamically modify High Traffic areas as the dwarves are travelling would provide the same benefit while keeping the same A* algorithm in place.
...
I had the same idea and searched in this and other threads for it, but nobody gave feedback to it afaik.
Wouldnt this work?
Just add a value for every tile that increases every time a dwarf walks over a tikle and globally decrease it periodically. The search algorithm would priorize high traffic tiles over others.

Sorry if its dumb...too obvious or whatever I'm just curious.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on March 30, 2011, 03:44:38 pm
What about the thing this guy said?
...
Question: Has Toady ever mentioned taking the principle of stigmergy from the ACO scheme in order to dynamically modify the PATH_COST value for tiles as dwarves travel over those tiles? My thought is that since we can already improve framerate by manually designating High Traffic Areas, perhaps inserting some code to dynamically modify High Traffic areas as the dwarves are travelling would provide the same benefit while keeping the same A* algorithm in place.
...
I had the same idea and searched in this and other threads for it, but nobody gave feedback to it afaik.
Wouldnt this work?
Just add a value for every tile that increases every time a dwarf walks over a tikle and globally decrease it periodically. The search algorithm would priorize high traffic tiles over others.

Sorry if its dumb...too obvious or whatever I'm just curious.

The closest thing that you could apply would be the bias/weighting of hierarchical nodes I was talking about a little up the page:

If you work with nodes, you could possibly start working with a "commonly used node" idea.  Either a "I'm specifically going from this node to this node" type of concept, where you would have to store the start and end points, although this is typically memory-wasteful, or by just weighting the node every time it is used.

I was talking earlier about weighting nodes - by using a counter where you bias a node so that the computer is more likely to search for a connection using a given node before any other if they have a high bias in their counter, and adding to that bias each time the connection does turn out to path through the node, and then subtracting from that bias counter every time you cannot path through that node to the destination, you will wind up with "major artery" types of nodes (like major hallways) rising up high in their bias counters, and paths that only lead to dead ends winding up with negative scores. 

Doing that sort of thing can help you rebalance what nodes you try to path through in some methods of pathfinding.

The problem with stigmergy in general is that it is potentially very memory-consuming, and doesn't necessarily improve pathfinding speed terribly much if you're just putting it on standard A*, anyway, at least until you have a bias hundreds or thousands of points strong so that dead ends are almost never pathed down.  In order to do that, you'd need something like 16 bits of data per tile, which is potentially a large amount of memory.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on March 30, 2011, 06:31:37 pm
The problem with stigmergy in general is that it is potentially very memory-consuming, and doesn't necessarily improve pathfinding speed terribly much if you're just putting it on standard A*, anyway, at least until you have a bias hundreds or thousands of points strong so that dead ends are almost never pathed down.  In order to do that, you'd need something like 16 bits of data per tile, which is potentially a large amount of memory.

On top of that[1], never mind that there's got to be some sort of sanity-check.  Just because dwarfs have been walking all the way around/across a mountain transferring goods from a dead-end front entrance to a dead-end rear entrance, when the player realises that this is happening and all he or she should need to do is tunnel through/unforbid the door between the sites, it's quite possible that the 'well-travelled' bias value on the mountainside route still makes it dominate the path-search over the more direct route.

Yes, hard cases make bad rules, but that's just an extreme version of something that needs to be considered before that suggestion is to be taken on-board.  Perhaps considered an acceptable side-effect, of course, and allowed to happen.


[1] Because one way of getting around that is to only 'create' reference values when walked over, and remove "flatlined' areas from the store altogether, in a dynamic and hash-like structure that doesn't attempt to store every single walkable tile, but only those having recent footsteps over them justify the slight[2] extra overhead for such a structure-lookup system and get a value, quickly getting culled.

[2] Or not.  I might let the development environment handle that sort of thing, but if we're talking about optimisation one really needs to work out how it can be done best.  Several of the ideas I have on how this might be done take up a large amount of memory (or time) in and of themselves.  If the limit on cells being stored is small enough, there could be a sorted list to binary-search containing pointers to where value is being held (if not the value itself, if that's more efficient and there aren't other bits of info being also stored there) but that would mean doing a splice-in for every single newly stepped-on tile...  Although the periodic devaluing operation could at least pull in the existing list and create a new list with reduced values in a very quick loop, discarding all the ones that hit the current 'floor' value.  Larger 'lists' would cause increasing referencing overheads, of course, on-top of their own basic footprint.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 03, 2011, 09:26:24 am

which method and what constraints?

Your most recent example.
I can do both  ;)



_012345678
0#########
1#..#.#..#
2#.......#
3#..#.#..#
4####Y####
5#..#.#..#
6#.......#
7#..#.#..#
8####.####
9#..#.#..#
A#.......#
B#..#.#..#
C####Z####
D#..#.#..#
E#.......#
F#..#.#..#
G####.####


With Path Caching I'll pick 2 or 3 way-points like Y= 4,4 and Z=4,C. This way there would be 1 path cached from Y->Z  go south 8 steps and it's reverse path .

If you want to go from 1,E to 7,1 you'll find a path from 1,E to Z, go on a path  from Z to Y  and then find a path from Y to 7,1. If you want to go to a closer node you might find that the distance to the node itself is closer than the way-point and you'll just path to it. You can also use the way-point twice  but it won't gain you much at all.  Adding 4 waypoints at the passages would make it even easier because the central hall would be the highway and your longest path would always be length 3 or less. You should also consider an O(n) path optimization/smoothing to prevent  the mob from crowding the way-points and going on unnecessary  paths.

If I was 6X6 room maximum(to complicate things ) a simple slicing algorithm would have the first room

_012345
0######
1#..#.#
2#.....
3#..#.#
4####.#
5#..#.#

after the room is generated it need to be walled off to check if it's valid

_01234567
0#######
1#######
2#..#.##
3#.....#
4#..#.##
5####.##
6#..#.##
7#######

now this room needs to be validated - every node should be reachable and it's not  so line 5 5 in the original room is either removed or has it's 5,1 and 5,2 discarded. next we can try to reshape the room to reach maximum coverage line 5 is a good candidate to be discarded because it has more nodes out of it than in it.  this way we can change from a 6X6 to a 5X7
or this

_01234567
0########
1#..#.#..
2#.......
3#..#.#..
4####Y###

do the same thing to validate and you get a good room to start with. This require all sorts of node exchange functions and validity checks. After you are done with defining rooms you can check the connections between them and define it as edges. That would give you something like this

A-B-C-D-E

this way if you want to get from 1,E to 7,1 again you'll need a path from D to A and would get  D->C->B->A-> 7,1. This gives you a couple of A* searches length 5 which in most case would be a straight line. The original problem is a 14+ step path which can reach very high complexity than the sum of it's parts.


I'm trying to sort out a JS demo for both but I need to fix up my UI. The bus ride didn't let me code much - it was a combination of baby screaming for attention and my very long arms.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 03, 2011, 10:48:24 am
Just to point out:
You've always been choosing a room division size in order to convenience yourself.  You're not allowed to chose the "best case scenario" for each example.

For example, what if the first step returned this?

_012345
0######
1######
2###..#
3###...
4###..#
5######/

What it the rooms were larger (rather than the quick and dirty 2x3 rooms I made)?

#######++#######
#+++++#++#+++++#
#+++++#++#+++++#
#++++++++++++++#
#+++++#++#+++++#
#+++++#++#+++++#
#######++#######
#+++++#++#+++++#
#+++++#++#+++++#
#++++++++++++++#
#+++++#++#+++++#
#+++++#++#+++++#
#######++#######
#+++++#++#+++++#
#+++++#++#+++++#
#++++++++++++++#
#+++++#++#+++++#
#+++++#++#+++++#
#######++#######
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 03, 2011, 12:09:09 pm
For the examples here I kept room the room spiting to small sizes.In game it would be better to make them large and greedy. I'm still unsure about a reasonable slicing scheme but in generally the rooms should be reasonably large and they should also try to be as wide open as possible (vector pathing is your friend if you can do it).  A set of rules can translate into code which would translate into a map.The advantage of a room method would be that you can keep subdividing the map into a simpler  map . The room method also allows for arbitrarily large worlds without major loss of FPS due to long paths. The main disadvantage is the amount of coding and design it would take to create it.

In most of the examples here I'd group it all into 1 or 2 nodes .  The grouping system simplify long range travel. Short range traveling is generally too simple to even consider. Even with the A* worst case example you don't really need a lot of rooms - you just need to turn it from a west ->east problem to a south-> east->north problem . As I said room system is a very complicated solution but it has major advantages.

A path caching to way-points scheme is very easy to add. Toady can give the user a set of 20 waypoints  and he'll save caches of all the paths between them . This way first thing anyone pathing would do is call the heuristic about 1+2*20 times. once for source destination and then 20 src<->waypoint and 20 dst<->waypoint.  With smart placement the players can simplify very long distances into a very simple highway.  With this system you got 1 major advantage - no complicated placement scheme and very a deterministic code .  The players would plant the waypoints and they would generate a huge FPS gain .


edit : minor changes to my simple test program (http://niseg.0adz.com/test_maze.html) (too lazy to rewrite it)
- added ability to add waypoints
- added ability to set start point
- added ability to set destination point
- the bfs now search from start point if it's valid

edit2: another major update to my test program - started using some simple CSS  ;)
- squared the maze
- added A star NAVIGATION I got from 46 dogs's blog( I got reference to it on the page)
- added path highlighting

edit3:
- Path caching done using user set waypoints (display processing time for generation)
- Find path renamed to Find Path A*
- "Find Path using  waypoints" was Added. This uses the path cache to generate path from source to destination it's about a factor of 10 faster than a* with good placement. there is no path smoothing yet. it uses the method I described above to find 2 intermediate to the cached path.
- removed the bfs maze to prevent confusion


have fun
edit4: future plans:
-expand the maze... done~

-add a better save/load function ...in progress
-add path cache size and optimized cache size(it currently saves 4byte per steps and I want to change it to 4bits per step or less)
-path smoothing to prevent zigzag into the waypoint (haven't looked into how it's done but shouldn't be tough)
-when the maze is bigger we'll talk  about optimizations , automatic placement  etc ;) small mazes have their limitations....
- the room splitting pathing algorithm is up next ... :o
edit5:
- expanded the grid to 32X32  nodes (framed in 34X34 box)
- modified save/load function to support loading  old format and save/load new v01 format :v01RRCCM* R=rows C=columns M= HEX representation binary maze data.
- fixed some waypoint deleting bugs not updating cache correctly - there is still a bug when 1 waypoint is closest to both source and destination
- forum output now shows the contents of the maze which include waypoints an start/destination
-changed waypoint symbol from '$' to 'w'.
more future stuff I'll add:
-load parameter shrinking(it's huge now) - run length encoding,  LZW or switch to b64(256-> 170 byte)
-load maze from edit box (quick pasting to forum)
-maze size  scaling (or something) and maze forum output scaling
-maybe better maze visuals .
-clickable "paint tools"
 

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Reelyanoob on April 06, 2011, 06:30:56 am
Just to point out:
You've always been choosing a room division size in order to convenience yourself.  You're not allowed to chose the "best case scenario" for each example.

For example, what if the first step returned this?
[...]
What it the rooms were larger (rather than the quick and dirty 2x3 rooms I made)?

[...]
You know, it's pathetically easy to write code that can flood-fill and detect rectangular areas? Bigger size rooms will make any node or room-based search algorithm far more efficient than pure A*. It's the small rooms / close packed where you would see less % improvement.

EDIT Here's my thoughts on pathing (i might edit this with any refinements) :-

Have each room / hallway keep a list of 'portals' - i.e points or zones connecting to the next room/area. Straight-line pathing can route dwarves from entrance to exit through a zone. No need to declare a specific path - the dwarf uses straight-line pathing through each zone given the constraint that zones are contiguous recatangles this can be done in realtime very fast.

Store only a list of zones which must be traversed, greatly reducing memory use. For pathing costs during the search for a good node-to-node path, use the distance from the incoming portal to the exit portal within each zone. Dwarves travelling would only need to remember the list of zones still to come, and only need to reference the current/next zones and walk straight towards the portal for the new zone.

Mark the portals(only) in the tiles they occupy, this is so that locking a door / adding a wall can trigger changes in node info on each side (the rest of the portal can be checked to see if it still allows travel).

If manually adding the zones is the chosen implementation, or if single-square nodes are used, then there may be gaps between zones. This is where storing the path on the map tiles themselves would be handy, when a door on a known path is locked or a wall built, the system would try to find a new path between the zones using normal A*, rejecting paths if they venture into other known zones (or hit a node with a better existing path to the destination), and severing the (direct) link completely if no route is found.

My last suggestion is - overlapping zones. e.g zones would include the walls surrounding them, the overlap areas would become the portals used for navigating, this would need no (or less) special markers to place on the map.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 06, 2011, 07:40:59 am
Just to point out:
You've always been choosing a room division size in order to convenience yourself.  You're not allowed to chose the "best case scenario" for each example.

For example, what if the first step returned this?
[...]
What it the rooms were larger (rather than the quick and dirty 2x3 rooms I made)?

[...]
You know, it's pathetically easy to write code that can flood-fill and detect rectangular areas? Bigger size rooms will make any node or room-based search algorithm far more efficient than pure A*. It's the small rooms / close packed where you would see less % improvement.

You should check previous page . Shape is no longer an Issue(using a bit vector). you can floodfill any shape using  a depth limited Breadth First search the issue is where to start and not to miss any open space. my idea for room splitting is this:

-arbitrarily divide  map  into flat squares
- block off each square with walls and make sure every node in it  can reach any other node.
- split  unreachable areas into new rooms
- make a connection graph between rooms (you can do collision detection BFS)
- merge smaller rooms into larger rooms with some size limit. It might be smart to keep ones with up/down access as exceptions.

Then when you search for a path you look for a room to room path. instead of a point to point path.

This is a better system than waypoint based path caching but it takes more work to add . I'm going to add this method to my JS demo but it would take me some time to do.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 06, 2011, 02:51:22 pm
Have each room / hallway keep a list of 'portals' - i.e points or zones connecting to the next room/area. Straight-line pathing can route dwarves from entrance to exit through a zone. No need to declare a specific path - the dwarf uses straight-line pathing through each zone given the constraint that zones are contiguous recatangles this can be done in realtime very fast.
How will you define the cost of moving from one portal to another? How will you define the A* heuristic?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Talonj on April 06, 2011, 07:40:23 pm
If I'm reading this thread correctly, there are three major ideas, each of which seems misunderstood by people discussing the other ideas...

The first is NW_Kohaku's hierarchical structure, which I don't fully understand myself.
Second is Niseg's, which I'd like to elaborate on a bit:

On embark:
1. Split the map into arbitrary N x M x O rectangular prisms (perhaps set as an init option, I will refer to them as cubes for convenience)
Then, for each cube:
2. Run Niseg's BFS search idea on a random node to ensure all open space within the cube is reachable.
3. All tiles highlighted by this BFS search are assigned to a node.
4. if there are more open space tiles left, go to 2.

Now you have a significantly smaller map to search through to find a general path, though each individual tile will still need to be searched for the actual path.
Use cases for this idea:
A) Mining a tile
1. Update the adjacency map (current system, discussed earlier in the thread)
2. Check all tiles adjacent to the current tile AND within the mined nodes cube.
3. Add this tile to the first found adjacent node.
4. If there is another adjacent node within the cube, combine the two nodes.

B) Pathing from a mason's shop to a stone
1. Find the stone using the item finding heuristic
2. Look at what node the tile the stone is on is in.
3. Look at what node the tile the dwarf is currently standing on is in
4. Use A* on the node structure to find the ideal path to the object, if this fails there is no path
Then, on each individual node:
1. If the item being searched for is NOT in the current node: from the algorithm's current position (initialized at the current position of the dwarf), use the item finding heuristic (restricted to the set of "all tiles on the edge" for the node) to find the nearest tile marked as an entrance into the target node OTHERWISE path to the square (containing the item) already found in the last search and end the search
2. Take one step toward the next node in the sequence, putting you inside that next node, then return to 1 until search ended

Notes:
 I chose arbitrary blocks to swiftly streamline the creation of nodes. If nodes were allowed to grow to arbitrary size, then the process of breaking them up into blocks small enough to be meaningful while also large enough to be effective would become significantly more difficult. There are certainly ways to create more efficient nodes, however there is not a more efficient way (That I can think of) to create nodes in general.
The other reason for arbitrary block size is that it allows a uniform "cost" to be assigned to each node and still have a reasonable closeness to the true cost of pathing through the node. Yes, this will result in sub-optimal paths being used, and used frequently, but the speed at which the paths will be found will improve significantly. You COULD save the true cost between every pair of nodes, but that's using a lot of memory, because one node can connect to quite a few other nodes, even with the "block" limitation.
Also, if the cube size is set as an init option, you can go as low as 2x2x2 and still reduce the number of total searchable nodes (compared to the current system) by anywhere from a factor of 2 to 8. As the cubes grow smaller, the possibility for winding paths and such grows smaller, which makes each node having the same cost more likely.
edit: Also, this would unfortunately significantly hinder the benefits of current pathfinding designations. The only feasibly quick way to do it would be that either the lowest or the highest of all path designations would be applied to the whole node. Or it could be done by the count of such designated tiles within the node. Also, while I was realizing this, I hit upon an idea... Apply the same concept to individual objects. Have each node have the status that it "contains microcline blocks" or "contains steel bars" and then use the overall heuristic based on the nearest node to do this. Depending on how the nodes end up being laid out, it might end up being feasible to do a BFS from the dwarf's current node to the first node found containing the material he's looking for. dwarves that know the specific destination they're pathing to, such as the bedroom, would obviously use the A* heuristic method, but the manhattan distance item finding heuristic has bothered a lot of people.


To summarize:
This algorithm will require each node to keep track of each exit to another node from each individual tile.
This algorithm will significantly improve the WORST CASE in A* of searching down every path with the manhattan distance heuristic. It will instead search down every dead end node, and since there are a logarithmically smaller number of nodes than tiles, this is still MUCH faster.
This algorithm will NOT improve the best case, since you still need to A* through each individual node, once the general path is found.
The overhead from this algorithm is relatively small, but it does not replace the current system, only adds to it, which means it is GUARANTEED to add at least some overhead. (You can of course do it in different ways that may replace the current system, but I don't know if they'd be faster. Feel free to call me out on it if there is a faster way)

Note2: Yes, this says almost exactly what Niseg's last post says, except with cubes. I just wanted to add on use cases for creating a new tile / using the grid to make it more readable, and also point out that it does not improve the best case, unlike what follows.

The third is Mohicans, which bears many similarities to Niseg's, but is fundamentally different.

The primary difference is in the use of convex polyhedrons, allowing the elimination of A* on a tile-by-tile level. The problem is in the creation of these convex polyhedrons. The problem does not, as some seem to believe, lie in creating nodes from already dug out rooms -- The problem is to create nodes while digging out rooms. Niseg's idea makes it easy, because there is no prerequisite for a tile being included in a node, you just check for an adjacent node and add to it. However, with this idea, unless a highly efficient algorithm to create and merge nodes is used, the overhead may outweigh the benefit, and the benefit may be mitigated by highly suboptimal shapes.
However, with that said, I highly favor speculation on this idea, because it would vastly improve pathfinding overall, as the vast majority of A* searching would be eliminated entirely, since instead of searching through each node, you simply walk in a straight line to the "gate" to the next node, because the whole point is that the nodes are designed in a way so that there is no pathfinding needed to traverse them, just a straight line.

I can elaborate more on this for people who don't understand (as this is the best idea if an efficient method of creating effective nodes can be found). I just don't have the time right now to demonstrate exactly the faults with currently suggested methods of creating these nodes.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 06, 2011, 11:08:04 pm
The hierarchical structure I was talking about is just a method of using search trees as a data structure to organize the connectivity of nodes and speed up inter-node pathing.  It doesn't have anything to do with intra-node pathing or zoning.

Basically, I was thinking of a Binary Search Tree as inspiration for it, and how that helps speed up searches.

Instead of making a standard connectivity grid for nodes, and then using a pathfinding program to search for a path, you create a tree data structure where connectivity is recorded in the pointers from one branch in the tree to the next. 

Searching a tree data structure is much easier than trying to pathfind through them, so it can abstractly find a set of nodes to path through very, very quickly with the minimum possible number of memory fetching. 

The data structure itself would kind of get bloated with pointers, depending on how you want to set it up - you basically can trade memory for speed and making better pathing decisions.

However, as I said before, this is talking solely about how to figure out which nodes to transverse once you have already set up the map, and doesn't even handle the size or shape of the nodes or intra-node pathing or anything besides the highest-level abstract pathing between nodes.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Reelyanoob on April 06, 2011, 11:35:56 pm
Have each room / hallway keep a list of 'portals' - i.e points or zones connecting to the next room/area. Straight-line pathing can route dwarves from entrance to exit through a zone. No need to declare a specific path - the dwarf uses straight-line pathing through each zone given the constraint that zones are contiguous recatangles this can be done in realtime very fast.
How will you define the cost of moving from one portal to another? How will you define the A* heuristic?
I covered that detail in my post (there was quite a bit of text though) - the cost to navigate through a rectangular zone portal => portal would be the dist from portal->portal in the zone, since zones are defined as openly connect rectangles this is a good estimate of the path cost. That would be added to the "path so far" for the graph A* is searching.

The heuristic for remaining distance to the target would be calculated in the normal A* way (with the additional check of 'is the target INSIDE this zone? - actually the dest zone ID could be determined before the search, and the zoneID of each searched zone compared to this ID), this will affect choice of zones to explore first (putting opened zones into the open list/heap). A* will search an arbitrary graph just as easily as it's set to search a grid.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Talonj on April 07, 2011, 01:07:40 am
Have each room / hallway keep a list of 'portals' - i.e points or zones connecting to the next room/area. Straight-line pathing can route dwarves from entrance to exit through a zone. No need to declare a specific path - the dwarf uses straight-line pathing through each zone given the constraint that zones are contiguous recatangles this can be done in realtime very fast.
How will you define the cost of moving from one portal to another? How will you define the A* heuristic?
I covered that detail in my post (there was quite a bit of text though) - the cost to navigate through a rectangular zone portal => portal would be the dist from portal->portal in the zone, since zones are defined as openly connect rectangles this is a good estimate of the path cost. That would be added to the "path so far" for the graph A* is searching.

The heuristic for remaining distance to the target would be calculated in the normal A* way (with the additional check of 'is the target INSIDE this zone? - actually the dest zone ID could be determined before the search, and the zoneID of each searched zone compared to this ID), this will affect choice of zones to explore first (putting opened zones into the open list/heap). A* will search an arbitrary graph just as easily as it's set to search a grid.

The problem is, as stated in my (probably TL;DR) post, in creating the zones in the first place. While it is relatively simple to flood fill random areas until there are no more rectangles to be had, fortresses aren't built all at once, they're dug out or constructed one tile at a time by dwarves who don't enjoy digging things out in a meaningful manner. Obviously, you need to attempt to merge the newly opened tile with nearby rectangles, or, conversely, remove the now-closed tile and split the rectangle up into smaller ones. However, I can't think of any suitably fast ways to do this, and no conclusive algorithms have really been put forth in this thread. (I spent most of my free time before posting consolidating ideas in my head to solidify Niseg's idea, since it is significantly easier to implement)

The hierarchical structure I was talking about is just a method of using search trees as a data structure to organize the connectivity of nodes and speed up inter-node pathing.  It doesn't have anything to do with intra-node pathing or zoning.

Basically, I was thinking of a Binary Search Tree as inspiration for it, and how that helps speed up searches.

Instead of making a standard connectivity grid for nodes, and then using a pathfinding program to search for a path, you create a tree data structure where connectivity is recorded in the pointers from one branch in the tree to the next. 

Searching a tree data structure is much easier than trying to pathfind through them, so it can abstractly find a set of nodes to path through very, very quickly with the minimum possible number of memory fetching. 

The data structure itself would kind of get bloated with pointers, depending on how you want to set it up - you basically can trade memory for speed and making better pathing decisions.

However, as I said before, this is talking solely about how to figure out which nodes to transverse once you have already set up the map, and doesn't even handle the size or shape of the nodes or intra-node pathing or anything besides the highest-level abstract pathing between nodes.

So you're saying that it's a method of searching through zones created by other means? I.e. we can use it on whichever grouping method other come up with? In that case, it's pretty cool, even though I don't really understand it.
In this vein, a short while after editing my wall of text for the second time, I realized that you can actually re-apply Niseg's algorithm on top of itself -- that is, group a cube of cubes of tiles into cubes of nodes, and search those, and create a massive tree structure that lends itself to recursive use of A* -- this would allow both the optimality of 2x2x2 cubes, and the abstraction and swiftness of 16x16x16 cubes, and also possibly make the idea of BFSing for the nearest (larger) node that contains a target material for item searching much more feasible, by then simply using nearest manhattan distance on a list of all items within that large node. There would be additional overhead for both, of course, but I believe it would be worth it, due to the sheer amount of pathfinding done in a mature fortress.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 07, 2011, 03:28:34 am
I think the room splitting algorithm is well defined don't forget the bitvector that defines nodes in a room. the bit vector is one of the major advantage.

example map(folded):
Spoiler (click to show/hide)
room is defined from point t( 2,1) to point b (4,6) with a bit vector :
Spoiler (click to show/hide)
to add 1,3 all we need to do is change t to 1,1 and then grow and regenerate the bit vector . It might be easier to create a new room and then merge it. the new room bit mask is:
Spoiler (click to show/hide)
When the other points are dag out it's just a matter of setting bits. when you wall off the room you can clear bits and at some point shrink the room (not really critical).  with a bitmask you can get an O(1) answer if a node is in a room .

It might be smart to create 3d  rooms and there is nothing stopping you from doing it with this model. It's also scalable to infinity so if your map becomes complicated you can split it farther by grouping its rooms into regions.

Anyways As I said the room splitting model a tad complicated (it's not that bad though most of it is already well defined). I think we should be aiming for path caching first( I have a working simulator) and we might be able to optimize it enough to make it adequate . Path caching is super easy and it can be user guided . If the user want to abuse it to confuse goblinite with silly waypoints he'll just get FPS drops.

There are two improvements I can think of to path caching:

1. directional waypoints.
2.  path smoothing. .

1.  since the simplest model user placed  the waypoints can be directional which would affect the heuristic function that helps selecting waypoints  closest to source and destination. As we all know the heuristic can lie and the shape can fix it. example (http://niseg.0adz.com/test_maze.html?maze=v0108082024B62424762404)(folded):
Spoiler (click to show/hide)
As you see due to the distance from S to the  east waypoint being shorter than the distance to the south  waypoint it would pick the wrong waypoint . Same with the destination D this cause the waypoint path finding to be worst than A*. by changing the huristic to give a directional penalty (can be automatic if wp is by a wall) it would help it pick a better waypoint.

Waypoint picking need to be smarter than heuristic but it should also try not to be too complex.

2. Path smoothing is a very important part of any waypoint system so anyone navigating using a waypoint won't have to go through the waypoint and only use it as a guide. This can be done by some simple function that intelligently picks 2 points and use depth  limited A* to make the path smoother . example  (http://niseg.0adz.com/test_maze.html?maze=v010A0A007DF005FF015FD08421007FF) (folded)
Spoiler (click to show/hide)
You see that here you got a zigzag from S to upper waypoint. S goes to the waypoint and then backtrack and then it goes to the next waypoint and backtracks to the destination.

This example isn't too good because it is bad waypoint placement but there are other examples where you got extremely long path you just need to smooth out the two ends.
 
Anyways I have decent progress with my simulator I do have a few minor bugs I gotta iron out and I also need to fix some structure ( like move the few instructions I added) . I'll probably start a new thread about it.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Talonj on April 07, 2011, 03:57:51 am
I think the room splitting algorithm is well defined don't forget the bitvector that defines nodes in a room. the bit vector is one of the major advantage.

example map(folded):
Spoiler (click to show/hide)
room is defined from point t( 2,1) to point b (4,6) with a bit vector :
Spoiler (click to show/hide)
to add 1,3 all we need to do is change t to 1,1 and then grow and regenerate the bit vector . It might be easier to create a new room and then merge it. the new room bit mask is:
Spoiler (click to show/hide)
When the other points are dag out it's just a matter of setting bits. when you wall off the room you can clear bits and at some point shrink the room (not really critical).  with a bitmask you can get an O(1) answer if a node is in a room .

It might be smart to create 3d  rooms and there is nothing stopping you from doing it with this model. It's also scalable to infinity so if your map becomes complicated you can split it farther by grouping its rooms into regions.

Anyways As I said the room splitting model a tad complicated (it's not that bad though most of it is already well defined). I think we should be aiming for path caching first( I have a working simulator) and we might be able to optimize it enough to make it adequate . Path caching is super easy and it can be user guided . If the user want to abuse it to confuse goblinite with silly waypoints he'll just get FPS drops.

There's a lot more to rooms than just squares. What about ramps? How about connections and shapes? If there isn't an arbitrary pre-set size cutoff, how will a room know when to split?
If you try to split based off of 1-2 tile wide passageways, what if a 1-2 tile wide passageway is dug out a series of times in a small room, creating many smaller, misshapen "rooms" within one larger room? This would end up with fewer tiles per room than an arbitrary size. Also, I don't see how just having a bit mask makes determining paths O(1)... Or the fact that the node structure is defined using a bit vector means anything at all. Okay, so the node area is stored as a map of boolean values... ... How ELSE would you do it?

Also, you say "to add 1,3 all we need to do is add 1,1 and grow and regenerate the bit vector" What exactly is this growing and regeneration? Just how big of an area are you going to rebuild with every newly created tile / newly walled off tile?

For that matter, path caching is most certainly not the way to go, for several reasons mentioned... Also, not mentioned is that combining these two methods is functionally impossible, since ideally all zones would be invisible to the player and automatically generated, thus setting waypoints would have no effect on the overall path algorithm used because it is not used on actual tiles, but groups of them -- unfortunately this also affects the useful traffic designations, but I think the FPS gain would be worth it. The other problem with path caching is that the overhead of caching paths, with the significantly reduced worst case scenario of the node grouping algorithms, may actually exceed the possible gains simply because the sheer number of paths needing to be cached.

Also, what you are doing there seems to be using the same zone theory and simply letting the player designate "zone" areas by using waypoints -- since the waypoints are in fact not even being used to cache paths anymore, if a dwarf is not standing exactly on top of the waypoint, he cannot use a cached path. Are you trying to cache paths starting from all points within a certain distance from the waypoint? Because that would quickly become exponentially more complicated...

The intent of my post was to create discussion on the potentially BETTER algorithm -- how to create the convex polyhedrons used within the navmesh algorithm, which is significantly more complex than just creating arbitrarily shaped rooms.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 07, 2011, 05:09:53 am
There's a lot more to rooms than just squares. What about ramps? How about connections and shapes? If there isn't an arbitrary pre-set size cutoff, how will a room know when to split?
The ramp just means a path upwards the bitmask is just to say if the node is in a room or not.  There is no problem with overlapping rooms and they would never cover the same nodes. You can even define a room within a room. The spliting size should be big enough to be useful but small enough that you won't make path search too complex.

If you try to split based off of 1-2 tile wide passageways, what if a 1-2 tile wide passageway is dug out a series of times in a small room, creating many smaller, misshapen "rooms" within one larger room? This would end up with fewer tiles per room than an arbitrary size. Also, I don't see how just having a bit mask makes determining paths O(1)... Or the fact that the node structure is defined using a bit vector means anything at all.
I didn't talk about O(1)  path finding but it's possible in a room system. I was talking about O(1) validation: "is the point in the square and is it's bit set.". I'm not sure how you'll search your start and destination rooms but those are not that bad even if you use a linear search.

smaller rooms are not a problem the can be group into 1 bigger room that contains them. The bitmap allows any shape rooms which makes it very flexible in terms of adding nodes while still having a "square" shape which make it easy to tell if the point is within it or not.


 Okay, so the node area is stored as a map of boolean values... ... How ELSE would you do it?

Also, you say "to add 1,3 all we need to do is add 1,1 and grow and regenerate the bit vector" What exactly is this growing and regeneration? Just how big of an area are you going to rebuild with every newly created tile / newly walled off tile?
This is the kind of optimizations i'll leave for later. In general if room structure changes I'll regenerate it  - it's not as bad as you think in terms of runtime.

For that matter, path caching is most certainly not the way to go, for several reasons mentioned... Also, not mentioned is that combining these two methods is functionally impossible, since ideally all zones would be invisible to the player and automatically generated, thus setting waypoints would have no effect on the overall path algorithm used because it is not used on actual tiles, but groups of them -- unfortunately this also affects the useful traffic designations, but I think the FPS gain would be worth it. The other problem with path caching is that the overhead of caching paths, with the significantly reduced worst case scenario of the node grouping algorithms, may actually exceed the possible gains simply because the sheer number of paths needing to be cached.

Also, what you are doing there seems to be using the same zone theory and simply letting the player designate "zone" areas by using waypoints -- since the waypoints are in fact not even being used to cache paths anymore, if a dwarf is not standing exactly on top of the waypoint, he cannot use a cached path. Are you trying to cache paths starting from all points within a certain distance from the waypoint? Because that would quickly become exponentially more complicated...

I was also skeptical about the path caching method at first till I kept looking at it. I explained how it works in previous pages. if you want to get to S->D you can do it through 2 waypoints w1 and w2 which have a full path cache then the only thing you need to do is find the closest waypoints to S and D and find paths to them from S and D. You might think it's not worth it and it's memory consuming but with good waypoint placement you can reduce the number of nodes visited from 60% to 5%. keeping the paths to the waypoint  short can  improve  the pathfinding algorithm complexity by a factor of 10.

Adding waypoint based pathfinding navigation is very easy  to do and the gains from it would be major. I know that room spliting is a better system but it would take us some time to make it work.


The intent of my post was to create discussion on the potentially BETTER algorithm -- how to create the convex polyhedrons used within the navmesh algorithm, which is significantly more complex than just creating arbitrarily shaped rooms.

constructing  nav mesh seems complicated and It could have too much memory and overhead use in case of  many "teeth" .
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 07, 2011, 09:39:13 am
The problem is, as stated in my (probably TL;DR) post, in creating the zones in the first place. While it is relatively simple to flood fill random areas until there are no more rectangles to be had, fortresses aren't built all at once, they're dug out or constructed one tile at a time by dwarves who don't enjoy digging things out in a meaningful manner. Obviously, you need to attempt to merge the newly opened tile with nearby rectangles, or, conversely, remove the now-closed tile and split the rectangle up into smaller ones. However, I can't think of any suitably fast ways to do this, and no conclusive algorithms have really been put forth in this thread. (I spent most of my free time before posting consolidating ideas in my head to solidify Niseg's idea, since it is significantly easier to implement)

Actually, I have covered that (http://www.bay12forums.com/smf/index.php?topic=76278.msg2097555#msg2097555). :)

But people don't like to give my method any merit, despite the fact that it's the only way that even makes sense.  We go side tracked on this "bitmask" think which is pointless and useless.  All that's really doing is covering how the navigation mesh is stored in memory (which is irrelevant) and not how it's built or used.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Talonj on April 07, 2011, 10:48:28 am
The problem is, as stated in my (probably TL;DR) post, in creating the zones in the first place. While it is relatively simple to flood fill random areas until there are no more rectangles to be had, fortresses aren't built all at once, they're dug out or constructed one tile at a time by dwarves who don't enjoy digging things out in a meaningful manner. Obviously, you need to attempt to merge the newly opened tile with nearby rectangles, or, conversely, remove the now-closed tile and split the rectangle up into smaller ones. However, I can't think of any suitably fast ways to do this, and no conclusive algorithms have really been put forth in this thread. (I spent most of my free time before posting consolidating ideas in my head to solidify Niseg's idea, since it is significantly easier to implement)

Actually, I have covered that (http://www.bay12forums.com/smf/index.php?topic=76278.msg2097555#msg2097555). :)

But people don't like to give my method any merit, despite the fact that it's the only way that even makes sense.  We go side tracked on this "bitmask" think which is pointless and useless.  All that's really doing is covering how the navigation mesh is stored in memory (which is irrelevant) and not how it's built or used.

You have covered an incredibly general algorithm, however "cluster into nodes" is not language specific enough to write into code, unfortunately. That's the sort of specificity I'm looking for -- If we want to even think about getting Toady to implement any of these (And I know that's a dream hiding in all of our hearts) -- we need at least some basic pseudocode, that I attempted in my post, but I know I left out a few important steps even then. The idea of creating a separate map for each pathing type is a good one, yes, as is the idea of giving workshops their own nodes, though I don't know if that is actually necessary.

Like I said in my post, the nodes are just an invisible abstraction rather than waypoints to frequently used structures. They need to be small enough that an algorithm searching on the tile level does not need to search very many dead ends, but large enough to significantly cut down on the searches done. That's why I think the arbitrary cube slicing has merit -- they don't need to be sensibly shaped, they just need to be groups that are searched with one single comparison in A*.

Also, if you look to my just previous post, you'll see me expressing my own confusion on getting hung up over how the vector is stored in memory has anything to do with algorithms ;D

snip
The ramp just means a path upwards the bitmask is just to say if the node is in a room or not.  There is no problem with overlapping rooms and they would never cover the same nodes. You can even define a room within a room. The spliting size should be big enough to be useful but small enough that you won't make path search too complex.

My point is that ramps upward represent a straight line in terms of games and should ideally be contained in a single room. This would significantly cut down on the number of nodes for those embarks that are nearly nothing but ramps. Also, my question is exactly when to split? Under what conditions? Tile count within a node = 30? Length = 5x width? The pink elephants have come to play? If you're even going to think about implementing this anywhere, there need to be details! So many more details, and most of what you have been posting recently have sadly been vague generalities.

If you try to split based off of 1-2 tile wide passageways, what if a 1-2 tile wide passageway is dug out a series of times in a small room, creating many smaller, misshapen "rooms" within one larger room? This would end up with fewer tiles per room than an arbitrary size. Also, I don't see how just having a bit mask makes determining paths O(1)... Or the fact that the node structure is defined using a bit vector means anything at all.
I didn't talk about O(1)  path finding but it's possible in a room system. I was talking about O(1) validation: "is the point in the square and is it's bit set.". I'm not sure how you'll search your start and destination rooms but those are not that bad even if you use a linear search.

I see I misread you there, but O(1) validation can be acquired as simply as adding a pointer to the Tile structure that points at its node. That simple. It shouldn't even ever have come to discussion, really.

smaller rooms are not a problem the can be group into 1 bigger room that contains them. The bitmap allows any shape rooms which makes it very flexible in terms of adding nodes while still having a "square" shape which make it easy to tell if the point is within it or not.

Under what conditions? When does a room join? Immediately until reaching the splitting size, I would assume, but even that is undefined. Keep in mind, as in my previous reply, that the idea isn't to create landmarks for the nodes, it's just to cut down the search space.


 Okay, so the node area is stored as a map of boolean values... ... How ELSE would you do it?

Also, you say "to add 1,3 all we need to do is add 1,1 and grow and regenerate the bit vector" What exactly is this growing and regeneration? Just how big of an area are you going to rebuild with every newly created tile / newly walled off tile?
This is the kind of optimizations i'll leave for later. In general if room structure changes I'll regenerate it  - it's not as bad as you think in terms of runtime.

That's not an optimization, it's the core of the algorithm. If building a node and referencing the resulting structures takes up too much longer than the current method, we are trading pathfinding optimization for landscape changing optimization. If we ever get moving fortress parts, and a few other updates, landscape changing is going to happen more and more frequently. It already happens at an incredible rate. Before even being considered viable, it needs to be as detailed as possible, to ensure it's even better than the current method.

For that matter, path caching is most certainly not the way to go, for several reasons mentioned... Also, not mentioned is that combining these two methods is functionally impossible, since ideally all zones would be invisible to the player and automatically generated, thus setting waypoints would have no effect on the overall path algorithm used because it is not used on actual tiles, but groups of them -- unfortunately this also affects the useful traffic designations, but I think the FPS gain would be worth it. The other problem with path caching is that the overhead of caching paths, with the significantly reduced worst case scenario of the node grouping algorithms, may actually exceed the possible gains simply because the sheer number of paths needing to be cached.

Also, what you are doing there seems to be using the same zone theory and simply letting the player designate "zone" areas by using waypoints -- since the waypoints are in fact not even being used to cache paths anymore, if a dwarf is not standing exactly on top of the waypoint, he cannot use a cached path. Are you trying to cache paths starting from all points within a certain distance from the waypoint? Because that would quickly become exponentially more complicated...

I was also skeptical about the path caching method at first till I kept looking at it. I explained how it works in previous pages. if you want to get to S->D you can do it through 2 waypoints w1 and w2 which have a full path cache then the only thing you need to do is find the closest waypoints to S and D and find paths to them from S and D. You might think it's not worth it and it's memory consuming but with good waypoint placement you can reduce the number of nodes visited from 60% to 5%. keeping the paths to the waypoint  short can  improve  the pathfinding algorithm complexity by a factor of 10.

Adding waypoint based pathfinding navigation is very easy  to do and the gains from it would be major. I know that room spliting is a better system but it would take us some time to make it work.

I'm not too sure how waypoint pathfinding would be easier to code than node grouping. Add in the algorithm to slice nodes, add the data structures and associated functions, change the initial pathfinding algorithm to work on nodes, then copy paste the pathfinding algorithm and loop it through each individual node. It is, of course, a little more complicated than that, but it's at least largely using an existing system. Creating path smoothing waypoints seems a little more complicated to me, but that may not be the case. I haven't seen the actual source code, after all. Regardless, my point was and still is, if you spend the time to implement waypoint path caching, you will have to scrap ALL OF THE CODE when switching over to room nodes, because they are INCOMPATIBLE.


The intent of my post was to create discussion on the potentially BETTER algorithm -- how to create the convex polyhedrons used within the navmesh algorithm, which is significantly more complex than just creating arbitrarily shaped rooms.

constructing  nav mesh seems complicated and It could have too much memory and overhead use in case of  many "teeth" .

As I outlined in my first post, the ONLY difference between navmesh and your idea is that navmesh has a restricted shape for the node size. I don't know what you mean by teeth. The memory use will be slightly higher, only because the number of nodes will probably be higher, but the point is is that it is an order of magnitude faster than the current method, so the overhead while pathfinding is meaningless. If we can find a method that deals with the frequently changing landscape in a sane manner that has as little overhead in that area as possible, it would without a doubt be THE ideal method.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 07, 2011, 11:34:06 am
A nav mesh is a special case of node grouping where the rooms have a shape of some polygon.  polygons means some floating point stuff and complex operations like division and multiplication but it might not be that bad.

A Nav mesh uses "convex polygons" and triangles so I guess we can do something like that . I'm still not sure how we'll cover all the nodes with shapes. "teethed " regions would be majorly problematic.
little example:
Spoiler (click to show/hide)
I'm counting here over 12 nodes created for a mesh and that's a lot of data . Node grouping can do it in 1 or 2.  Other than that those meshes are usually used to convert open areas into a graph which is navigated with A*. Those polygons are usually also hand drawn.

I think that with a mesh you might have the problem that maintaining it would be complicated and as you dig through your port you get crazy shapes and the nav mesh generator would keep trying to fit those polygons in which would be counter productive. I can try to write a simulation for it but it would take some research. I haven't found any source code that relates to nav mesh generation and its dynamic maintenance . I might want to look at RTS or something.

I'm not a big expert in discrete math and graph algorithms . I just know the basic and how to put things together. If you give me code I can read it and understand how it works.I did find some stuff on the internet. As I said I'm going to perfect my waypoint navigator before switching an approach .

You are welcome to write some source code in any language or show me an existing project that does automatic navmesh generation. I don't think it's worth the trouble but I was  previously a big skeptic of the path caching approach and now became an advocate of it. It's not as memory intensive as you think and its gains in CPU time are huge.
 
As I said before A* can be fooled to go the wrong way. This is especially useful if you want to travel long distances. I made my program A* rather than using identical waypoint because it would be silly to do it and I observed some crazy stuff( I can probably fix it just figured it out  ;)).

Another approach you can take in pathing is to assume you can get anywhere in a straight line and then deal with obstetrical . This generally assumes that if you go toward your target you'll reach it especially if it's on the same level. If you can fly this is what you want to do .

example (http://niseg.0adz.com/test_maze.html?maze=v010B0B1042084508214520C0910204401BFF1

link):
Spoiler (click to show/hide)
If you want to reach from S to D and want to use a streight line point 1 is blocked, 2 and 3 are passable 4 is blocked and 5 is passable .

A* complexity of this problem is 21. Using my program I can calculate how much complexity it would take to go around the obstacles.  S to 2 = 4, 3 to 5 = 18. This yields higher complexity so it's not always good especially for walker. What a walker can do instead of trying to go around obstacles is think other straight paths from nodes nearby to like the lower case one. The problem with walker is that it's still trying to shoot through a needle hole but in open areas you can get to your target fairly fast. The other issue with A* is the amount of overhead in the algorithm and visiting a node has a lot more involved than checking it's passable.

I'll have to respond to Talonj later I currently don't have the time ;).

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 07, 2011, 11:49:00 am
I'm counting here over 12 nodes created for a mesh and that's a lot of data . Node grouping can do it in 1 or 2.  Other than that those meshes are usually used to convert open areas into a graph which is navigated with A*. Those polygons are usually also hand drawn.
If you want to reach from S to D and want to use a streight line point 1 is blocked, 2 and 3 are passable 4 is blocked and 5 is passable .

The problem with node grouping is that you still need to do local A* to travel inside a single node.  With a navigation mesh of convex polygons you do not.
You're trading RAM (cheap) for CPU (expensive).

Also, it's very easy to merge tiles into nodes as they are dug out.  It has been explained, although it's broken into several parts.
One (http://www.bay12forums.com/smf/index.php?topic=76278.msg2102253#msg2102253)
Two (http://www.bay12forums.com/smf/index.php?topic=76278.msg2102312#msg2102312)
Three (http://www.bay12forums.com/smf/index.php?topic=76278.msg2102566#msg2102566)
Four (http://www.bay12forums.com/smf/index.php?topic=76278.msg2102584#msg2102584)
Five (http://www.bay12forums.com/smf/index.php?topic=76278.msg2102593#msg2102593)

Essentially, take the tile to be added to the nodes, compare with neighboring nodes, find the largest it can merge with and still maintain a convex shape (restricting the algorithm to 45 degree angles, if necessary, to allow for non-square nodes), then attempt to merge that node with its neighbors (repeat as necessary).

Removing tiles works in reverse.  Simply carve (http://developer.valvesoftware.com/wiki/Carve#Carving)* its volume out of the node it is a part of.

*There's a smarter way to carve than the way Hammer does it, although it doesn't save a whole lot.  Basically, determine your first new node, then make the second on the opposite side, rather than around the edge:

Spoiler (click to show/hide)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 07, 2011, 12:12:18 pm
Actually, I have covered that (http://www.bay12forums.com/smf/index.php?topic=76278.msg2097555#msg2097555). :)

But people don't like to give my method any merit, despite the fact that it's the only way that even makes sense.  We go side tracked on this "bitmask" think which is pointless and useless.  All that's really doing is covering how the navigation mesh is stored in memory (which is irrelevant) and not how it's built or used.

That's not true, I assume something basically the same as what you are talking about (although I'm not sure of why the workshops need to be their own node) when I'm talking about any of these things.  If I don't say I support it, it's just because I was assuming that was true.

So you're saying that it's a method of searching through zones created by other means? I.e. we can use it on whichever grouping method other come up with? In that case, it's pretty cool, even though I don't really understand it.
In this vein, a short while after editing my wall of text for the second time, I realized that you can actually re-apply Niseg's algorithm on top of itself -- that is, group a cube of cubes of tiles into cubes of nodes, and search those, and create a massive tree structure that lends itself to recursive use of A* -- this would allow both the optimality of 2x2x2 cubes, and the abstraction and swiftness of 16x16x16 cubes, and also possibly make the idea of BFSing for the nearest (larger) node that contains a target material for item searching much more feasible, by then simply using nearest manhattan distance on a list of all items within that large node. There would be additional overhead for both, of course, but I believe it would be worth it, due to the sheer amount of pathfinding done in a mature fortress.

What you are talking about is multi-tiered pathfinding - something that can make sense, based upon certain assumptions of how complex a map will be.

What I'm talking about with a tree data structure, however, is a tree data structure (http://en.wikipedia.org/wiki/Tree_(data_structure)), which means it's inherently hierarchical.  Trees contain branch nodes which are fully functional as smaller trees, themselves. 

It's not all that complicated if you consider it - Once you have a grand list of nodes that you have cut the map up into, you have to start organizing them.  You pick some arbitrary node near the middle of the map (you would need to be able to "balance" the tree later on, anyway, so starting from an arbitrary point is fine for now), and make that the root node.  Let me use an older diagram for this:

Spoiler (click to show/hide)

The root node here is the central stairwell that is in bright red. 

Pointers are stored in a vector (a sad necessity, as you can have arbitrary numbers of connections) to all nodes the root node can connect to. 

These are the doors that splay out from the central stairwell (darker red).

These connect to branch nodes, themselves (the red-orange square hallway around the central stairway), and then to other nodes (the orange hallways leading away from the central stairwell), then to others (yellow-orange doors and minor hallways), then to others (some of the yellow rooms or doors off of minor hallways), etc.

Now, you have a data structure where connectivity is implied through the presence of pointers to given nodes.  This isn't all that different from most other meshes or other means of pathfinding at this point, except that we don't really care about the relative locations of any given nodes (east, west, up, down, doesn't matter, just connection matters).

Now, we need to put in the two things we need that lets us actually do the basic pathfinding. 

Each node needs to store with its pointers the length of the path through it, the width of the path through it, and the type of movement it requires (I.E. walking, swimming, flying). 

Further, in order to make the search possible without advanced pathfinding, each branch node needs to store some form of list (maybe a hash to be faster?) that contains all of the leaves and branches that are "higher up" ("higher" means away from the roots, towards leaves) the tree from itself that it can connect to through only moving up the tree from where it is. 

This last point is where this method becomes faster, but also takes up more memory than other pathfinding methods, the hash list would involve lots of duplicate references to nodes.  This would have to be as compressed as possible (Just a reference to a specific node) to save on memory. 

Now, in order to search this tree, you start from the starting node, and search the hash list of branches and leaves connected to the starting node.  If the destination node is not in that list, you go down a node on the tree, and search the lower node that connects to the starting node, and see if you can reach the destination node by only going up from there.  If that doesn't work, you keep going down the tree all the way to the roots until you can find a path to the destination node.

Once you find a branch with a connection to the destination node, you just go up the tree, testing which branches will have connections to the destination node, until you finally strike the destination node, itself.

The list of nodes you had to go down and then up is a valid path to the destination. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Talonj on April 07, 2011, 02:40:42 pm
Essentially, take the tile to be added to the nodes, compare with neighboring nodes, find the largest it can merge with and still maintain a convex shape (restricting the algorithm to 45 degree angles, if necessary, to allow for non-square nodes), then attempt to merge that node with its neighbors (repeat as necessary).

Most of those links before were reiterating problems with the idea, not exactly the best links to give. I understand that finding the optimal would be difficult, but if you settle for node groupings and merging algorithms that are SO suboptimal that they end up being the current system + overhead from checking every additional node, we'll have a new problem: Digging lag.

I can't think of a simple "merge with largest neighbor" algorithm that wouldn't take up a relatively large amount of time. With just using node grouping, without bothering with convex shapes (which, to reiterate, DOES improve the worst case, but does NOT improve the best case, like this does) you pick an arbitrary neighbor and then add yourself to it. Or, when adding a wall, just remove the tile from the node, simple as that.

You only dig out one tile at a time. That means that new tiles dug out can only be added to a node if that node is a 1 tile wide hallway in the given direction. Also, remember that dwarves dig in seemingly (to the player) random directions (though it's a simple direction preference hierarchy, I think), so breaking the algorithm to build suboptimal nodes wouldn't be as intentional as you believe. You could code the algorithm to these preferences, but since I don't know them off hand, speculation on that is out.

I'm saying that, if we want to make this a feasible idea, we need to put together a step by step exactly what parameters of each tile/node will be checked, in which order, to merge nodes. I can't think of such a step-by-step algorithm for the navmesh convex polyhedrons. I can for arbitrary rectangular prisms subdivided into accessible regions, which is what I outlined in my first post.

A nav mesh is a special case of node grouping where the rooms have a shape of some polygon.  polygons means some floating point stuff and complex operations like division and multiplication but it might not be that bad.

A Nav mesh uses "convex polygons" and triangles so I guess we can do something like that . I'm still not sure how we'll cover all the nodes with shapes. "teethed " regions would be majorly problematic.
little example:
Spoiler (click to show/hide)
I'm counting here over 12 nodes created for a mesh and that's a lot of data . Node grouping can do it in 1 or 2.  Other than that those meshes are usually used to convert open areas into a graph which is navigated with A*. Those polygons are usually also hand drawn.

I think that with a mesh you might have the problem that maintaining it would be complicated and as you dig through your port you get crazy shapes and the nav mesh generator would keep trying to fit those polygons in which would be counter productive. I can try to write a simulation for it but it would take some research. I haven't found any source code that relates to nav mesh generation and its dynamic maintenance . I might want to look at RTS or something.

I'm not a big expert in discrete math and graph algorithms . I just know the basic and how to put things together. If you give me code I can read it and understand how it works.I did find some stuff on the internet. As I said I'm going to perfect my waypoint navigator before switching an approach .

You are welcome to write some source code in any language or show me an existing project that does automatic navmesh generation. I don't think it's worth the trouble but I was  previously a big skeptic of the path caching approach and now became an advocate of it. It's not as memory intensive as you think and its gains in CPU time are huge.
 
As I said before A* can be fooled to go the wrong way. This is especially useful if you want to travel long distances. I made my program A* rather than using identical waypoint because it would be silly to do it and I observed some crazy stuff( I can probably fix it just figured it out  ;)).

Another approach you can take in pathing is to assume you can get anywhere in a straight line and then deal with obstetrical . This generally assumes that if you go toward your target you'll reach it especially if it's on the same level. If you can fly this is what you want to do .

example (http://niseg.0adz.com/test_maze.html?maze=v010B0B1042084508214520C0910204401BFF1

link):
Spoiler (click to show/hide)
If you want to reach from S to D and want to use a streight line point 1 is blocked, 2 and 3 are passable 4 is blocked and 5 is passable .

A* complexity of this problem is 21. Using my program I can calculate how much complexity it would take to go around the obstacles.  S to 2 = 4, 3 to 5 = 18. This yields higher complexity so it's not always good especially for walker. What a walker can do instead of trying to go around obstacles is think other straight paths from nodes nearby to like the lower case one. The problem with walker is that it's still trying to shoot through a needle hole but in open areas you can get to your target fairly fast. The other issue with A* is the amount of overhead in the algorithm and visiting a node has a lot more involved than checking it's passable.

I'll have to respond to Talonj later I currently don't have the time ;).



First off, you're severely misunderstanding complexity. Complexity is measured in worst case, best case, average case based on some variable (in this case, generally, something to do with the total number of tiles). In A*, all you do is visit one node, then check all surrounding nodes for the node with the lowest of (estimated distance to target from node + cost to move to said node). In DF, all costs are equal, so only a swift coordinate subtraction is required to find the distance. What do you even mean with your second picture anyway? From what I'm reading, it seems like you're picking nodes progressively farther from start waypoint to target waypoint and just computing straight line and then checking to see if there is any straight line path between the nodes, going on until you find one. Explain your algorithm so I can make a slightly less ridiculous conclusion, please...

Also, you're significantly overcomplicating the Navmesh problem. In DF, since we are dealing with discrete tiles instead of open space, there are no floating point calculations to be had. How will you travel across .2376 of a tile anyway? The only thing the algorithm has to deal with is maintaining the polygons. And, for the third or fourth time, my post is asking people to start suggesting ideas for how to create a dynamic navmesh maintenance algorithm. The navmesh is better. There can never be an argument against that, it lowers best and worst case complexities by an order of magnitude. It will reduce the whole of pathfinding down another logarithm.

Also, I looked and there isn't really much easily findable literature on automatic, dynamic generation and maintenance of navmeshes using discrete tiles like we have here. However, it shouldn't be THAT complicated, quite a few have thrown in ideas and tossed around problems already. What we need to do now is compile together a list of individual conditions for the cases of adding and removing a tile that can be translated into code relatively easily.

For example:
Spoiler (click to show/hide)

I can't wrap my head around how to do it efficiently. I don't mean to yell at others to do what I can't, but I know that before we can tout the feasibility and improvements of the navmesh system, we have to outline exactly how it will work, why it is feasible, and, more importantly, if we are to have a chance in hell of convincing Toady to improve the pathfinding algorithm in this way, we need detailed pseudocode that can easily and directly be translated into programming statements.

(I closed my laptop and drove for a half-hour in the middle of this post, so I may have repeated myself a couple of times)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 08, 2011, 12:59:34 pm
Kohaku:
Doesn't your extra storage at each level in the tree negate any gains from having a tree structure in the first place?

And won't the resulting paths be silly when the shortest path is a cross-branch step? For a simple example, consider a map that is only one huge ring-shaped tunnel (or series of rooms). Opposite the root node in the ring will be two nodes which are only connected through the root node - so the path found will go all the way around the ring unnecessarily?

Pardon me if I've misunderstood, but it seems like you're trying to squeeze performance out of pathing that is provably theoretically impossible - unless the map is *actually* a tree, topologically!
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 08, 2011, 01:21:58 pm
You're confusing storage with processing.  Storage we have plenty of, processing we're using too much of.

By storing the data in the tree you trade away CPU usage for more RAM footprint.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 08, 2011, 03:26:41 pm
Kohaku:
Doesn't your extra storage at each level in the tree negate any gains from having a tree structure in the first place?

And won't the resulting paths be silly when the shortest path is a cross-branch step? For a simple example, consider a map that is only one huge ring-shaped tunnel (or series of rooms). Opposite the root node in the ring will be two nodes which are only connected through the root node - so the path found will go all the way around the ring unnecessarily?

Pardon me if I've misunderstood, but it seems like you're trying to squeeze performance out of pathing that is provably theoretically impossible - unless the map is *actually* a tree, topologically!

Draco18s has already responded to the first paragraph, so I'll skip that.

As for the second, you're right - you will return a valid, if theoretically unoptimized path if you simply go for the simplest, fastest, first path you can find.  In some ways, this might be preferable (if you want faster pathfinding, even if it costs you optimal pathfinding in return), but there are ways to return more optimal paths, although they have some costs associated with them.  I simply left them out of that last post I made, because I wanted to keep the post simpler.

In the first method, (let's use Wikipedia's page on trees (http://en.wikipedia.org/wiki/Tree_(data_structure)) for an illustration), let's assume that we found a path in that tree from the "5" node on the bottom left to the "9" node on the right.  This would return a path of "5->6->7->2->5->9", but at the same time, 7 and 5 are connected, so you can cut out the path with 2 inside of it.

When making that original chain of nodes, you basically are only looking for going up and down the tree, not laterally - you go "down" the tree ("down" being towards the roots) until you find a route directly up the tree you can follow.  To do this, you have a list of all the points "up the tree" from a given node.  Once you have that chain, however, you can look for lateral shortcuts by simply comparing all the connections (up, down, or lateral on the tree) that allow a given node to bypass one or more steps in the chain.

This method has a complexity of an additional O(n^2/2) where n is the length of the chain you returned previously.  It winds up with some extra memory calls, but should still be much faster than A*-ing the entire fort.

This will basically return you the previous path, but with a few shortcuts taken where they are found.



The other option is more complex, and will return you an optimal route at a greater cost, especially memory-wise. 

Let's look at the example picture I made earlier, again, because this was something I made to try to illustrate the exact problem you were pointing out in my idea, when I realized it was there.

Spoiler: big picture again (click to show/hide)

The same organizational rules from the previous times I used this graph still apply - bright red stairwell is the root node (or the lowest-level node visible on this level, at least), and the changing colors radiating out from it represent lower levels of nodes (with dividers in the red-orange "ring" hallway to denote different branches on the same layer of the tree).

We path from (S)tart to (F)inish.

This map assumes rectangular nodes and doors as their own personal nodes.

The last method I mentioned will return the blue line.  Although the red line really should go through the other door I punched in the F-room late in making the graph, the red line basically demonstrates an optimal path (going through the southern door would be 1 tile faster). (Also, the F-Room should have been recolored yellow-green instead of just green, as it connects to a yellow door node.)

Now, again, at least in this case, the blue line actually returns a sub-optimal but still acceptably inefficient path.  Rather than going to the central stairwell, it takes the "lateral shortcut" by going from the western red-orange "ring hallway" node to the northern red-orange "ring hallway" node before going back "up the tree" by going through the hallways, door, and finally hitting the green F-room. 

I cannot make a "lateral shortcut" with the pathfinding to use the yellow-orange hallway next to "D" on the map because it is not in the pathfinding chain I originally constructed.

In order to actually make that path potentially show up, I would have to make a much slower, and more complex method of building that chain of connections in the first place.  This means that we are going to have to search for more than just a path, but an optimal path, and this means that we have to start storing much more data to actually search for what is optimal, and what is not. 

For example, we can make the red line a potential returnable path if we were to include the green "F" room as being "up the tree" from the western orange hallway, as well as storing it as "up the tree" from the northern orange hallway - basically duplicating the amount of data. 

This means that every hallway node that connects to a given node higher than its own tier on the tree is recorded as being "directly up from it", which means that all of that area in the northwestern arc between the two big orange hallways has their nodes pointed to in the big hash list of nodes "up the tree" from both hallways. 

This becomes very problematic as you get many more small nodes clogging up the diagram - the size of these lists increases geometrically with the number of layers of nodes we're dealing with if we use this method.  Using some sort of method to trim down on the actual numbers of nodes in the data structure would significantly help trim down the size of the resulting data structure.  Either multiple layers of nodes, or more permissive node-constructing methods would keep the overall size of the tree down. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 08, 2011, 03:27:50 pm
Actually, I think I've thought of a much simpler/better way to explain what this tree system would represent.

Think of your address.  Let's assume you want to get somewhere.  Let's say, oh, 123 Sesame Street, which is in New York City, which is in New York, which is in The United States of America, which is on Earth, which is in the Sol System, which is in The Milky Way Galaxy.

So, if we ask the computer "Can you tell me how to get to Sesame Street?" (sorry, sorry!) we start by asking, "Are we on Sesame Street already?" "No."  OK, then, we have to search a broader area.  We know that Sesame Street is in New York City, so we have to ask, "Are we in New York City already?" "No."  Then we have to look broader still, "Are we in New York State already?" "No." Go further out, "Are we in the USA already?" "Yes."  Well, OK, then, we only have to look as far as traveling inside the USA, and don't have to ask ourselves how to get to the Sol System or rent a space ship or anything. 

From there, we can tell that we are in state , and need to travel on the interstate/national level to get to the New York State area, then into the New York City area on a state level, then onto Sesame Street on a city level, then to the specific address of Sesame Street want to get to on a street level.

This is why this isn't a matter of local pathfinding - it just assumes something else handles local pathfinding for it.  This works better for the longest-range pathfinding, and tells the local pathfinding to stay within the borders of one locality when looking for a path that is within one relatively-sized area instead of another.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 09, 2011, 12:14:13 am
You're confusing storage with processing.  Storage we have plenty of, processing we're using too much of.

By storing the data in the tree you trade away CPU usage for more RAM footprint.
You misunderstand me; I meant that the extra storage has to be searched as well for each node, costing CPU. Even if it's a hash map, if it has to be done for every node it's still going to affect the time complexity.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 09, 2011, 12:18:59 am
Actually, I think I've thought of a much simpler/better way to explain what this tree system would represent.

Think of your address.  Let's assume you want to get somewhere.  Let's say, oh, 123 Sesame Street, which is in New York City, which is in New York, which is in The United States of America, which is on Earth, which is in the Sol System, which is in The Milky Way Galaxy.

So, if we ask the computer "Can you tell me how to get to Sesame Street?" (sorry, sorry!) we start by asking, "Are we on Sesame Street already?" "No."  OK, then, we have to search a broader area.  We know that Sesame Street is in New York City, so we have to ask, "Are we in New York City already?" "No."  Then we have to look broader still, "Are we in New York State already?" "No." Go further out, "Are we in the USA already?" "Yes."  Well, OK, then, we only have to look as far as traveling inside the USA, and don't have to ask ourselves how to get to the Sol System or rent a space ship or anything. 

From there, we can tell that we are in state , and need to travel on the interstate/national level to get to the New York State area, then into the New York City area on a state level, then onto Sesame Street on a city level, then to the specific address of Sesame Street want to get to on a street level.

This is why this isn't a matter of local pathfinding - it just assumes something else handles local pathfinding for it.  This works better for the longest-range pathfinding, and tells the local pathfinding to stay within the borders of one locality when looking for a path that is within one relatively-sized area instead of another.
Yeah, this is the essence of hierarchical pathfinding, and it is pretty much what we do as humans when trying to plan how to get somewhere on a large scale.
The trouble is always how to delineate the different units, though. With cities and planets, at least, it's easy - they're clearly defined and well separated. There's nothing so neat about a Dwarf Fortress map. Rooms are one thing, but how are they supposed to be clustered together into larger units? It's not obvious.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 09, 2011, 12:33:09 am
You misunderstand me; I meant that the extra storage has to be searched as well for each node, costing CPU. Even if it's a hash map, if it has to be done for every node it's still going to affect the time complexity.

It's not extra data for extra data's sake.

Lets put it like this:
You're looking for your keys.  You don't remember where you left them or when it was that you last had them.  They're somewhere in your house.

The current pathfinding method is equivalent to going from room to room to room in your house and itemizing everything in each room, on each shelf in each cupboard and every drawr, one at a time until you locate your keys.  Ok, not quite.  A* does make some generally good guesses about where to search next that makes it slightly better than the analogy here, which is equivalent to either BFS.

The pathfinding optimiations we're talking about are more like this:

You don't know where your keys are...but you do know they're not in the fridge or in the eating utensil drawer.  So instead of searching every square inch of your house you check your pants pockets (usual place), the bedside table (where you left them yesterday), and next to the phone (ah, here they are.  That's right, the phone was ringing when I came in earlier!)

Rather than having to search each tile to find a path, we're instead checking in a more general sense of where to look to start looking.  By having a much smaller search space you increase the search performance by a huge factor.  You're not searching the extra data, but rather using the extra data as a search space.

Hmm.

Like this.  Imagine a huge grid of tiles, featureless plane.  Millions of tiles.  Your job: find the distance from point A to point B by walking on each one and counting, "one, two three..."  It's going to take a while.

Now imagine that every 10 squares there's a thick border.  And every hundred a huge dark border even more recognizable than the one every 10.  You realize that your start and end locations are not only not in the same 10-square, they're not even in neighboring 100 squares!  So rather than counting each tile you generalize.  You count hundred-squares.  You find that there are 4.  Next you count the partial hundred-squares using the ten-squares.  There's 6 of those, two on one end, four on the other.  Finally you count the last remaining distance.  13.  9 tiles on one end, four on the other.  How far's the distance?

One, two, three, four....
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 09, 2011, 06:19:49 am
You misunderstand me; I meant that the extra storage has to be searched as well for each node, costing CPU. Even if it's a hash map, if it has to be done for every node it's still going to affect the time complexity.
Now imagine that every 10 squares there's a thick border.  And every hundred a huge dark border even more recognizable than the one every 10.  You realize that your start and end locations are not only not in the same 10-square, they're not even in neighboring 100 squares!  So rather than counting each tile you generalize.  You count hundred-squares.  You find that there are 4.  Next you count the partial hundred-squares using the ten-squares.  There's 6 of those, two on one end, four on the other.  Finally you count the last remaining distance.  13.  9 tiles on one end, four on the other.  How far's the distance?

One, two, three, four....
Except, of course, in that scheme nothing needs to be stored because the hierarchical structure is implicit. Not so in Kohaku's scheme. If each square at each scale had to keep an explicit list (or hash table) of all the smallest-scale squares that are in it, it wouldn't look so nice anymore.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on April 09, 2011, 08:17:15 am
I am in the mood of writing some code, so I made the "merge node" algorithm, which I used to slice in rectangles some maps (I add all the walkable tiles one by one, like if it was a digged tile).
here is what it gives on some classic maps.

a classic fortress, 304 tiles represented with 14 nodes
Code: [Select]
##################################
###########+++++##################
###########+++++##################
#######+++#+++++#++++++++#########
#######+++#+++++#++++++++#########
#######+++#+++++#++++++++#########
#######++++++++++++++++++#########
###########+++++#++++++++#########
###########+++++#++++++++#########
###########+++++#++++++++#########
###########+++++##################
###########+++++##################
###########+++++##################
###########+++++##################
######++++#+++++##################
######++++#+++++##################
######++++++++++##################
######++++#+++++##################
######++++#+++++##################
######++++#+++++##################
######++++#+++++##################
######++++#+++++##################
######++++#+++++##################
######++++#+++++##################
######++++#+++++##################
######++++#+++++##################
######++++++++++#+++##############
######++++#+++++#+++##############
###########+++++++++##############
###########+++++#+++##############
###########+++++#+++##############
###########+++++##################
###########+++++##################
##################################

Code: [Select]
###################################
###########44444###################
###########44444###################
#######333#44444#11111111##########
#######333#44444#11111111##########
#######333#44444#11111111##########
#######333222222222222222##########
###########55555#77777777##########
###########55555#77777777##########
###########55555#77777777##########
###########55555###################
###########55555###################
###########55555###################
###########55555###################
######<<<<#55555###################
######<<<<#55555###################
######<<<<666666###################
######<<<<#:::::###################
######<<<<#:::::###################
######<<<<#:::::###################
######<<<<#:::::###################
######<<<<#:::::###################
######<<<<#:::::###################
######<<<<#:::::###################
######<<<<#:::::###################
######<<<<#:::::###################
######<<<<888888#===###############
######<<<<#?????#===###############
###########?????9999###############
###########?????#>>>###############
###########?????#>>>###############
###########?????###################
###########?????###################
###################################
###################################

the "corridor", 18 tiles represented by 12 nodes.

Code: [Select]
##################################
##+#+#+#+#+#+#####################
#++++++++++++#####################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################


Code: [Select]
###################################
##1#2#3#4#5#6######################
#718293a4b5c6######################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################


the forest, 234 tiles represented with 33 nodes.
Code: [Select]
##################################
#######++++++++++#################
######+++++++++#+#################
######+#++#++#+++#################
######+++++++++++#################
######+++++++#+++#################
######+++++++++++#################
######++++++++++##################
######+++++++++++#################
######+++#+++++++#################
#######++++++++++#################
######+++++++++#+#################
######+++++++++++#################
######+++++#+++++#################
######+++++++++++#################
######++#+++#++++#################
######++++++++++##################
######++++#++++++#################
######+++++++++++#################
######+++++++++#+#################
######++++#++++++#################
######+++++++++++#################
#######++++++++++#################
######++++++++#++#################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
Code: [Select]
###################################
#######1111111111##################
######222222222#3##################
######4#55#66#773##################
######48888888883##################
######4999999#::3##################
######4999999<<<3##################
######4999999<<<###################
######4999999<<<;##################
######4??#>>>>>>;##################
#######??=======;##################
######AAAAAAAAA#;##################
######AAAAAAAAA@;##################
######DDDDD#CCC@;##################
######DDDDDBBBB@;##################
######NN#FFF#GG@;##################
######NNEEEEEEE@###################
######NNHH#JJJJ@K##################
######NNHHIIIII@K##################
######NNHHIIIII#K##################
######NNHH#LLLLLK##################
######NNHHMMMMMMK##################
#######OOOOOOOOOK##################
######PPPPPPPP#QK##################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################


the "teeth" 96 tiles represented with 9 nodes

Code: [Select]
##################################
######++++++++++##################
######++++++++++##################
######+++++++++###################
######+++++++++###################
######+++++++++###################
######+++++++++###################
######++++++++####################
######+++++++#####################
######+++++++#####################
######+++++#######################
######++++########################
######+++#########################
######++##########################
######++##########################
######+###########################
######+###########################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################
##################################


Code: [Select]
###################################
######2222222222###################
######2222222222###################
######333333333####################
######333333333####################
######333333333####################
######333333333####################
######11111111#####################
######5555555######################
######5555555######################
######44444########################
######6666#########################
######777##########################
######99###########################
######99###########################
######8############################
######8############################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################
###################################

here is the source code : http://www.megaupload.com/?d=4G4RUAIK
the graph.c is a bunch of function I use to manipulate graph and list (I used the adjacency list  graph representation)

And btw
Quote
The problem is to create nodes while digging out rooms. Niseg's idea makes it easy, because there is no prerequisite for a tile being included in a node, you just check for an adjacent node and add to it. However, with this idea, unless a highly efficient algorithm to create and merge nodes is used, the overhead may outweigh the benefit, and the benefit may be mitigated by highly suboptimal shapes.
My code is still utterly unoptimized and the complexity of the merge function is O(n) in the worst case where n is the number of connections of the node where the tile is merged (O(1) if the digged tile can't be merged). The only real problem of this method is to find out how to (very) efficiently slice the map (see the "classic fortress" the main hall is cut in 8 parts)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 09, 2011, 10:25:21 am
Except, of course, in that scheme nothing needs to be stored because the hierarchical structure is implicit. Not so in Kohaku's scheme. If each square at each scale had to keep an explicit list (or hash table) of all the smallest-scale squares that are in it, it wouldn't look so nice anymore.

Doesn't matter if you're explicitly storing larger chunks or implicitly knowing what they are.  The point is that A* takes fewer steps.  The reason this works is because every explicitly defined area is a convex solid, meaning that from any point within its boundaries to any other point within its boundaries there exists an uninterrupted strait line (of unknown length) between them.  A* doesn't need to check of the path exists on the tile level so long as it exists on the "node map" level.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 09, 2011, 10:50:46 am
Doesn't matter if you're explicitly storing larger chunks or implicitly knowing what they are.  The point is that A* takes fewer steps.  The reason this works is because every explicitly defined area is a convex solid, meaning that from any point within its boundaries to any other point within its boundaries there exists an uninterrupted strait line (of unknown length) between them.  A* doesn't need to check of the path exists on the tile level so long as it exists on the "node map" level.
Your answer has nothing to do with the tree structure or the hash tables.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 09, 2011, 10:58:15 am
Doesn't matter if you're explicitly storing larger chunks or implicitly knowing what they are.  The point is that A* takes fewer steps.  The reason this works is because every explicitly defined area is a convex solid, meaning that from any point within its boundaries to any other point within its boundaries there exists an uninterrupted strait line (of unknown length) between them.  A* doesn't need to check of the path exists on the tile level so long as it exists on the "node map" level.
Your answer has nothing to do with the tree structure or the hash tables.

Doesn't matter.  The data structure used is one of generalization.  A tile always knows which node it is in in the tree/hash/mesh* thereby ignoring the "search the data structure" part of your worry.  Of course, even that doesn't matter, as searching a data structure of points for a given point is trivial compared to the time that is saved by using the data structure.

*For trees, it actually doesn't matter, it can be determined because the data structure is a god damn tree.  If you don't know how to search a tree, and why it takes O(n) time to search, you don't know how a tree is set up.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 09, 2011, 11:35:52 am
Doesn't matter if you're explicitly storing larger chunks or implicitly knowing what they are.  The point is that A* takes fewer steps.  The reason this works is because every explicitly defined area is a convex solid, meaning that from any point within its boundaries to any other point within its boundaries there exists an uninterrupted strait line (of unknown length) between them.  A* doesn't need to check of the path exists on the tile level so long as it exists on the "node map" level.
Your answer has nothing to do with the tree structure or the hash tables.

Doesn't matter.  The data structure used is one of generalization.  A tile always knows which node it is in in the tree/hash/mesh* thereby ignoring the "search the data structure" part of your worry.  Of course, even that doesn't matter, as searching a data structure of points for a given point is trivial compared to the time that is saved by using the data structure.

*For trees, it actually doesn't matter, it can be determined because the data structure is a god damn tree.  If you don't know how to search a tree, and why it takes O(n) time to search, you don't know how a tree is set up.
We're still talking about pathfinding, right? Not about searching for a single node?
I quote:
Quote
Now, in order to search this tree, you start from the starting node, and search the hash list of branches and leaves connected to the starting node.  If the destination node is not in that list, you go down a node on the tree, and search the lower node that connects to the starting node, and see if you can reach the destination node by only going up from there.  If that doesn't work, you keep going down the tree all the way to the roots until you can find a path to the destination node.

Once you find a branch with a connection to the destination node, you just go up the tree, testing which branches will have connections to the destination node, until you finally strike the destination node, itself.
Now tell me how the searching of data structures doesn't impact performance in this algorithm.

I submit: Yes, if you restrict your pathfinding to only considering this star-shaped topology of your map, ignoring any cross-connections, then you can find a path faster like Kohaku says. But
a: Your paths can be arbitrarily bad and
b: Your time cost will be multiplied by a hash table (or similar) lookup (since it occurs at every step) and
c: Your space cost will be much increased

b and c would be mitigated if we had something like the square-in square subdivision you suggested earlier - then a couple of comparisons would do and no extra storage would be needed. But that carries the extra problem that not all space in each super-square is connected. That's been discussed earlier in this thread; you could split each node into multiple ones representing connected subcomponents. This throws the best-case complexity out the window however.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 09, 2011, 12:28:39 pm
I added a few things to my simulator. people on modding forum suggested using either the vector heuristic or max. Manhaten always overestimate which is pretty bad.

add a silly path smoother but it's less than optimal.

I am in the mood of writing some code, so I made the "merge node" algorithm, which I used to slice in rectangles some maps (I add all the walkable tiles one by one, like if it was a digged tile).
here is what it gives on some classic maps.

Ok I looked at some of your code I think you should have used an array of structs instead of 3d array . Well doesn't matter.

my idea was to use this data type for node:
Spoiler (click to show/hide)

This can save nodes in any shape even overlapping rooms with max size of 256. There are more useful function like growing and shrinking it to the appropriate room size (adding rows and columns at the edges) .

This data type help you avoid wasting memory on small rooms(I saw your program was going crazy when it couldn't merge). all you need to do is to floodfill (Breadth first) and save the node into a room  rooms. My approach is "a start big, divide map into chunks -> validate room and turn unconnected parts into their own rooms -> connect the rooms with edges -> merge smaller rooms  into bigger rooms  . The general guideline is to avoid creating new rooms unless it's necessary .
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on April 09, 2011, 01:24:53 pm

Ok I looked at some of your code I think you should have used an array of structs instead of 3d array . Well doesn't matter.

my idea was to use this data type for node:
Spoiler (click to show/hide)

This can save nodes in any shape even overlapping rooms with max size of 256. There are more useful function like growing and shrinking it to the appropriate room size (adding rows and columns at the edges) .

I'm not sure I understand your struct , do you define a node by a (at most) 10 edges shape? if so, what are the 2 corners?
how can it store this shape for exemple? (which is convex) (edit: forget this , but still how do you represent this shape and whith how many nodes?)
Code: [Select]
##################
##+#+#+#+#+#######
#++++++++++#######
##################

And more importantly how do you know if you can add a tile to a shape (does the new shape will still be convex?).

But my main goal was to make the function that dinamically change the graph when you add (dig) a new walkable tile not the room slicing function. I just tried to slice the map by digging 1 tile by 1 tile, and it was surprisingly not so bad and pretty fast for a first try.

Feel free to do whatever you want with my code.
I'll try to improve my struct, make the split function, the A* using my struct and the basic A* to have a first idea of the degree of improvement this method gives.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 09, 2011, 06:56:07 pm
We're still talking about pathfinding, right? Not about searching for a single node?
I quote:
Quote
Now, in order to search this tree, you start from the starting node, and search the hash list of branches and leaves connected to the starting node.  If the destination node is not in that list, you go down a node on the tree, and search the lower node that connects to the starting node, and see if you can reach the destination node by only going up from there.  If that doesn't work, you keep going down the tree all the way to the roots until you can find a path to the destination node.

Once you find a branch with a connection to the destination node, you just go up the tree, testing which branches will have connections to the destination node, until you finally strike the destination node, itself.
Now tell me how the searching of data structures doesn't impact performance in this algorithm.

I submit: Yes, if you restrict your pathfinding to only considering this star-shaped topology of your map, ignoring any cross-connections, then you can find a path faster like Kohaku says. But
a: Your paths can be arbitrarily bad and
b: Your time cost will be multiplied by a hash table (or similar) lookup (since it occurs at every step) and
c: Your space cost will be much increased

b and c would be mitigated if we had something like the square-in square subdivision you suggested earlier - then a couple of comparisons would do and no extra storage would be needed. But that carries the extra problem that not all space in each super-square is connected. That's been discussed earlier in this thread; you could split each node into multiple ones representing connected subcomponents. This throws the best-case complexity out the window however.

You're getting a fairly close, yes.

A. is probably not as bad as you think it might be, and it may simply be worth the loss.  As long as the nodes are of generally similar sizes, you should generally see nodes that are equidistant from wherever the root node is should be roughly similar tiers on the tree, unless the nodes have to take some very winding detours.  In that case, the path that took the long detours will naturally already be fairly high on the tree, while the straighter path will be low on the tree.  The low parts of the tree should take precedence in gaining leaves and branches for itself in the purpose of building the tree.  Using the last method I mentioned ("duplicate-branches" let's call it), the one that takes up extra memory, should potentially solve all the problems with un-optimized routes.  (And remember, we want to optimize for performance and memory use more than we necessarily want to optimize for finding the shortest path, so long as it isn't an unreasonably long detour.)  I haven't actually tried to come up with some sort of nightmare case that would actually produce a real problem for the duplicate-branches, so it may be optimal, anyway.

B is true, but again, it's probably not the limitation you think it is - you are looking up the hash table in every node you visit to see if there is a direct path up the tree to find the node you are searching for.  This is, however, not a problem.  This basically just means we are doing another memory fetch per node we look at, while at the same time we are cutting down a cross-map search from a sub-geometric complexity to a logarithmic complexity.  In other words, we're turning O(n^3) into O(log(2n)) where the 2 in the 2n is the extra looking up in the hash table.  That's completely worth it in anything but the shortest of all pathfinding equations.

C is the real threat.  As you say, however, it may just be easier to make multiple "levels" or "hierarchies" of data structures altogether to try to keep the size of each individual data structure down.  (I say "levels" instead of "tiers" so as not to confuse the terminologies, here.)  Because the complexity of those hash tables increases geometrically with the number of tiers in the tree, (and again, this complexity is geometric growth of memory consumption giving us logarithmic growth of processor power,) you can save on memory by making multiple levels of nodes.

For example, in the "moving to another location on the Earth" example I was talking about earlier, you can organize individual nodes of buildings and streets, and conglomerate them together into a city, and you only have to do the tree search from the city level up to the planet level. 

You can have fairly simple nodes that are conglomerated together on the next level of abstraction so that you have an area consisting of no more than some arbitrary number of nodes or some arbitrary amount of area where you can ensure relatively easy connectivity between that area's nodes, and then make that area of nodes the "city" which is the smallest unit in the tree data structure - hence, conglomerating 100 nodes into a "node area" that occupies one large-scale tree node. 

The starting point and destination would then compare whether they are in the same node area or not, and if they are in the same area, you wouldn't have to use the large-scale tree at all.

You could work the small-scale area into being a tree configuration, as well.  You simply need to make a list of known connections to the other areas, and pare them down to the ideal candidates.  In a collection of smaller-scale nodes, where everything is conglomerated based upon being in proximity to one another, you will actually see your "A" concern a little less prominent, as well, since you can simply build the closest thing to a fractal "star" that you can get out of the nodes to make your small-scale tree.

You can also throw as many levels of abstraction into this as you ever deem necessary at that point - you can simply have some arbitrary cut-off of x-number of nodes in a tree that forces the jump to a new level of abstraction, allowing for arbitrary levels of abstraction, although this would make the address of each node become more complex, and require a vector to store it, rather than set data types. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 10, 2011, 01:03:10 am

Ok I looked at some of your code I think you should have used an array of structs instead of 3d array . Well doesn't matter.

my idea was to use this data type for node:
Spoiler (click to show/hide)

This can save nodes in any shape even overlapping rooms with max size of 256. There are more useful function like growing and shrinking it to the appropriate room size (adding rows and columns at the edges) .

I'm not sure I understand your struct , do you define a node by a (at most) 10 edges shape? if so, what are the 2 corners?
how can it store this shape for exemple? (which is convex) (edit: forget this , but still how do you represent this shape and whith how many nodes?)
Code: [Select]
##################
##+#+#+#+#+#######
#++++++++++#######
##################

And more importantly how do you know if you can add a tile to a shape (does the new shape will still be convex?).

But my main goal was to make the function that dinamically change the graph when you add (dig) a new walkable tile not the room slicing function. I just tried to slice the map by digging 1 tile by 1 tile, and it was surprisingly not so bad and pretty fast for a first try.

believe me 10 edges is more than enough. rooms with too many can be  merged or sliced.

let say our constraint is size 4X4 rooms or 16 nodes per room

_0123456789ABCDE
0##################
1##+#+#+#+#+#######
2#++++++++++#######
3##################


here we can split to 2 rooms because there are 24 nodes . first thing split it  like a program into 4x4s

_0123 4567 89AB CDEF
0#### #### #### ######
1##+# +#+# +#+# ######
2#+++ ++++ +++# ######
3#### #### #### ######
             nodes
id|ul |lr |bv16|0|1|2|3|4|5|
--|---|---|----|-|-|-|-|-|-|
0 |0,0|0,3|02F0|1| | | | | |
1 |4,0|7,3|0AF0|0|2| | | | |
3 |8,0|B,3|0AE0|2| | | | | |
4 |C,0|F,3|0000| | | | | | |

room 4 can be discarded...

now with both nodes and tables we can start transforming for a merge or leave them this way to support digging. the merge is done by slicing the sides like bottom and top that have no edges and then transforming them into new room. in our case it would be real easy
 
merge 0 into 1 would make a room ul=1,1 lr=B,2 and the bitmask would transform from 4X4 to 2X8 bv=AAFE.

if you preserve the  original structure and want to dig 1,1  all you need to do is change mask from 02F0 to 03F0.

the validation scheme is a bit vector output breadth first search.Which is xored with the original room's open slot bitvector   which gives you rooms outside the array. you can then figure out what you need to chop out.  This example isn't that useful for showing complex splitting.

Edit: PS

I'm considering  openning another thread for path caching since we kinda split this thread into multiple dirrections. Some people want to talk about meshes( I think I got a way to implement it after looking at a few topics on the subject) , and others about room division (promising but take some work).

Path caching is by far the least complicated method to implement . Optimizing it is a complex topic though the algorithms are not high complexity. I think it's preferable  the game use waypoints as a guide  rather than to use them as a waypoint.  I have a new search which rounds off the ends in my simulator.  and I'm still experimenting with stuff (looked and how you do it in meshes) . It now let you draw lines too which would make it easier to draw your mazes.  I think I'll add the splitter I mentioned above soon .
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 10, 2011, 02:13:24 am
A. is probably not as bad as you think it might be, and it may simply be worth the loss.  As long as the nodes are of generally similar sizes, you should generally see nodes that are equidistant from wherever the root node is should be roughly similar tiers on the tree, unless the nodes have to take some very winding detours.  In that case, the path that took the long detours will naturally already be fairly high on the tree, while the straighter path will be low on the tree.  The low parts of the tree should take precedence in gaining leaves and branches for itself in the purpose of building the tree.  Using the last method I mentioned ("duplicate-branches" let's call it), the one that takes up extra memory, should potentially solve all the problems with un-optimized routes.  (And remember, we want to optimize for performance and memory use more than we necessarily want to optimize for finding the shortest path, so long as it isn't an unreasonably long detour.)  I haven't actually tried to come up with some sort of nightmare case that would actually produce a real problem for the duplicate-branches, so it may be optimal, anyway.
I sort of see before me a road system where all traffic between Pasadena and Seattle is routed through St. Louis...

I don't quite follow how the "duplicate-branches" algorithm works. What precisely are you storing for each node in addition to the simpler version? Which stores, if I understand it correctly, a list of all nodes above it and a pointer to its immediate successors.
(Your use of up and down confused me before; I usually have parent nodes above the child nodes but at least I get you now)

Quote
B is true, but again, it's probably not the limitation you think it is - you are looking up the hash table in every node you visit to see if there is a direct path up the tree to find the node you are searching for.  This is, however, not a problem.  This basically just means we are doing another memory fetch per node we look at, while at the same time we are cutting down a cross-map search from a sub-geometric complexity to a logarithmic complexity.  In other words, we're turning O(n^3) into O(log(2n)) where the 2 in the 2n is the extra looking up in the hash table.  That's completely worth it in anything but the shortest of all pathfinding equations.
I don't know enough about the complexity of hashes but won't the worst-case bite you occasionally? Anyway, you may be right on this one. Again, you could do without any hash table if the contents of a node were implicit (like with a quadtree, which is pretty much what Draco brought up before).

Quote
C is the real threat.  As you say, however, it may just be easier to make multiple "levels" or "hierarchies" of data structures altogether to try to keep the size of each individual data structure down.  (I say "levels" instead of "tiers" so as not to confuse the terminologies, here.)  Because the complexity of those hash tables increases geometrically with the number of tiers in the tree, (and again, this complexity is geometric growth of memory consumption giving us logarithmic growth of processor power,) you can save on memory by making multiple levels of nodes.

For example, in the "moving to another location on the Earth" example I was talking about earlier, you can organize individual nodes of buildings and streets, and conglomerate them together into a city, and you only have to do the tree search from the city level up to the planet level. 
This hierarchical clustering is really independent of your tree-based search. Any search method can be used with it.

One has to connect the different levels though - if I'm in St. Louis on the large-scale map, where exactly am I on the city map? How do I combine the costs from both levels? But this is for another subthread, really.

Quote
You can have fairly simple nodes that are conglomerated together on the next level of abstraction so that you have an area consisting of no more than some arbitrary number of nodes or some arbitrary amount of area where you can ensure relatively easy connectivity between that area's nodes, and then make that area of nodes the "city" which is the smallest unit in the tree data structure - hence, conglomerating 100 nodes into a "node area" that occupies one large-scale tree node. 

The starting point and destination would then compare whether they are in the same node area or not, and if they are in the same area, you wouldn't have to use the large-scale tree at all.

You could work the small-scale area into being a tree configuration, as well.  You simply need to make a list of known connections to the other areas, and pare them down to the ideal candidates.  In a collection of smaller-scale nodes, where everything is conglomerated based upon being in proximity to one another, you will actually see your "A" concern a little less prominent, as well, since you can simply build the closest thing to a fractal "star" that you can get out of the nodes to make your small-scale tree.

You can also throw as many levels of abstraction into this as you ever deem necessary at that point - you can simply have some arbitrary cut-off of x-number of nodes in a tree that forces the jump to a new level of abstraction, allowing for arbitrary levels of abstraction, although this would make the address of each node become more complex, and require a vector to store it, rather than set data types.
Sounds OK in principle, but how would it all be done more concretely?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 11, 2011, 10:07:33 am
My work on path smoothing have shown major progress as you can see in this Maze (http://niseg.0adz.com/test_maze.html?maze=v02AgAgAQEQEEGQcJFQIIAxwAAAAAAMAAAAAwAAAPrmAQAAHAAAAAMAADAAwAAPAAAAAOAAgAACAQBBDAIAQDAEACDACAAhABAAIAAgABAAQAAQAIAAEAEAAAgCAAAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)(someone else drew it though). You can play with waypoint and do extra smoothing steps . The results are pretty good( you can even smooth A*) except for when there are loops which are caused by waypoints. I'll either use the loop searching function I'm working on  and do smoothing afterward  or improve the path smoothing to have a larger lookahead especially on the first iteration. 

I think that after I get some kind of working setup it would be ready for its own thread  ;).

btw I opend a threads  (http://www.bay12forums.com/smf/index.php?topic=81686.0)on the modding forum about my path finding simulator . I update that thread with my progress and plans.

edit:
I've been thinking about a new scheme after looking at some AI material . It's is based on path caching using something like hierarchical model with waypoints.. All waypoint would be double cross shaped with N,S,E,W,U,D edges and they would be placed to form a grid

flat example
Code: [Select]
A-B-C-D
| | | |
E-F-G-H
| | | |
I-J-K-L

They would be arbitrarily spread out through the map in a grid and the path between adjacent waypoints would be saved. Then to find a path all you need is use the old path cacher and then smooth it out to reach an optimal path.
 this saves the headache of defining "rooms". it's not optimal but it's better than high complexity A*. In books I looked at they say that if you go 60X60 grid you better have a better plan than just using A*.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 11, 2011, 11:12:33 am
I sort of see before me a road system where all traffic between Pasadena and Seattle is routed through St. Louis...

I don't quite follow how the "duplicate-branches" algorithm works. What precisely are you storing for each node in addition to the simpler version? Which stores, if I understand it correctly, a list of all nodes above it and a pointer to its immediate successors.
(Your use of up and down confused me before; I usually have parent nodes above the child nodes but at least I get you now)

This is why we then do this part:

Quote
In the first method, (let's use Wikipedia's page on trees for an illustration), let's assume that we found a path in that tree from the "5" node on the bottom left to the "9" node on the right.  This would return a path of "5->6->7->2->5->9", but at the same time, 7 and 5 are connected, so you can cut out the path with 2 inside of it.

When making that original chain of nodes, you basically are only looking for going up and down the tree, not laterally - you go "down" the tree ("down" being towards the roots) until you find a route directly up the tree you can follow.  To do this, you have a list of all the points "up the tree" from a given node.  Once you have that chain, however, you can look for lateral shortcuts by simply comparing all the connections (up, down, or lateral on the tree) that allow a given node to bypass one or more steps in the chain.

This method has a complexity of an additional O(n^2/2) where n is the length of the chain you returned previously.  It winds up with some extra memory calls, but should still be much faster than A*-ing the entire fort.

This will basically return you the previous path, but with a few shortcuts taken where they are found.

This would mean that, you would find a route that goes through St. Louis, and then you search for more direct paths by cutting out whatever "middlemen" you can, resulting in a much more direct route.


I don't know enough about the complexity of hashes but won't the worst-case bite you occasionally? Anyway, you may be right on this one. Again, you could do without any hash table if the contents of a node were implicit (like with a quadtree, which is pretty much what Draco brought up before).

Hashes are very simple.  If you aren't familiar with a hash, the idea is that, instead of building a linked list that you have to traverse down the list one by one, having to ask each item on the list where the next item on the list is, you generate a hash, which acts as a table of contents on the data.  The hash table is an array with specific addresses (think of these as drawers in a filling cabinet), and objects get filed into the hash list based upon the number that comes up when you hash their reference data, the data you are searching for. 

Hashing just means converting the data back into numbers, and adding and multiplying those numbers by a set amount so that you get a relatively unique integer number that can be compared to any other integer, no matter what sorts of data were originally thrown into the hash. 

When you have a piece of data you want to throw into the hash table, you hash the reference data, the data you would search for, and then throw it in the resulting "drawer" of the hash table.  When you want to look for that data again, you take the data you are searching for, hash that, and it will come up with the number of the hash table "drawer" you want to look for.

Hash tables are a way of looking for data in a list very quickly.  They actually make the act of searching take up theoretically O(n/x) long, where x is the size of the hash table, and n is the size of the amount of data you are searching for.  Technically, "x" should always be larger than n (how much larger depends on if you have linked lists off of the "filing cabinets" as well for overflow), so it really just comes down to O(1), which is the ideal complexity level - no matter what size the table is, it takes the same amount of time to find what you are looking for.  (As compared to a linked list taking O(n), where if the data you are looking for is at the end of the list, you have to go through every single item on the list in order before you can find the one thing you are looking for.)



These "shortest of all cases" is literally something like "Urist, it's three feet to your right.  You can see it.  Just walk straight there."  Something like that is so trivial, even with the loading of checks to see what zip code the target is in, you can do those all day long without a noticeable drop in FPS.

This hierarchical clustering is really independent of your tree-based search. Any search method can be used with it.

One has to connect the different levels though - if I'm in St. Louis on the large-scale map, where exactly am I on the city map? How do I combine the costs from both levels? But this is for another subthread, really.

You can store tree-level paths "through" the tree.  This means that you don't even have to path through entire lower-level trees you are pathing through, you just store the route, and always take that route. 

If you're passing through St. Louis by taking the Interstate, you don't need to look at the individual city routes at all, you just need to stay on the Interstate heading on whatever direction you are heading. 


Quote
You can have fairly simple nodes that are conglomerated together on the next level of abstraction so that you have an area consisting of no more than some arbitrary number of nodes or some arbitrary amount of area where you can ensure relatively easy connectivity between that area's nodes, and then make that area of nodes the "city" which is the smallest unit in the tree data structure - hence, conglomerating 100 nodes into a "node area" that occupies one large-scale tree node. 

The starting point and destination would then compare whether they are in the same node area or not, and if they are in the same area, you wouldn't have to use the large-scale tree at all.

You could work the small-scale area into being a tree configuration, as well.  You simply need to make a list of known connections to the other areas, and pare them down to the ideal candidates.  In a collection of smaller-scale nodes, where everything is conglomerated based upon being in proximity to one another, you will actually see your "A" concern a little less prominent, as well, since you can simply build the closest thing to a fractal "star" that you can get out of the nodes to make your small-scale tree.

You can also throw as many levels of abstraction into this as you ever deem necessary at that point - you can simply have some arbitrary cut-off of x-number of nodes in a tree that forces the jump to a new level of abstraction, allowing for arbitrary levels of abstraction, although this would make the address of each node become more complex, and require a vector to store it, rather than set data types.
Sounds OK in principle, but how would it all be done more concretely?

Well, you just start with whatever convex cubes you wind up having from the node-creating function (that's beyond this discussion).  Then you have to start stitching these pieces together.

You have two major paths to follow from there.

The first option is that you can start from geometric isolation:
This means starting with splitting the map into cubes of geographic areas, and then looking to make sure that all nodes in those cubes connect with one another, and splitting of any cubes which do not have connectivity.  You then stitch together trees out of the nodes that are still in those geographic areas have connectivity, and then you build the next level of hierarchy as a way to get from one geographic area to the others.

The other option is that you can start from an arbitrary point somewhere in the "middle" of the map:
This works best with the innate nature of a tree data structure, upon further thought, since it relies upon some of its basic principles, and assumes some dynamic ability to shift to changing nodes.

Pick a node, any random node on the map. 

Now, you have to start connecting all its adjacent nodes to it as branches, and start building a tree.

During this process, the tree needs to "balance" itself, which is a basic function of many trees.  This means that the "root node" will change to be the node with the most roughly-equidistant leaf nodes hanging off of it.  (This means that you don't want a lopsided tree, if a branch becomes larger than the rest of the tree, the start of that branch becomes the new root, and the old root becomes a branch of the new root.)

Once you hit a certain point of complexity, say ten tiers on the tree structure, it is time to build the next level of hierarchy.  In this, the root node becomes not only a root node for the level-1 tree that we were building before, but also the root node of the level-2 tree, which acts as the geographical equivalent of moving from a city-level to a state-level of travel.  Each of those other level-1 trees becomes filled out with new root nodes for their level-1 trees, based upon the fastest connection to the root node of the level-2 tree.  Each of these new level-1 trees is now a branch of the level-2 tree.  You then keep on going, populating the level-1 trees until they have to simply split off, and make a new level-1 tree which they are connected to. 

Eventually, you wind up building the whole tree by flood-filling the map of nodes until you have connected every node that has a connection.

If the level-2 tree becomes complex enough, it, too, would split into a level-3 tree.  You can make this sort of method have theoretically infinite levels. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 11, 2011, 12:21:12 pm
My work on path smoothing have shown major progress as you can see in this Maze (http://niseg.0adz.com/test_maze.html?maze=v02AgAgAQEQEEGQcJFQIIAxwAAAAAAMAAAAAwAAAPrmAQAAHAAAAAMAADAAwAAPAAAAAOAAgAACAQBBDAIAQDAEACDACAAhABAAIAAgABAAQAAQAIAAEAEAAAgCAAAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)(someone else drew it though). You can play with waypoint and do extra smoothing steps . The results are pretty good( you can even smooth A*) except for when there are loops which are caused by waypoints. I'll either use the loop searching function I'm working on  and do smoothing afterward  or improve the path smoothing to have a larger lookahead especially on the first iteration. 

Nice interface.
I pressed A* and got a slightly "off" path though, so I'm wondering: what is the actual cost function you're using? one step costs 1? That would explain the path I saw but that makes several of the heuristics inadmissible.

Also, there's another heuristic that might be relevant:
sqrt(2)*max(abs(dx),abs(dy)) + (1-sqrt(2))min(abs(dx),abs(dy))
that is, the smallest distance possible if you may only walk at 45 degree increments (which is true for dwarfs in DF, though not for projectiles).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 11, 2011, 12:31:27 pm
In the first method, (let's use Wikipedia's page on trees for an illustration), let's assume that we found a path in that tree from the "5" node on the bottom left to the "9" node on the right.  This would return a path of "5->6->7->2->5->9", but at the same time, 7 and 5 are connected, so you can cut out the path with 2 inside of it.

When making that original chain of nodes, you basically are only looking for going up and down the tree, not laterally - you go "down" the tree ("down" being towards the roots) until you find a route directly up the tree you can follow.  To do this, you have a list of all the points "up the tree" from a given node.  Once you have that chain, however, you can look for lateral shortcuts by simply comparing all the connections (up, down, or lateral on the tree) that allow a given node to bypass one or more steps in the chain.

This method has a complexity of an additional O(n^2/2) where n is the length of the chain you returned previously.  It winds up with some extra memory calls, but should still be much faster than A*-ing the entire fort.
Here you're letting the shortcut lookup be O(1) and the construction of that lookup table O(n), I take it. That may be reasonable on average, though not worst-case I guess.

Quote
This would mean that, you would find a route that goes through St. Louis, and then you search for more direct paths by cutting out whatever "middlemen" you can, resulting in a much more direct route.
Well, whether it's much shorter or merely cuts the very tip of the wedge next to St. Louis depends wholly on the coarseness of the map, doesn't it? If there are always at least two cities between the first and second "leg" of the trip, this modification won't make any difference.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 11, 2011, 12:38:20 pm
This hierarchical clustering is really independent of your tree-based search. Any search method can be used with it.

One has to connect the different levels though - if I'm in St. Louis on the large-scale map, where exactly am I on the city map? How do I combine the costs from both levels? But this is for another subthread, really.

You can store tree-level paths "through" the tree.  This means that you don't even have to path through entire lower-level trees you are pathing through, you just store the route, and always take that route. 

If you're passing through St. Louis by taking the Interstate, you don't need to look at the individual city routes at all, you just need to stay on the Interstate heading on whatever direction you are heading. 
This works well if there are only a few entry points into a sub-map. There are only so many ways to enter St. Louis (on a major highway at least). But it will be worthless if there are loads and loads of entry points, such as will be the case for a general quadtree square over a DF map. And for anything larger-scale than individual rooms, which *may* have only a few doors out of it, it will be a monumental task coming up with an algorithm to decide the right way to subdivide the map into a large-scale clustering which minimizes the number of entry points.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 11, 2011, 12:51:23 pm
Sounds OK in principle, but how would it all be done more concretely?

Well, you just start with whatever convex cubes you wind up having from the node-creating function (that's beyond this discussion).  Then you have to start stitching these pieces together.

You have two major paths to follow from there.

The first option is that you can start from geometric isolation:
This means starting with splitting the map into cubes of geographic areas, and then looking to make sure that all nodes in those cubes connect with one another, and splitting of any cubes which do not have connectivity.  You then stitch together trees out of the nodes that are still in those geographic areas have connectivity, and then you build the next level of hierarchy as a way to get from one geographic area to the others.
Whoa, hold there. Let's assume without loss of generality that *all* the free space in the map is connected. What then? Just being connected can't be used as criterion for splitting space up - that would be meaningless! Space that isn't connected shouldn't be part of the same tree on *any* level!
You have to divvy space up on the basis of choke points, or maximum convex regions or some other heuristic. Which one though?

Quote
The other option is that you can start from an arbitrary point somewhere in the "middle" of the map:
This works best with the innate nature of a tree data structure, upon further thought, since it relies upon some of its basic principles, and assumes some dynamic ability to shift to changing nodes.

Pick a node, any random node on the map. 

Now, you have to start connecting all its adjacent nodes to it as branches, and start building a tree.

During this process, the tree needs to "balance" itself, which is a basic function of many trees.  This means that the "root node" will change to be the node with the most roughly-equidistant leaf nodes hanging off of it.  (This means that you don't want a lopsided tree, if a branch becomes larger than the rest of the tree, the start of that branch becomes the new root, and the old root becomes a branch of the new root.)

Once you hit a certain point of complexity, say ten tiers on the tree structure, it is time to build the next level of hierarchy.  In this, the root node becomes not only a root node for the level-1 tree that we were building before, but also the root node of the level-2 tree, which acts as the geographical equivalent of moving from a city-level to a state-level of travel.  Each of those other level-1 trees becomes filled out with new root nodes for their level-1 trees, based upon the fastest connection to the root node of the level-2 tree.  Each of these new level-1 trees is now a branch of the level-2 tree.  You then keep on going, populating the level-1 trees until they have to simply split off, and make a new level-1 tree which they are connected to.
Could you draw a picture of that? *scratches head* Does every subtree become a single node in the L2 tree or multiple nodes? If multiple, how is the L1 tree subdivided to make L2 nodes?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on April 11, 2011, 01:38:25 pm
Remember I mentioned Hash Tables in an earlier post.  (Ok, maybe you don't, it was probably within a TL;DR; kind of post.)

Hash tables can be most inefficient for some searches and must ideally represent a much sparser map of points of interest than the totality of all possible points.  Otherwise you might as well suffer the overheads of storing each (totality-set) point in an array (of however many dimensions) and get direct access to the data or reference (or lack, thereof), rather than having to wander through a list of randomly sorted reference points[1] to make your intended discovery.

A sorted hash-table index, however, would be very good for a situation where changes are few but queries many, by binary-search methods.  Each time you have to change the table, though you would have to insert each and every new item (binary-search for the pair just-above and just-below, by the search criteria being used, then shuffle the top 'half' upwards to make room) and remove each and every removal (reverse, by shuffling down the greater-thans).  You could make a compromise system in which a limited number of null data points get left behind after splicing out a point so that there's a chance that a spliced-in item can sit in a handy null-point, but that does slow the searching down[3], there's always going to be the possibility that a number of shifts[4], and certainly while increasing the number of hash-points being stored there's going to be a scarcity of null-spots and you're going to be increasing the table's size just as if it wasn't a null-filled version.  Never mind that you may end up storing an N point hash table in a 2N or more length hash table, which may again eat into any of the efficiencies you get.


I'm not saying that Hash Tables are bad, and as a Perlite I tend to (over?-)use them myself for convenience alone, but the purpose you're putting the hash-table towards might not be particularly conducive to the structure.  There isn't a magical 'black box' function that will let you store and retrieve hash values (including references) under a hash key in a straight O(c) number of CPU ticks.  You may even be optimising something by using hash lookup that was actually more optimal, despite itself, than the hash-maintenance and using process ends up being.


Some intelligence may be able to counter the disadvantages, however.  Perhaps integrating some sort of acknowledgement that the raising/lowering of a bridge might indeed split apart and reform into one areas on either side of it, according to state, would prevent you from trying to utterly collapse the hash-table entries regarding the separated zones into a single one (with all accompanying shuffling, if that's what's being done) when the bridge lowers and causes a reassessment as a combined zone, only to require the separation again (shuffling them the other way) each time the bridge raises and forces the zones to separate.  Rinse and repeat many times, if the bridge is frequently toggled.

Perhaps a limited use of null-referencing 'placeholder' table entries could hold zones that are abandoned upon a reversibly state-change, so as to be quickly re-instated (and other placeholder entries being set in any equivalent abandonments when moving from the second state back to the first).  Other than this, stick to the shuffling-without-nulls (creating or folding into) when (comparatively rare) landscape changes are made.  It would take a little[5] extra coding to identify such obviously reversible states, but would not be quite so bad as having to keep null-references all over the place "just in case".


Note that I've not enumerated any of these ideas, mainly because the several different approaches being tried would give different amounts of overhead-bias for any given potential hash-using idea, and with at least three (and probably even more, if you consider how many different ways there are to fine-tune everything) hash-using ideas as well I don't see it worthwhile to do more merely expounding awareness.


[1] Either looking through the entire hash-set for the nearest point (possibly stopping immediately if you hit the exact point), or looking through a hash-set that contains within the hash-table[2] a 'coverage' for each set-point and stopping when the we find the appropriate container for the queried location.

[2] Or referenced from it, allowing variable-length structures, so perhaps taking less space if the data requiring storing is suitably compliant.

[3] May mean a significant amount of hunting up and/or down for a non-null table item to complete that round of the binary search, unless they're null referenced but maintain their original sorting values, ready for overwriting as deemed suitable.

[4] Into the next null space above only, of course, not necessarily for the whole top-end of the stack from that point.

[5] Or not a little, but I'm sure it could be done.  Maybe whittle it down to "does <combined-zone> include <movable-landscape-components>?" and go from there, whenever transitioning either from combined-zone to separate-zones or vice-versa.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 11, 2011, 02:23:30 pm
In the first method, (let's use Wikipedia's page on trees for an illustration), let's assume that we found a path in that tree from the "5" node on the bottom left to the "9" node on the right.  This would return a path of "5->6->7->2->5->9", but at the same time, 7 and 5 are connected, so you can cut out the path with 2 inside of it.

When making that original chain of nodes, you basically are only looking for going up and down the tree, not laterally - you go "down" the tree ("down" being towards the roots) until you find a route directly up the tree you can follow.  To do this, you have a list of all the points "up the tree" from a given node.  Once you have that chain, however, you can look for lateral shortcuts by simply comparing all the connections (up, down, or lateral on the tree) that allow a given node to bypass one or more steps in the chain.

This method has a complexity of an additional O(n^2/2) where n is the length of the chain you returned previously.  It winds up with some extra memory calls, but should still be much faster than A*-ing the entire fort.
Here you're letting the shortcut lookup be O(1) and the construction of that lookup table O(n), I take it. That may be reasonable on average, though not worst-case I guess.
No, not worst-case, really, but worst case can be very tricky to calculate.
Quote
This would mean that, you would find a route that goes through St. Louis, and then you search for more direct paths by cutting out whatever "middlemen" you can, resulting in a much more direct route.
Well, whether it's much shorter or merely cuts the very tip of the wedge next to St. Louis depends wholly on the coarseness of the map, doesn't it? If there are always at least two cities between the first and second "leg" of the trip, this modification won't make any difference.

Except it doesn't just trim off the very tip.  It compares every step of the journey for a shorter route between every point along the line.  This means that it will only path up to St. Louis if it has to go that far to find the correct relative distances in the tree for comparison, and then it could theoretically lop off that pathfinding all the way down to a simple path directly from one city to the other.

Let's take an example of two cities on opposite sides of a state boarder.  When you want to go across that state border into the next town, you would be transitioning not just cities, but also states.  This means you hop up from a street level to a city level to a state level to a national level of travel, then zoom back down to the city and street level.  But you don't need to travel back to state capitals to get there, you just need to check for the best lateral connection on the tree, which would involve simply driving down the nearest road across the border. 

In this example, the tree would be searched up to the national level, but then it would find the lateral pathway across the tree that lets it move at a street-to-street level or city-to-city level, rather than on a state-to-state level.

This hierarchical clustering is really independent of your tree-based search. Any search method can be used with it.

One has to connect the different levels though - if I'm in St. Louis on the large-scale map, where exactly am I on the city map? How do I combine the costs from both levels? But this is for another subthread, really.

You can store tree-level paths "through" the tree.  This means that you don't even have to path through entire lower-level trees you are pathing through, you just store the route, and always take that route. 

If you're passing through St. Louis by taking the Interstate, you don't need to look at the individual city routes at all, you just need to stay on the Interstate heading on whatever direction you are heading. 
This works well if there are only a few entry points into a sub-map. There are only so many ways to enter St. Louis (on a major highway at least). But it will be worthless if there are loads and loads of entry points, such as will be the case for a general quadtree square over a DF map. And for anything larger-scale than individual rooms, which *may* have only a few doors out of it, it will be a monumental task coming up with an algorithm to decide the right way to subdivide the map into a large-scale clustering which minimizes the number of entry points.

This goes back to that hierarchical pathfinding thing I was talking about about ten pages earlier in the thread.

You can draw up all the pathways in and out of a node, but you really don't need all of them.  As long as you are pathing "through" St. Louis, and not actually going to some point inside of it, it doesn't matter that there are routes through St. Louis that aren't the Interstate, as long as the Interstate is the BEST path, that's all you need to remember.

You can check for plenty of routes from one point to another, but you only need to store the best route from one exit to another exit.  You can keep storing the different entry points, but these would only matter if you were looking for a specific point inside of St. Louis you wanted to reach where it might make a difference.


Sounds OK in principle, but how would it all be done more concretely?

Well, you just start with whatever convex cubes you wind up having from the node-creating function (that's beyond this discussion).  Then you have to start stitching these pieces together.

You have two major paths to follow from there.

The first option is that you can start from geometric isolation:
This means starting with splitting the map into cubes of geographic areas, and then looking to make sure that all nodes in those cubes connect with one another, and splitting of any cubes which do not have connectivity.  You then stitch together trees out of the nodes that are still in those geographic areas have connectivity, and then you build the next level of hierarchy as a way to get from one geographic area to the others.
Whoa, hold there. Let's assume without loss of generality that *all* the free space in the map is connected. What then? Just being connected can't be used as criterion for splitting space up - that would be meaningless! Space that isn't connected shouldn't be part of the same tree on *any* level!
You have to divvy space up on the basis of choke points, or maximum convex regions or some other heuristic. Which one though?

Of course they aren't part of the same tree if they aren't connected.

This isn't a problem at all - if you cannot find a connection for some reason, you just start building another tree.  Only connected nodes are connected to the same tree.  Connection on a tree IS the implication of connectivity on the map, after all.

If the trees get connected again, it's fairly simple to put them together - that's the great thing about trees, they're wonderfully easy to merge and disconnect and mess with connections.  They are better about being dynamic than other types of data structures.


Quote
The other option is that you can start from an arbitrary point somewhere in the "middle" of the map:
This works best with the innate nature of a tree data structure, upon further thought, since it relies upon some of its basic principles, and assumes some dynamic ability to shift to changing nodes.

Pick a node, any random node on the map. 

Now, you have to start connecting all its adjacent nodes to it as branches, and start building a tree.

During this process, the tree needs to "balance" itself, which is a basic function of many trees.  This means that the "root node" will change to be the node with the most roughly-equidistant leaf nodes hanging off of it.  (This means that you don't want a lopsided tree, if a branch becomes larger than the rest of the tree, the start of that branch becomes the new root, and the old root becomes a branch of the new root.)

Once you hit a certain point of complexity, say ten tiers on the tree structure, it is time to build the next level of hierarchy.  In this, the root node becomes not only a root node for the level-1 tree that we were building before, but also the root node of the level-2 tree, which acts as the geographical equivalent of moving from a city-level to a state-level of travel.  Each of those other level-1 trees becomes filled out with new root nodes for their level-1 trees, based upon the fastest connection to the root node of the level-2 tree.  Each of these new level-1 trees is now a branch of the level-2 tree.  You then keep on going, populating the level-1 trees until they have to simply split off, and make a new level-1 tree which they are connected to.
Could you draw a picture of that? *scratches head* Does every subtree become a single node in the L2 tree or multiple nodes? If multiple, how is the L1 tree subdivided to make L2 nodes?

I'm going to make my diagram "upside down", just for consistency in making people understand the concept of a "tree", where "higher tier" means "up", for those who aren't familiar with the customary way of dealing with trees in Computer Science.

Spoiler: large image (click to show/hide)

Anyway, it's not that much more complex than a regular tree - instead of a tree node containing a single map node's data, it contains a link to another tree (the red lines).  It's just using a minor bit of recursion in the data structure. 

If you understand trees at all, it's just a fairly simple extension of the concept.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 11, 2011, 03:57:29 pm
Nice interface.
Thanx, It could be better but it's functional (does what it supposed to do with little gimmicks).
I pressed A* and got a slightly "off" path though, so I'm wondering: what is the actual cost function you're using? one step costs 1? That would explain the path I saw but that makes several of the heuristics inadmissible.
there is currently no weights or adjustment to A* to fit DF exactly it's not really the point but I can add it along with traffic zones if I put my mind to it

The current default heuristic function is a vector magnitude sqrt(dx2 +dy2 ) it should be admissible i might want to Math.floor it to avoid floating point .
Also, there's another heuristic that might be relevant:
sqrt(2)*max(abs(dx),abs(dy)) + (1-sqrt(2))min(abs(dx),abs(dy))
that is, the smallest distance possible if you may only walk at 45 degree increments (which is true for dwarfs in DF, though not for projectiles).
I can easily add that one it's pretty simple to add heuristic functions to my program.

You can do a path smoothing after A* should give you a better result . I also improved path smoothing by drawing reverse lines - helps me avoid hitting walls but it's generally a work-around that seem to work .

The smoothing functions tries to shoot lines from node n to node n+2 if it has no obstructions it saves that line  it then shoots to n+3 and so on until it's blocked.  when a line is blocked it uses the longest line it found and replace the path with it. after that it advance to the end of that path and continue shooting vectors forward. It's not that bad in terms of complexity.

I'm thinking about corrective vector Pathing method which is a greedy method and it would probably won't work well. It will help flying creatures though. I just did something silly to see what happens when I do some spoilerific experimentation.
Spoiler (click to show/hide)


After my experiment I think Toady let A star run to worst case when there is no path . any hierarchical model would solve the problem.


And about  hash tables there are two kinds: bucket list and flat array.

The advantage of bucket list is that the table doesn't need to change or be very big  initially and it's easy to insert elements even on collisions. It's major disadvantage is memory thrashing . A link list structure that might be spread across wide memory areas. The array method's advantage is that it's easy to cache and you pay a lot less on collision the disadvantage is that with insertions and deletions it gets dirty  with "removed" and it also has a limit. This means that sometimes you may want to to get "rehash the table" or grow it.  picking a good hash is also usesful I think the preferable method is a combination of shifts and XORs (very cheap for a processor) even though a remainder function is commonly use it's very expensive in terms of processing. The size is  commonly a power of 2 to take advantage of binary &  (can be used as remainder for powers of two used for cyclical arrays).

So if someone wants to use a hash function they would usually prefer the complex but trusty flat array though I managed to do fine with the other variation and it gave me extremely good results (5us lookup on a 200Mhz core /33mh bus processor isn't bad). Complexity isn't everything in data structure and sometimes you can just do a linear search and it would be as fast as a hash table especially on a small N.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 11, 2011, 07:05:58 pm
A sorted hash-table index, however, would be very good for a situation where changes are few but queries many, by binary-search methods.  Each time you have to change the table, though you would have to insert each and every new item (binary-search for the pair just-above and just-below, by the search criteria being used, then shuffle the top 'half' upwards to make room) and remove each and every removal (reverse, by shuffling down the greater-thans).  You could make a compromise system in which a limited number of null data points get left behind after splicing out a point so that there's a chance that a spliced-in item can sit in a handy null-point, but that does slow the searching down[3], there's always going to be the possibility that a number of shifts[4], and certainly while increasing the number of hash-points being stored there's going to be a scarcity of null-spots and you're going to be increasing the table's size just as if it wasn't a null-filled version.  Never mind that you may end up storing an N point hash table in a 2N or more length hash table, which may again eat into any of the efficiencies you get.


I'm not saying that Hash Tables are bad, and as a Perlite I tend to (over?-)use them myself for convenience alone, but the purpose you're putting the hash-table towards might not be particularly conducive to the structure.  There isn't a magical 'black box' function that will let you store and retrieve hash values (including references) under a hash key in a straight O(c) number of CPU ticks.  You may even be optimising something by using hash lookup that was actually more optimal, despite itself, than the hash-maintenance and using process ends up being.

Sorry, I didn't remember that post. (How long ago was it?  This thread has kind of gone on for a couple months...)

I guess I didn't think about the cost of updating a hash table explicitly, I just went for the fastest way to search a list of nodes...

I'll try to think of a more dynamic method of sorting and retrieving data, then.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on April 12, 2011, 04:30:47 am
Sorry, I didn't remember that post. (How long ago was it?  This thread has kind of gone on for a couple months...)

Well, it turns out that I mentioned it in the relatively short post http://www.bay12forums.com/smf/index.php?topic=76278.msg2132502#msg2132502 (thought I'd written a lot more about it... maybe I did and edited it down... you may not believe it, but I do frequently edit my posts down, so that they're only massively lengthy, rather than their original state of being enormously long :) )

And I'd forgotten, for the moment, the linked-list version of hash-tables.  Yes, saves a bit of time shuffling elements up and down in a reserved area.  Which is why it's sometimes good to use assembler-level control (apart from the pain of debugging!) when it comes to trying to use one form of efficiency instead of another.  Perl, as mentioned, has Hash Tables but, without looking it up, I wouldn't know what back-end methods it uses to maintain them so they could quite unsuited for the efficiencies we seek.  (Not that I'm suggesting we write this stuff in Perl, that's just my own favoured prototyping language, after which I'd consider which lower-level coding approach could best implement all those handy (but often expensive!) short-cuts Perl provides. :) )
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 12, 2011, 06:10:37 am
Tell me what hash table you want and i'll find you the source code in google  ;) any language.

the optimal hashtable is so easy I can write it down from scratch.
simple table with key as first int element of struct :  ;)
Code: [Select]
#define EMPTY NULL
int removed=0;
#define REMOVED (void *) (&removed);
int size=0;
void ** table;
init(int n)
{
int i=0;
size=1<<n;
table=malloc(size);
for (i=0 ;i<size;++i) table[i]=EMPTY;
}
#define HASHFUNCTION(a) (a) /* find something better than this and replace*/
hash(int val)
{
return (HASHFUNC(val))&(size-1);
}
int insert(void * val)
{
int i,j;
i=*((int  *) val);
i=hash(i);
for(j=0;j<size;++j)
{
if(table[i]==EMPTY|| table[i]==REMOVED)
{table[i]=val;return 1;}
i=(i+1)&(size-1);
}
return 0;
}
void *  find(int key)
{
int i,j;
i=hash(key);
for(j=0;j<size;++j)
{
if(table[i]==EMPTY)
 return NULL;
if(table[i]!=REMOVED)
return table[i];
i=(i+1)&(size-1);
}


}
I happen to remember most of the common data structures  and I hope my coworkers at least understand how to use them  ;).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: FearfulJesuit on April 12, 2011, 09:15:14 am
Why shouldn't it be possible to have the computer calculate some lines that follow the best path fairly closely, and then the dwarf just goes along those lines and doesn't have to recalculate until it reaches the end of the line? Then the dwarf doesn't have to figure out where it's going again every time it takes a step. It'd make a 200-dwarf fort a snap.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Mohican on April 12, 2011, 09:29:17 am
Why shouldn't it be possible to have the computer calculate some lines that follow the best path fairly closely, and then the dwarf just goes along those lines and doesn't have to recalculate until it reaches the end of the line? Then the dwarf doesn't have to figure out where it's going again every time it takes a step. It'd make a 200-dwarf fort a snap.
how do you know if a line follow a path if you don't know the path?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 12, 2011, 10:12:13 am
Why shouldn't it be possible to have the computer calculate some lines that follow the best path fairly closely, and then the dwarf just goes along those lines and doesn't have to recalculate until it reaches the end of the line? Then the dwarf doesn't have to figure out where it's going again every time it takes a step. It'd make a 200-dwarf fort a snap.
My Path caching scheme does exactly that!

 check this example (http://niseg.0adz.com/test_maze.html?maze=v02AgAgAQEQEFBRwdHBwFEA0RAwAAAEAABABAAAQAQAAEAEAABABAAAQAQAAEAEAABABAAAQAQA7__97wBABQAAX_UAAFAVAABQFQAAV5UAAFLVAABWlQAAVtUAAFCVAABf1QAAQBEA7___7wBABAAAQAQAAEAEAABABAAAQAQAAEAEAABAAAAAQAQAAAAEAABABAA) . If you click "find path using waypoints" you'll notice it visits the waypoint. If you  clicked "smoothed path using waypoints" you'll see it doesn't use the waypoint anymore(same path finding with smoothing algorithms ran twice ). You can play with source and destination waypoints and shape . Take note that you'll have to update path cache after removing waypoints (a bug I didn't fix yet) and after changing the structure of the maze ( I don't validate cached paths yet before using them).

The waypoint save full cache to every other waypoint and try to go S->w1->w2->D unless w1==w2 and then it does A*. It's currently pretty dumb and I don't validate much, the smoothing scheme is also getting some improvements.

There are still problem with waypoint selection but it's intended for a system where the user selects the waypoint and he/she can pick optimal ones himself. Other waypoints can be used for invaders who enter at a fixed point

If you got a band of  "goblins" for example that waits for an open entry into the fort you can put 2 waypoints like this

########
+w#W++X#
########

the "goblins" can wait until there is a valid path between w and W which won't get updated too often (A* worst case where there is no path) and they only start moving when that's true.
how do you know if a line follow a path if you don't know the path?

With path smoothing that doesn't really matter. if you keep paths between certain key points it can be adjusted to lead to other points. close to them.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on April 12, 2011, 11:57:50 am
Why shouldn't it be possible to have the computer calculate some lines that follow the best path fairly closely, and then the dwarf just goes along those lines and doesn't have to recalculate until it reaches the end of the line? Then the dwarf doesn't have to figure out where it's going again every time it takes a step. It'd make a 200-dwarf fort a snap.

That's already how it works, it's just that figuring out the path that one time for each journey is relatively expensive.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: ji11 on April 12, 2011, 12:15:10 pm
Apart from improving the algorithm, shouldn't pathfinding be highly parallelizable? Could it be split between several of the computer's cores and run at the same time?

Right now it seems like only one (of 3) of the DF processes is active taking only one of my cores at a time (http://i.imgur.com/RJVZu.png)

Sorry if this has been discussed before...
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 12, 2011, 12:37:07 pm
This would mean that, you would find a route that goes through St. Louis, and then you search for more direct paths by cutting out whatever "middlemen" you can, resulting in a much more direct route.
Quote
Well, whether it's much shorter or merely cuts the very tip of the wedge next to St. Louis depends wholly on the coarseness of the map, doesn't it? If there are always at least two cities between the first and second "leg" of the trip, this modification won't make any difference.

Except it doesn't just trim off the very tip.  It compares every step of the journey for a shorter route between every point along the line.  This means that it will only path up to St. Louis if it has to go that far to find the correct relative distances in the tree for comparison, and then it could theoretically lop off that pathfinding all the way down to a simple path directly from one city to the other.

Let's take an example of two cities on opposite sides of a state boarder.  When you want to go across that state border into the next town, you would be transitioning not just cities, but also states.  This means you hop up from a street level to a city level to a state level to a national level of travel, then zoom back down to the city and street level.  But you don't need to travel back to state capitals to get there, you just need to check for the best lateral connection on the tree, which would involve simply driving down the nearest road across the border.
I was talking about only the tree-based pathfinding here, without also imposing the hierarchical scheme you suggested subsequently. If all you have are cities, not states or any larger groups, you'll still have the problem I describe. Just clarifying.

Quote
This works well if there are only a few entry points into a sub-map. There are only so many ways to enter St. Louis (on a major highway at least). But it will be worthless if there are loads and loads of entry points, such as will be the case for a general quadtree square over a DF map. And for anything larger-scale than individual rooms, which *may* have only a few doors out of it, it will be a monumental task coming up with an algorithm to decide the right way to subdivide the map into a large-scale clustering which minimizes the number of entry points.

This goes back to that hierarchical pathfinding thing I was talking about about ten pages earlier in the thread.

You can draw up all the pathways in and out of a node, but you really don't need all of them.  As long as you are pathing "through" St. Louis, and not actually going to some point inside of it, it doesn't matter that there are routes through St. Louis that aren't the Interstate, as long as the Interstate is the BEST path, that's all you need to remember.

You can check for plenty of routes from one point to another, but you only need to store the best route from one exit to another exit.  You can keep storing the different entry points, but these would only matter if you were looking for a specific point inside of St. Louis you wanted to reach where it might make a difference.
No, you misunderstand. I really meant passing-through. If St. Louis has only, say, 10 major entry points you need to store 45 costs. All well and good. But what about the state of Missouri? It will likely have hundreds of entry points, meaning thousands of costs to pre-compute and store.

I'll reiterate my main point: Hierarchical representations only help you if the world conforms to that hierarchy. Cities are natural clusters as far as pathfinding is concerned -states are not. Nor, as I said, are any Dwarf Fortress subdivisions except for "room" that I've heard proposed.
Star shaped topologies help you only if the world is star-shaped.
Quad trees help you only if the world has large square chunks of free space/occupied space. And if you impose a quad tree over a DF map, you're going to have an entry point count that is proportional to the length of the sides, meaning O(L^2) costs to be precomputed.

Basically: No free lunch. The only way to beat unbiased tile-by-tile BFS is to bias the search. A* biases in favor of worlds with straight-ish paths. Room-based nodes bias in favor of worlds which actually have rooms. Your tree search approach biases (heavily) in favor of worlds with a star-shaped topology. Your hierarchical search biases in favor of worlds with scale invariance.
Nothing wrong with any of this - one just have to go into it with open eyes. It happens to be my belief that both the star-shaped world assumption and the scale invariance assumption will be quite off in many, if not most Dwarf Fortress maps.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 12, 2011, 12:43:37 pm
Just a minor clarification: The no free lunch theorem mostly talks about time complexity. When you exclude a subspace of solutions as with your tree pathfinding you get around this and can be faster, but you still pay - in the quality of solutions. There's always a tradeoff somewhere.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 12, 2011, 12:49:43 pm
I pressed A* and got a slightly "off" path though, so I'm wondering: what is the actual cost function you're using? one step costs 1? That would explain the path I saw but that makes several of the heuristics inadmissible.
there is currently no weights or adjustment to A* to fit DF exactly it's not really the point but I can add it along with traffic zones if I put my mind to it

The current default heuristic function is a vector magnitude sqrt(dx2 +dy2 ) it should be admissible i might want to Math.floor it to avoid floating point .
That's not admissible if the step cost is 1. 4 steps diagonally would cost 4 in reality, but that heuristic is higher (4*sqrt(2)). The heuristic must be equal or lower. Same goes for some of the others.


Also, there's another heuristic that might be relevant:
sqrt(2)*max(abs(dx),abs(dy)) + (1-sqrt(2))min(abs(dx),abs(dy))
that is, the smallest distance possible if you may only walk at 45 degree increments (which is true for dwarfs in DF, though not for projectiles).
I can easily add that one it's pretty simple to add heuristic functions to my program.

You can do a path smoothing after A* should give you a better result . I also improved path smoothing by drawing reverse lines - helps me avoid hitting walls but it's generally a work-around that seem to work .[/quote]
Thinking more about performance than aesthetics, smoothing afterwards is too late - an inaccurate heuristic means the A* itself will take longer than necessary.
That said, certainly when A* yields a suboptimal path smoothing may give you something less suboptimal.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 12, 2011, 01:08:55 pm
The first option is that you can start from geometric isolation:
This means starting with splitting the map into cubes of geographic areas, and then looking to make sure that all nodes in those cubes connect with one another, and splitting of any cubes which do not have connectivity.  You then stitch together trees out of the nodes that are still in those geographic areas have connectivity, and then you build the next level of hierarchy as a way to get from one geographic area to the others.
Whoa, hold there. Let's assume without loss of generality that *all* the free space in the map is connected. What then? Just being connected can't be used as criterion for splitting space up - that would be meaningless! Space that isn't connected shouldn't be part of the same tree on *any* level!
You have to divvy space up on the basis of choke points, or maximum convex regions or some other heuristic. Which one though?

Of course they aren't part of the same tree if they aren't connected.

This isn't a problem at all - if you cannot find a connection for some reason, you just start building another tree.  Only connected nodes are connected to the same tree.  Connection on a tree IS the implication of connectivity on the map, after all.
Sure, disconnected trees aren't the problem. But you can't use connectedness as the criterion for splitting up space like in the quote. You have to make something else up, some heuristic - there's no free lunch.

Quote
The other option is that you can start from an arbitrary point somewhere in the "middle" of the map:
This works best with the innate nature of a tree data structure, upon further thought, since it relies upon some of its basic principles, and assumes some dynamic ability to shift to changing nodes.

Pick a node, any random node on the map. 

Now, you have to start connecting all its adjacent nodes to it as branches, and start building a tree.

During this process, the tree needs to "balance" itself, which is a basic function of many trees.  This means that the "root node" will change to be the node with the most roughly-equidistant leaf nodes hanging off of it.  (This means that you don't want a lopsided tree, if a branch becomes larger than the rest of the tree, the start of that branch becomes the new root, and the old root becomes a branch of the new root.)

Once you hit a certain point of complexity, say ten tiers on the tree structure, it is time to build the next level of hierarchy.  In this, the root node becomes not only a root node for the level-1 tree that we were building before, but also the root node of the level-2 tree, which acts as the geographical equivalent of moving from a city-level to a state-level of travel.  Each of those other level-1 trees becomes filled out with new root nodes for their level-1 trees, based upon the fastest connection to the root node of the level-2 tree.  Each of these new level-1 trees is now a branch of the level-2 tree.  You then keep on going, populating the level-1 trees until they have to simply split off, and make a new level-1 tree which they are connected to.
Could you draw a picture of that? *scratches head* Does every subtree become a single node in the L2 tree or multiple nodes? If multiple, how is the L1 tree subdivided to make L2 nodes?

I'm going to make my diagram "upside down", just for consistency in making people understand the concept of a "tree", where "higher tier" means "up", for those who aren't familiar with the customary way of dealing with trees in Computer Science.
[/quote]
I'm only a computer scientist by adoption, but I must say I've almost never seen a tree diagram that way up - it was you who was talking about going "down" when moving towards the root, before. But anyway, we know what we mean.

Quote
Spoiler: large image (click to show/hide)

Anyway, it's not that much more complex than a regular tree - instead of a tree node containing a single map node's data, it contains a link to another tree (the red lines).  It's just using a minor bit of recursion in the data structure. 

If you understand trees at all, it's just a fairly simple extension of the concept.
That doesn't really answer my question. How do you create that tree from a L1 tree? Could you draw the original next to it? Because, I'll be frank, it seems to me that you've missed some logical steps. Why didn't all the children of the original root node become L2 nodes, but only 3 of them?
(If the original root is St. Louis, how come some of its neighbors get to be states and some not..?)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 12, 2011, 11:43:58 pm
I'm going to break off answering this into discrete chunks at this point...

I was talking about only the tree-based pathfinding here, without also imposing the hierarchical scheme you suggested subsequently. If all you have are cities, not states or any larger groups, you'll still have the problem I describe. Just clarifying.

Well, the thing is that the tree-based pathfinding is optimized for finding a path with the least amount of processor time consumed possible.

It is NOT trying to find the optimal path for a dwarf to get from point A to point B in the shortest number of steps.  It IS trying to make the processing-time-optimal calculation to find ANY valid path.

You are complaining that the form of the function that isn't concerned at all with distance optimization isn't distance optimized.  Of course it isn't - it's not even supposed to be!

It's only the alternate versions, where we aren't optimizing one over the other that you have something closer to distance-optimization.  But it's still a tradeoff. 

It's like seeing a boat, and complaining about how it's really hard to handle on the Interstate.  It wasn't ever built to accomplish that function in the first place.


No, you misunderstand. I really meant passing-through. If St. Louis has only, say, 10 major entry points you need to store 45 costs. All well and good. But what about the state of Missouri? It will likely have hundreds of entry points, meaning thousands of costs to pre-compute and store.

I'm not misunderstanding, this is exactly what I was talking about.

Missouri might have 100 entry points, but you don't need to actually record all of them.  That's what I said about recording only the best of them. 

Missouri is only connected to, what, 5, 6 different states?  All you need to record is the best path if you are traveling through Missouri from one state to another.  Typically, this means you just stay on the Interstate the whole way through.

Yes, this means you'd have to pre-compute which paths are "best", but you'd either have to pre-compute them or else have to perform on-the-fly pathfinding no matter what pathfinding method you use, anyway.  The only question in which one is best depends mostly on the probability of the map becoming dramatically changed vs. how often dwarves will pathfind through those areas.

I'll reiterate my main point: Hierarchical representations only help you if the world conforms to that hierarchy. Cities are natural clusters as far as pathfinding is concerned -states are not. Nor, as I said, are any Dwarf Fortress subdivisions except for "room" that I've heard proposed.
Star shaped topologies help you only if the world is star-shaped.
Quad trees help you only if the world has large square chunks of free space/occupied space. And if you impose a quad tree over a DF map, you're going to have an entry point count that is proportional to the length of the sides, meaning O(L^2) costs to be precomputed.

Basically: No free lunch. The only way to beat unbiased tile-by-tile BFS is to bias the search. A* biases in favor of worlds with straight-ish paths. Room-based nodes bias in favor of worlds which actually have rooms. Your tree search approach biases (heavily) in favor of worlds with a star-shaped topology. Your hierarchical search biases in favor of worlds with scale invariance.
Nothing wrong with any of this - one just have to go into it with open eyes. It happens to be my belief that both the star-shaped world assumption and the scale invariance assumption will be quite off in many, if not most Dwarf Fortress maps.

But this is, again, completely ignoring some of the solutions to these exact problems I've already outlined.

If you want to optimize for direct paths, you have to use a method which trades performance in terms of processor power and memory storage in exchange for better distance pathfinding optimization.

I've already discussed different gradients of ways to do this - duplicate-information storage in the tree WILL enable trees to become less "star-shaped" by having the "star" overlap on top of itself. 

This is specifically HOW to avoid the "going to St. Louis to get to Pasadena" problem you were talking about - but you don't seem to be paying it any attention at all.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 13, 2011, 11:04:38 am
I'm going to break off answering this into discrete chunks at this point...

I was talking about only the tree-based pathfinding here, without also imposing the hierarchical scheme you suggested subsequently. If all you have are cities, not states or any larger groups, you'll still have the problem I describe. Just clarifying.

Well, the thing is that the tree-based pathfinding is optimized for finding a path with the least amount of processor time consumed possible.

It is NOT trying to find the optimal path for a dwarf to get from point A to point B in the shortest number of steps.  It IS trying to make the processing-time-optimal calculation to find ANY valid path.

You are complaining that the form of the function that isn't concerned at all with distance optimization isn't distance optimized.  Of course it isn't - it's not even supposed to be!

It's only the alternate versions, where we aren't optimizing one over the other that you have something closer to distance-optimization.  But it's still a tradeoff. 

It's like seeing a boat, and complaining about how it's really hard to handle on the Interstate.  It wasn't ever built to accomplish that function in the first place.
Good, we're on the level then. I just wanted it clear for the record that, on its own, the tree pathfinding though fast won't produce optimal paths (unless the map is star-shaped). Which is why you propose modifications/additions to it, to smooth that bias out. Nothing wrong with that.


Quote
I'm not misunderstanding, this is exactly what I was talking about.

Missouri might have 100 entry points, but you don't need to actually record all of them.  That's what I said about recording only the best of them. 

Missouri is only connected to, what, 5, 6 different states?  All you need to record is the best path if you are traveling through Missouri from one state to another.  Typically, this means you just stay on the Interstate the whole way through.
OK, sorry if I misunderstood; it looked like you were talking about within-unit pathing.

But this is not a solution if you think about it.
What's the "best" path from Arkansas through Missouri to Kansas? Looking at Google Maps, it looks like that's Bella Vista to Galena - about 25 miles.
What's the "best" path from Tennessee through Arkansas to Missouri? Crossing at Blytheville you can do it in 20 miles.
So - this proves you can get from Tennessee to Kansas in less than 50 miles. Or? I'm not being facetious here - try it yourself. If you had some other definition of "best" path in mind, what is it?

Keeping only one through-state(node) path cost is a major simplification which - unless there is only one entry point into each state "node" - will make for some completely wild paths. Plus, it would be near impossible to come up with an admissible heuristic for A* if you want to use that.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Sunken on April 13, 2011, 11:22:46 am
I'll reiterate my main point: Hierarchical representations only help you if the world conforms to that hierarchy. Cities are natural clusters as far as pathfinding is concerned -states are not. Nor, as I said, are any Dwarf Fortress subdivisions except for "room" that I've heard proposed.
Star shaped topologies help you only if the world is star-shaped.
Quad trees help you only if the world has large square chunks of free space/occupied space. And if you impose a quad tree over a DF map, you're going to have an entry point count that is proportional to the length of the sides, meaning O(L^2) costs to be precomputed.

Basically: No free lunch. The only way to beat unbiased tile-by-tile BFS is to bias the search. A* biases in favor of worlds with straight-ish paths. Room-based nodes bias in favor of worlds which actually have rooms. Your tree search approach biases (heavily) in favor of worlds with a star-shaped topology. Your hierarchical search biases in favor of worlds with scale invariance.
Nothing wrong with any of this - one just have to go into it with open eyes. It happens to be my belief that both the star-shaped world assumption and the scale invariance assumption will be quite off in many, if not most Dwarf Fortress maps.

But this is, again, completely ignoring some of the solutions to these exact problems I've already outlined.

If you want to optimize for direct paths, you have to use a method which trades performance in terms of processor power and memory storage in exchange for better distance pathfinding optimization.

I've already discussed different gradients of ways to do this - duplicate-information storage in the tree WILL enable trees to become less "star-shaped" by having the "star" overlap on top of itself. 

This is specifically HOW to avoid the "going to St. Louis to get to Pasadena" problem you were talking about - but you don't seem to be paying it any attention at all.
That's a pretty uncharitable thing to say. I've said that the "shortcut" solution you suggested won't cut it unless you can show how it is combined with your hierarchical scheme, and to my mind you haven't yet. That's not "not paying attention".
I keep asking questions because I think you will find things far more difficult than might be first imagined if you really get down to the details. That's my experience at least: I've spent hundreds of hours trying to implement similar things, most of that time on things I'd never have expected to be so hard.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: MercuryP on April 13, 2011, 12:37:35 pm
But this is not a solution if you think about it.
What's the "best" path from Arkansas through Missouri to Kansas? Looking at Google Maps, it looks like that's Bella Vista to Galena - about 25 miles.
What's the "best" path from Tennessee through Arkansas to Missouri? Crossing at Blytheville you can do it in 20 miles.
So - this proves you can get from Tennessee to Kansas in less than 50 miles. Or? I'm not being facetious here - try it yourself. If you had some other definition of "best" path in mind, what is it?

I confess I'm not particularly engaged in this topic, but wouldn't doing things this way defeat the whole purpose of having nodes in the first place?  The whole point of nodes is to pick out important positions on the map and find paths according to those.  Namely, these important positions would be the centerpoints of each node.  So finding a path from Arkansas through Missouri to Kansas would require said path to travel through the center of Missouri.  I'm thinking it would probably need to be relative to the centerpoints of Arkansas and Kansas, too.

You can smooth things out later by doing regular intranode pathfinding at each node along the way.  If the nodes make sense, this should be a larger quantity of very cheap calculations relative to what the game does now, and the cheapness should more than make up for the larger quantity.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 13, 2011, 12:44:03 pm
You can smooth things out later by doing regular intranode pathfinding at each node along the way.  If the nodes make sense, this should be a larger quantity of very cheap calculations relative to what the game does now, and the cheapness should more than make up for the larger quantity.

Quite.  Smaller search space.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 13, 2011, 01:07:52 pm
That's a pretty uncharitable thing to say. I've said that the "shortcut" solution you suggested won't cut it unless you can show how it is combined with your hierarchical scheme, and to my mind you haven't yet. That's not "not paying attention".

But I HAVE shown it, in four different ways.  Two had pictures.  I'm running out of different ways to show it.  I've never mentioned this shortcut method in any setting OTHER than in the setting of a list of nodes produced from a tree.

Look, I'll just draw another picture:
Spoiler (click to show/hide)

The pathfinding constitutes a list of nodes it has to traverse to find A path to the destination node from the green node on the left to the green node on the right.  (All nodes not involved in this linked list (which would not be formed in tree form any longer, but a linked list) are removed. It has to cross into a level 2 search, going from blue nodes into the larger black, level 2 nodes, like in the last picture.  It then starts testing each and every node it had to cross to see if there are shortcuts, paths between the nodes that you had to cross in order to find a quicker way - and that's what the cyan line is. 

It finds a connection stored in the node (not the data tree's list of "higher nodes") that is a connection from one level 1 node to another level 1 node in a different pair of level 2 nodes.  It then cuts out all the middlemen and jumps directly across the data structure, finding a much shorter path that doesn't involve those other level 2 node areas at all.



And the reason my tone is getting rather frustrated at this point is that you keep trying to tell me the things I just explained to you, as if they were a problem.

I KNOW there is no free lunch, I just explained that. 

I know what the limitations are, I was the one who pointed them out first, while I was explaining them.  That's why I came up with solutions and workarounds.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: MercuryP on April 13, 2011, 02:32:39 pm
Okay, so here's a question.  It's obvious that you have to split the map up into nodes larger than a single space in order to improve the pathfinding.  You can't really improve upon A*, so you trade space for time.

So the map's split up using some elegant node-choosing algorithm.  This alone is going to speed up pathfinding considerably.  When I try to get out of a building when I'm on the third floor, I don't first try and go through the floor below me, then search for an alternate path.  I path to the door, then I path to the stairs, then I path down to the first floor, then I path to the exit.

So why do a tree, as opposed to just A* on the nodes?  It seems like A* on nodes would be fast enough in and of itself, and would be easier to implement.  I mean, I think the tree is a great idea and I don't see any problems with it, but does it have any advantages other than a little more speed?  Or would it really be that much faster?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 13, 2011, 02:34:33 pm
So why do a tree, as opposed to just A* on the nodes?  It seems like A* on nodes would be fast enough in and of itself, and would be easier to implement.  I mean, I think the tree is a great idea and I don't see any problems with it, but does it have any advantages other than a little more speed?  Or would it really be that much faster?

That's what I've been thinking.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 13, 2011, 07:12:23 pm
You can smooth things out later by doing regular intranode pathfinding at each node along the way.  If the nodes make sense, this should be a larger quantity of very cheap calculations relative to what the game does now, and the cheapness should more than make up for the larger quantity.

Sorry to have not responded to this one earlier, but I wanted to focus in on speaking to Sunken at the time. 

Yes, this is exactly what I was suggesting doing - making a larger, looser set of nodes, and just allowing A* within the barriers of the current node to pathfind to the destination (possibly with a steering bias to help avoid collisions).

Okay, so here's a question.  It's obvious that you have to split the map up into nodes larger than a single space in order to improve the pathfinding.  You can't really improve upon A*, so you trade space for time.

So the map's split up using some elegant node-choosing algorithm.  This alone is going to speed up pathfinding considerably.  When I try to get out of a building when I'm on the third floor, I don't first try and go through the floor below me, then search for an alternate path.  I path to the door, then I path to the stairs, then I path down to the first floor, then I path to the exit.

So why do a tree, as opposed to just A* on the nodes?  It seems like A* on nodes would be fast enough in and of itself, and would be easier to implement.  I mean, I think the tree is a great idea and I don't see any problems with it, but does it have any advantages other than a little more speed?  Or would it really be that much faster?

I started thinking about the tree-based pathfinding idea when I was considering how to work multiple nested hierarchies and trying to get the game to recognize high-traffic hallways as compared to dead-end rooms.  My mind's image of the hierarchies led me to thinking about quad trees, and I realized that a tree-based search structure would allow us to pathfind without having to use some variation of A* at the more abstract hierarchies. 

To put it in terms of leaving a building, you don't think "I need to pathfind down 30 feet, north 25 feet and east 10 feet," you think, "to reach the exit, I need to get to the ground floor, and to get to the ground floor, I first have to go to the stairs."

The advantage of a tree-based search over some modified variation on A* is that you don't have to do the sorts of loopy heuristics that get complicated in a very abstract hierarchical search.  A* relies upon the heuristic to make its guesses, and when you don't have a way to make a general guess about what direction a given node lies down, it can become fairly problematic. 

A tree-based search is also not that hard to implement at all - it's a fairly rudimentary data type in very common use for finding data quickly.  There are degrees of complication that arise the more accurate you wish to make the search in exchange for greater use of memory, but these seem to be far more complex for me to explain to people than they actually would be to program.  A tree is simply a more abstract means of thinking about things (like "I need to go to the nearest stairwell") as opposed to the more direct A* ("I need to follow this wall until I find a passage that leads downward"). 

A tree-based search is faster than A* with a loopy heuristic that has to make a bunch of guesses on every connecting node, but it depends on how much you want to optimize for walking distance, and not just upon conserving processor power.  If you throw in too many trade-offs that trade memory for precision, then A* could potentially just be worth the memory you take back.  The exact crossover point on this is based largely upon the subjective relative value you are placing upon accuracy, processor consumption, and memory consumption at the time, however, so if you really want to argue for one over the other, there's a case for several different paths.  A* can potentially use up less memory, but use up more processor power.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: MercuryP on April 13, 2011, 09:28:30 pm
I don't really see why A* itself would get complicated, though.  You find nodes, find direct paths between adjacent nodes, then do A* with the standard distance-from-destination heuristic using the points where the nodes connect to each other as your search graph.  Admittedly, the heuristic is not conducive to picking out the proper path without a significant level of failure, but if the nodes are few enough does it really matter?

I do see your point though.  If you have a hallway of bedrooms, it makes a lot of sense not to try and go through the other bedrooms when you're pathing out.  With most of the things that get built in DF, trees make a whole lot of sense.  Buildings with rooms and hallways and exits and such.

I'm curious about what would happen with wide-open spaces, though.  What about outside the fort?  Is the whole exterior going to be one node, or will it be sliced up into smaller blocks?  If you slice it up, then you have a lot of pieces connecting to each other, and that doesn't much fit into a tree.  You can arbitrarily assign a top node and then file things away, sure, but you'll end up in situations where the paths are extremely suboptimal.

In terms of the US map, you're going from AZ to WY, and the root node is OK, so you pick out a path AZ->NM->OK->KS->NE->WY.  That's six steps from something you could do in two.  You can't find a shortcut since there's no direct path between any of the nodes you're going through.  I know the goal isn't to find an optimal path, but take this a few steps further out (Florida to Maine?) and you end up with paths that aren't even good.  A slightly meandering path is one thing, but your dwarves could easily end up prioritizing a point in the middle of nowhere that has no real significance to your fort.

It seems like the best thing to do here would just be to make the entire outside area one single node, or a few very very large nodes.  That way the high-level nodes would be a lot more likely to end up in the right places, and you wouldn't have a faux-tree of nodes that are all really connected to each other.  But doing that makes it hard for me to wrap my head around how you would go about splitting up the map into nodes in the first place.

You've probably considered/discussed this already, so apologies if I'm rehashing things you've already been over.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 14, 2011, 12:08:07 am
I'm curious about what would happen with wide-open spaces, though.  What about outside the fort?  Is the whole exterior going to be one node, or will it be sliced up into smaller blocks?  If you slice it up, then you have a lot of pieces connecting to each other, and that doesn't much fit into a tree.  You can arbitrarily assign a top node and then file things away, sure, but you'll end up in situations where the paths are extremely suboptimal.

In terms of the US map, you're going from AZ to WY, and the root node is OK, so you pick out a path AZ->NM->OK->KS->NE->WY.  That's six steps from something you could do in two.  You can't find a shortcut since there's no direct path between any of the nodes you're going through.  I know the goal isn't to find an optimal path, but take this a few steps further out (Florida to Maine?) and you end up with paths that aren't even good.  A slightly meandering path is one thing, but your dwarves could easily end up prioritizing a point in the middle of nowhere that has no real significance to your fort.

It seems like the best thing to do here would just be to make the entire outside area one single node, or a few very very large nodes.  That way the high-level nodes would be a lot more likely to end up in the right places, and you wouldn't have a faux-tree of nodes that are all really connected to each other.  But doing that makes it hard for me to wrap my head around how you would go about splitting up the map into nodes in the first place.

You've probably considered/discussed this already, so apologies if I'm rehashing things you've already been over.

Yes, this is exactly the thing that Sunken has been talking about, and I don't particularly feel like rehashing right now.

Suffice it to say, there are ways to overcome this deficiency, and it involves consuming more memory by storing duplicate paths.  Basically, you could consider Wyoming "up the tree" from both Colorado and Nebraska.  In that case, you go from AZ->NM->CO->WY.  It's not the fact that it's "three steps" that matters, though, it's the total distance you traveled, and whether or not it was the most direct route - a trip that passes through Nevada and Utah is going to be longer than a trip through New Hampshire, Massachusetts, and Connecticut, even if it's only passing through two states, rather than three.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: MercuryP on April 14, 2011, 06:31:57 pm
Yeah, I see what you mean.  A tree just doesn't seem to be a particularly good model for open areas, though, even if it can be made to work.

So let me attempt to contribute an idea on top of the tree.  I was trying to think along the lines of networking, but what I came up with was a little different.  The entire map is a tree-ish sort of thing where each node is either:

a) a single map node
or
b) a graph consisting of exactly one cycle of nodes

Something like this:

1) Split the map into nodes.
2) Make a node graph.
3) Look for cycles, starting with the smallest available cycle (measured according to game distance).  Treat these as singular nodes in the remaining graph, and repeat until there are no more cycles.
4) The remaining graph will of course be a tree.

Without cycles, this is the same as a regular tree.

What about large rings?

Code: [Select]
o........o........o........o........o........o
.                                            .
.                                            .
.                                            .
o                                            o
.                                            .
.                                            .
.                                            .
o                                            o
.                                            .
.                                            .
.                                            .
o........o........o........o........o........o

When pathing to the opposite corner, you can end up going the wrong way pretty easily.  But we know it's a cycle, so that can be used to advantage by storing a clockwise distance index (to distance to the centers of the nodes relative to an arbitrary starting position) and a full cycle length.  Since there are only two options for directions to go in, it's pretty easy to pick the right way.

So that covers halls of bedrooms (no cycles), and covers two-dimensionally ringed hallways.

What about double rings?

Code: [Select]
o........o........o........o........o........o........o........o........o........o........o
.                                            .                                            .
.                                            .                                            .
.                                            .                                            .
o                                            o                                            o
.                                            .                                            .
.                                            .                                            .
.                                            .                                            .
o                                            o                                            o
.                                            .                                            .
.                                            .                                            .
.                                            .                                            .
o........o........o........o........o........o........o........o........o........o........o

First you condense, say, the left ring into a single node, and then you're left with a single ring, wherein one of those nodes is abstracted.  So how do you store the clockwise distance index for the abstracted node?  The same way as before, using the "center" (the midpoint between the two end connecting nodes).  Since it's counting actual game spaces, it should still work correctly.

Okay.  How about two adjacent floors of ringed hallways with stairs in the four corners?

Code: [Select]
2D simulation
...,................................................................................................
.                                                                                                  .
o........o........o........o........o........o........o........o........o........o........o........o
.                                            .        .                                            .
.                                            .        .                                            .
.                                            .        .                                            .
o                                            o        o                                            o
.                                            .        .                                            .
.                                            .        .                                            .
.                                            .        .                                            .
o                                            o        o                                            o
.                                            .        .                                            .
.                                            .        .                                            .
.                                            .        .                                            .
o........o........o........o........o........o........o........o........o........o........o........o
.                                                                                                  .
...,................................................................................................

It gets a little confusing here, but it still works as far as I can tell, and as long as the smallest cycles are the most internal, the chosen paths are still good.

And now what about the wide-open exterior of the fort?

I was hoping to come up with a way to consolidate the entire exterior into one network-esque node and just do regular pathfinding on that, but I think a huge nested graph of 3-node cycles actually works pretty well, again provided that the smallest cycles are furthest down the tree.  That way, pathing basically goes to smaller and smaller regions until it pinpoints the target location.

There are some calculations to be done with the centerpoints of the nested cycles, but I don't think it would be a huge problem.    It's not overly memory friendly, but probably wouldn't be too terrible.  The advantage it has over the regular tree, provided that I'm not missing some obvious counterexample, is that you won't need the "find a shortcut" algorithm or to store alternate paths at all, the paths that do get found are very reasonable, and since routing through a cycle is "intra-node routing" as far as the overall tree is concerned, the main algorithm is no slower.  And with the clockwise node indexing, routing through the cycles should be fast as well.  Going in and out of and passing through the sub-cycles does get a little complicated, though.

I feel like I'm missing something that makes this idea entirely worthless, but it's not readily obvious to me.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Aquillion on April 14, 2011, 08:09:17 pm
You can't really improve upon A*
You totally can if you use more specific heuristics.  A* is a very good general-case solution for a totally random graph, but if you know some general features of the graph beforehand, you can use heuristics customized to the case you're dealing with to speed up pathfinding, sometimes immensely.

More importantly, though, the slowdown in DF's pathing probably doesn't have anything to do with the abstract speed of the algorithm; it probably has to do with how it interacts with the limitations of architecture.  On a really really huge graph, like the ones DF works with, the slowdown isn't going to directly be from the processing itself, but from the cost of accessing that huge graph in memory.  Specifically, because access is so unpredictable, and because the graph is too big to fit into your cache, you have to go to RAM constantly.  While RAM is fast, sure, when you're doing a huge series of calculations, you want to be able to keep as much as possible in your cache -- as a result, simply applying A* mindlessly to a huge graph is going to end up being much less efficient than you would think, because most of your time is wasted fetching stuff from RAM to the processor.  Even those few milliseconds add up when you're forced to fetch from RAM for every step in the graph that you take.

Eg. see the abstract for this (http://portal.acm.org/citation.cfm?id=945395) paper, which touches on the problem.  A* and Dijkstra's algorithm in general was set up to minimize computation time, not to reduce access; but nowadays, access is the real bottleneck, at least when dealing with graphs that are too huge for caching to eliminate the issue.

(There are other issues, but this should give you the general idea.  It's a very common mistake to fall into the trap of saying 'oh, I have a beautiful, perfect-looking algorithm, I'll just use that!' without considering the actual constraints placed by your hardware.)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on April 15, 2011, 09:12:14 pm
More specific heuristics?
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on April 16, 2011, 04:35:47 am
More specific heuristics?
I must say that I remain a bit wary about "Well, we know there'll be corridors and rooms..." coming into discussions about how to make a better A*, or why to swap to a 'better'-than-A*-when-it-comes-to-corridors-and-rooms system.

Not to say that I don't like the various solutions being brought forward, but just because one player uses a basic 3x3-grid-and-doorways[1] doesn't mean that another player doesn't do 3x3-grid-with-columns[2] or 3x3-grid-with-nothing![3], among others (I didn't even bother to draw diagonal doorways, but I know they're popular) not even taking into account stairwell placement issues.  And there are players who do more aesthetic (less grid-like) layouts with diagonals, even approximations of curves, or are almost entirely open-plan or opportunistic within dug-out veins and other deposit minings.  Some will go for closed-path systems[6] that should be a pathing algorithm's dream.  Certain pathing algorithms, anyway, but others might struggle.

 
Personally, I tend to go for a variety of "filled 11-blocks"[4] within a corridor framework, according to need, and even my corridors might be simple or fancy[5].

Combined with the (near-)open nature of the surface topology and the different ways the various cavern setups might appear, I can only suggest that anyone suggesting a solution optimised for a typical playing-style/fort-layout should look at least at the 'natural' environment, and probably into other layout designs being used (even intermingled in the same fort!) and do a sanity check to see if they're in danger of de-optimising those areas.

Which is not to say that A* is the best-all-rounder, even, I hesitate to add.  And I know people already design their forts according to the vagaries of A* (e.g. walling off unused areas of the fort as a nod towards helping the A* from not investigating that easily-taken dead-end), even while others just ignore it all.  Under a different scheme the former can change styles again, if necessary, while the latter keeps on ignoring the issue (for better or worse).


A long, long time ago, though, in a completely different thread, I mentioned one improvement to pathing that might help (and might easily help immediately, with a suitably annotated A* scheme).  When going to dig out a tile (or otherwise make passable one that's currently impassible), give that destination tile an "honorary passable" status for the purpose of that particular path-finding search and then cut the found path short by one tile to find the actual work-spot.  This way you don't get dwarves standing directly SE of this block, now seeking to cut it out, finding that the westerly tile is a viable dig-spot and then seeking the long path around a mountain to make that dig.  Nor do you get dwarves checking the westerly-tile path, then various other paths to any other access points until they finally get to checking the path to the SE tile, which trumps it and throws all the other pathing effort in the bin, which would be the other solution (saving on dwarf-time, but wasteful of pathing-time).

Instead: Let pathing algorithm know that dig-block is valid destination for this journey; Pathing algorithm (of most sensible types) almost immediately determines that the best path to dig block would be to go NW, and no further; Because it's a dig-job, pop the NW off of the stack; Travel instructions = stop here; Commence to dig to NW.

(If relevant to instances where only orthogonal working is actually legal, would need slight modification to prevent 'illegal' last-steps, but minimally so.)

Should an alternate method be implemented, I'd very much like the above to become a realistic possibility, in some form that does not require a complete tree-graph overhaul, of course, or risks sending other nearby dwarves towards the not-yet-passable tile in advance of its removal. (If they're far enough away, already, they could anticipate, but I think keeping the passability-in-potentia local to the specific miner's path-search data would be wiser and might be simpler.)




[6] Main marble rock-race opens only into stone workshop opens only onto various stockpiles clumped together opens onto Trade Depot, tree-farm only leads to wood stockpile only leads to carpenter only leads into various furniture stockpiles leads to central stairwell for distribution, ore-vein is mediated by ore stockpile, smelter, metal stockpile (maybe others along those lines) and forge then metal goods/weapons/armour/etc stockpiles, etc, and I won't even describe such a farming layout, although I've got a nice one planned that one day I'll actually establish properly!)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 16, 2011, 09:35:01 am
Need I remind you that we want a pathing algorithm that is "fast" not "110% dead spot on finds the shortest route."*

Organizing the map into room/corridor nodes and A*ing that will return sub-optimal paths on occasion.  This is OK.  Finding the absolute shortest path every time is why pathing is so CPU intensive.

*Doing the pathcheck to the impassible-to-dig tile does save CPU, yes, but the point remains: we're not trying to find the best path we're trying to find a reasonably short route quickly.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 16, 2011, 10:39:52 am
Yes, that's basically been what I've been saying with the tree structure this whole time.  It's meant to be fast, not accurate.

As for the problem of large, open areas, I think the best solution I can come up with would actually be to just make the whole surface before you start carving it up one giant node, unbounded by size limitations.  Then you just A* across the giant node.  As long as all you have is an open field where slopes don't matter and only occasional trees as obstacles, A* is perfectly fine. 

It's only in areas where you have something like a river bisecting the map, or sheer cliff faces, that you need to split that up into nodes that a tree would handle. 

That, alone, would be enough to clean up the big weakness in the tree method for handling large open areas.

Still, after a certain point, I'm just plain getting tired of defending the tree method, and am willing to just go back a few steps in its evolution, and talk more about building a pathfinding tree solely as a means of identifying what are rooms and what are hallways, and then using A* through the resulting structure.  (This seems to be what Draco18s favors.) 

Multiple hierarchical levels of node structure, again, make the whole thing more efficient, especially since the top levels of the hierarchical structure can just store "best routes" for long-range pathfinding.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Setharnas on April 16, 2011, 10:56:49 am
What Draco said. I would even go so far as to suggest that simply splitting each z-level into 8x8 squares annotated with portal information and running HPA* over that first could have additional usage - as in, introducing additional annotations that say "this square has wood resources. this square has metal resources. this square has building-grade rocks." and changing the 'where do I get the next block of stone for this wall?' search to a hierarchical breadth-first search. Best effect if the squares also hold z-connectivity annotations - a rock that's located just one z below on the same x/y would only be found if the area BFS actually got that far. Why only resource classes (rock/metal/wood) as annotations? Because that is what the game is interested in the most usually. If actual materials are needed, an extra search can be executed that builds lists the old fashioned way.

The whole point of hierarchical path finding is to first work on a simplified abstraction of the map, ideally with a set of nodes that completely fits into cache (as much of a pipe dream that may be for DF). It basically returns a burrow that actually limits all pathing for that particular path request. The whole path caching idea is just icing on the cake - I would much rather attempt to tackle that in combination with a user-set waypoint system.

I consider the room-node identification method as achievable (I know it has been used in continuous space environment games before, and grid based is just a special case of continuous based environments), but computationally too risky for the stuff DF players come up with.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Starver on April 16, 2011, 11:55:55 am
*Doing the pathcheck to the impassible-to-dig tile does save CPU, yes, but the point remains: we're not trying to find the best path we're trying to find a reasonably short route quickly.

You missed the point I was making with that bit, it seems.  The best path-checking in the world (being somehow fastest and best and the least CPU intensive, if such a chimeric beast could even exist) returning the round-the-mountain solution is as much in error as the current system.  Even if it did it with a fraction of the effort.

Even a "reasonable route, quick-processing, low-memory footprint" version that still ends up tracing a route hundreds of tiles long (or through however many zones/nodes/whatever) not only wastes dwarf-time, but also impacts the FPS compared to the one that says "Hmm, I can dig that from here" and needs to go no further.  This applies to "walk three steps and I can mine that square from there" cases as well, or any arbitrary distance that's still a fraction of the illogically long distance round to the other side, so while a preliminary "check to see if diggable tile is next to (or nearly next to, or nearly nearly next to) dwarf seeking to work that tile" is a viable option in the extreme example, you'd still end up making the long-distance route-checking if it was just one step beyond your threshold for checking this fact.  Unless you grant the target temporary accessible status of some kind, when it's all done as part of the necessary pathing check in the first place, no extra fuss.

That was the point.


I'm actually not as bothered about massive amounts of speed improvement at the expense of 'accuracy', where some speed improvement might still be had for a totally accurate version. To compare with image formats, I'd go with PNG over JPEG, but both are better than BMP or 'Portable[Bit|Gray|Pix|]Map' representations (especially P1, P2 or P3, in the latter case).  However, I'd live with whichever, if that happened[1], and I just thought I'd take the opportunity to mention a small consideration that all algorithms should at least consider (even though it might not be practical[2]) before someone ends up getting a system implemented (of whatever quality) that doesn't even consider this... well...  consideration.

But having made this point, I shall go back to either lurking or being constructive (or otherwise) regarding the other general issues, depending on how the discussion goes.


[1] The main problem is that as well as 'absolutists' insisting on the "one and only best route, whatever the cost (albeit as low as can be had!)", there will be people who think that one system is 'good enough' but that another is 'not quite good enough, even if faster', and a third is 'much better than it should be, and too expensive for all that'.  At least among the "one and only best" people there's no shifting grey line to be argued over. :)

[2] I think it should be for most systems, given it's a temporary allocation anyway, I could see certain zone-based algorithms actually adding the "target tile" as a zone of its own (or extension of other zones) for up to 5[3] different neighbouring zones, in a manner that would technically be an illegal duplication/overlap under the more strict systems.  And each of those connecting 'diggable-froms' could be at the end of indeterminately long corridors winding around who-knows where.  And the first four/five choice to access the dig site could be lead anywhere, through all kinds of terrain (external, cavernous, dwarf-dug into either easily-navigable layouts or labyrinthine messes, etc) horrendously difficult to path and time-wasting to cycle through each of them, and possibly the absolute worst-case scenario to attempt to go by the current priority scheme.

[3] i.e. if it was a stairwell tile being dug with a pre-existing stairwells dig/constructed into existence above and below and up to three different neighbouring incursions[4] on the same level, e.g. W, NE and SE.  Hmm, actually, there's possible arguments for six different neighbouring digging-points if it's a ramp to be dug with pre-existing W, NE, SE access on lower level and E, SW, NW on the upper, if I'm not wrong about ramps being able to be dug diagonally from Z+1.

[4] With four, there'd be diagonal passage between them, invalidating the example.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 17, 2011, 08:56:58 am
I just skimmed through the recent responses:
- suboptimal paths can be smoothed using a simple line drawing algorithm try this maze (http://niseg.50webs.com/test_maze.html?maze=v02AgAgAQEVEFBRwdHBwFEA0RAwAAAEAABABAAAQAQAAEAEAABABAAAQAQAAEAEAABABAAAQAQA7__97wBABQAAX_UAAFAVAABQFQAAV5UAAFLVAABWlQAAVtUAAFCVAABf1QAAQBEA7___7wBABAAAQAQAAEAEAABABAAAQAQAAEAEAABAAAAAQAQAAAAEAABABAA) , click on "find path using waypoints", then click on "smooth Path (LOS search)". You'll see my loop chopper (nlog(n) ) and then line smoother (currently bounded by  n^2/2 ) turning a suboptimal path into an optimal one. The example path smoother generates a  lines with total length of 650 nodes  on 131 length path  which is less than nlog(n) ( i got a debug value called ntracker in smoother and i put a breakpoint in Chrome). I still need to optimize those smoothers they aren't that bad comparing to path finding complexity.

- I didn't look at the tree stuff yet (seems complicated)

-I've tried experimenting with heuristics if you got a suggestion for a good one ( I still need to add one I saw somewhere on forum but i lost it  :().

- the caching problem can be solved by a few bit vectors who represent the entire map . it would take about 56KB per 200 height embark square. or 900KB for a 4X4 map . holding 1 vector for walkers,flyers,swimer,magma walkers would take about 3.6MB. due to the locality most of the data fetches would be local. As far as I think Toady might be doing something similar to that  because I've seen linear improvement in FPS while keeping memory speed constant while raising CPU speed

I'm going with my waypoint room implementation you can enable the checkbox and click redraw to see my simple arbitrary room selector ( might change it).

I thought about creating a direct LOS heuristic which would be high complexity but would probably give better accuracy at leading to the target.  The idea is if you try to go toward your destination with a straight line and hit an obstacle you'll have to at least go around it which is about 2 moves.

here is an example  (http://niseg.50webs.com/test_maze.html?maze=v02AJAJCAIDCQIhEIgEAgkEAgEC)
Spoiler (click to show/hide)
* is the A* path ( ::)  just found a bug I manually fixed)   .


if the penalty for hitting an obstacle is 3 and you are at point a . The closest point is North with simple heuristic  but if you draw a straight line you hit 1 obstacle so instead of  score of   about 2.5 you get a score of about 5.5 due to the penalty.  the point SE is about 4 away but because there is a clear line (somewhat need to sort out the ends  ;)) to the destination there is no penalty.

Well I need to implement it to see how well it works :-\ this example is hand drawn so I don't know the true path.



EDIT: if you check my WP room example you can see the paths between them - I thought I could avoid diagonals but now I have to add them back in. The paths are found by doing a limited heuristic A* which is limited to 16. I'll add back the diagonals and update.
EDIT2: added diagonals made, a single recursion with double the search limit on dead ends nodes.
EDIT3: I hammered out the bugs in room based waypoint path finding it's still not full proof and I doubt It would work when there is no path to the destination(that's the next stage).  I also need to add more freedom in wp room selection.
EDIT4:traffic zones added to the simulation as separated A* search.
EDIT5: changed links
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Phoebus on April 22, 2011, 07:25:06 pm
I just did a bunch of pathfinding test.

I rate DF's pathfinding engine with an F-.

Literally, even within the mindset of only using a A* search algorithm, everything about the pathfinding engine has been done wrong.
EVERYTHING.

1. The heuristic estimate is of 1 per tile, not 2 per tile as it should be. That incurs an ridiculously huge performance penalty (1000x the cost or more in common otherwise optimal A* scenarios) for the sake of naive traffic cost agendas.
2. The algorithm values the Z axis less than the horizontal axis. Optimized for ramp seeking greed, the A* algorithm searches every Z levels (between the origin and the target) in hope of finding a ramp. Incredibly stupid 'optimization' for the sake of trivial outdoor pathfinding. Sane DF heuristic should value underground Z levels as a top priority. Stairs/Ramps are relatively rare, and should be highly valued when they are found.
3. The system uses taxicab heuristics, but non-taxicab movement costs. Wtf really.

- DF A* pathfinding algorithm should use non-taxicab heuristic horizontally, but not vertically. Ex.: max(abs(x1-x2), abs(y1-y2)) + abs(z1-z2)
- Optionally, outdoor heuristics should also have an option (on by default) to also use non-taxicab vertically, for the sake of the outdoor ramp layout. Ex.: max(abs(x1-x2), abs(y1-y2), abs(z1-z2))
- The basic heuristic estimate per tile should equal or greater than the cost for 'Normal Traffic' by default, and it's also very important for it to be customizable, as tweaking the traffic cost values is pointless unless we can also change the heuristic estimate. An heuristic estimate smaller than normal traffic cost invariably results in A* bombs.
- There should be an independent heuristic estimate value 'bonus' for Z-levels, preferably configurable too.

No matter how much you tweak the A* algorithm, it is NOT going to be less than disastrous in it's worst case scenarios, which are common in DF.
A* well configured as listed above is VERY efficient at pathfinding to a reachable target on the same z-level, tweaking it away from that will make it much worse at what it's good at, and barely any better at what it's bad at. Don't do it.
A* well configured as listed above is also much more efficient at pathfinding through non-maze forts, for example using access shafts.

Fixing A* worse case scenarios will require a solution like implementing a node system engineered around vertical access points. I repeat, tweaking A* will not fix anything.

The worst case pathfinding scenarios for DF are:
- Not being able to reach the target.
- Needing to move to a Z-level further away from the target to reach the target.
- Maze like architecture.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 23, 2011, 09:19:53 am
2. The algorithm values the Z axis less than the horizontal axis. Optimized for ramp seeking greed, the A* algorithm searches every Z levels (between the origin and the target) in hope of finding a ramp. Incredibly stupid 'optimization' for the sake of trivial outdoor pathfinding. Sane DF heuristic should value underground Z levels as a top priority. Stairs/Ramps are relatively rare, and should be highly valued when they are found.

- DF A* pathfinding algorithm should use non-taxicab heuristic horizontally, but not vertically. Ex.: max(abs(x1-x2), abs(y1-y2)) + abs(z1-z2)
- Optionally, outdoor heuristics should also have an option (on by default) to also use non-taxicab vertically, for the sake of the outdoor ramp layout. Ex.: max(abs(x1-x2), abs(y1-y2), abs(z1-z2))

I'm sorry, but what, exactly, is the reasoning behind this?

I can assure you that stairwells are anything but rare in many fortresses, and not all fortresses by any means use a "Central Stairway" approach to construction.

Fixing A* worse case scenarios will require a solution like implementing a node system engineered around vertical access points. I repeat, tweaking A* will not fix anything.

Yes, well, that's sort of what's been said throughout the thread on everything but the first proposals sockless made, excepting the "engineered around vertical access points" part, since you can't assume that vertical access points mean anything.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Phoebus on April 23, 2011, 01:36:34 pm
2. The algorithm values the Z axis less than the horizontal axis. Optimized for ramp seeking greed, the A* algorithm searches every Z levels (between the origin and the target) in hope of finding a ramp. Incredibly stupid 'optimization' for the sake of trivial outdoor pathfinding. Sane DF heuristic should value underground Z levels as a top priority. Stairs/Ramps are relatively rare, and should be highly valued when they are found.

- DF A* pathfinding algorithm should use non-taxicab heuristic horizontally, but not vertically. Ex.: max(abs(x1-x2), abs(y1-y2)) + abs(z1-z2)
- Optionally, outdoor heuristics should also have an option (on by default) to also use non-taxicab vertically, for the sake of the outdoor ramp layout. Ex.: max(abs(x1-x2), abs(y1-y2), abs(z1-z2))

I'm sorry, but what, exactly, is the reasoning behind this?

I can assure you that stairwells are anything but rare in many fortresses, and not all fortresses by any means use a "Central Stairway" approach to construction.

Every single fortress use the central stairway approach, it's just that some have more than others.
Why?
Because, literally, you can't build on vertical movement tiles, while even vertical movement tiles are horizontal movement tile, .
So, literally, all fortresses need to build their stuff next/away from vertical access tile, and the majority of that 'stuff' will not block horizontal movement.

Unless you want to build a fortress that specificaly designed to be a maze, your fortress will be much easier to navigate horizontally than it will be vertically.

Fixing A* worse case scenarios will require a solution like implementing a node system engineered around vertical access points. I repeat, tweaking A* will not fix anything.

Yes, well, that's sort of what's been said throughout the thread on everything but the first proposals sockless made, excepting the "engineered around vertical access points" part, since you can't assume that vertical access points mean anything.
Because, I'm being pragmatic.
Any node system needs nodes.
There's no reason a node system would need to replace A*, supplementing it is far wiser.
If DF uses both a node system and a A*, it would be stupid to optimize the node system to solve the pathfinding problems that A* is already able to solve efficiently.
What A* can't handle efficiently are large/complex obstacles. 3D maps can increase both the size & complexity of obstacles exponentially.
Hence the worst case scenarios for A* will invariably involve Z levels, which requires vertical access points.
So by using vertical access points as nodes, you end up using the node system when and where you usually need it the most.

But sure, you can try to design an algorithm to find navigation nodes in a complex 3D maze of rooms, that could be more effective at pathfinding.
But see how designing that system goes for you and how much Toady cares about the 'solution'.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 23, 2011, 02:44:34 pm
Every single fortress use the central stairway approach, it's just that some have more than others.
Why?
Because, literally, you can't build on vertical movement tiles, while even vertical movement tiles are horizontal movement tile, .
So, literally, all fortresses need to build their stuff next/away from vertical access tile, and the majority of that 'stuff' will not block horizontal movement.

Unless you want to build a fortress that specificaly designed to be a maze, your fortress will be much easier to navigate horizontally than it will be vertically.

This is how I build workshops, so as to be efficient, and control what stones are selected for products.
Spoiler (click to show/hide)

No matter how much I dig downward, I am only moving my workshops 1 step further away from the stockpile per 6 workshops I build.

I also have a layer of pure soil between the stockpile layer and workshops because I want to preserve the chance to have underground trees, so you can generally assume that trip is more vertical than horizontal. 

Generally speaking, I just segregate my fortress horizontally, and then do my "sprawl" vertically, preferring narrow, yet deep fortresses.

That's just building for a particular form of optimization, however. I wasn't feeling artsy when I was doing that, except to make a hexagon instead of a square, and just made it compact and efficient.  If we want to go for a truly extreme version, we can go look at
Undergrotto (http://www.bay12forums.com/smf/index.php?topic=50916.0) once again.

Because, I'm being pragmatic.
Any node system needs nodes.
There's no reason a node system would need to replace A*, supplementing it is far wiser.
If DF uses both a node system and a A*, it would be stupid to optimize the node system to solve the pathfinding problems that A* is already able to solve efficiently.
What A* can't handle efficiently are large/complex obstacles. 3D maps can increase both the size & complexity of obstacles exponentially.
Hence the worst case scenarios for A* will invariably involve Z levels, which requires vertical access points.
So by using vertical access points as nodes, you end up using the node system when and where you usually need it the most.

But sure, you can try to design an algorithm to find navigation nodes in a complex 3D maze of rooms, that could be more effective at pathfinding.
But see how designing that system goes for you and how much Toady cares about the 'solution'.

Actually, there's little reason that a nodal system would really need to see a difference between a horizontal "hallway" and a vertical "hallway" made of stairs.  They theoretically cover the same distance, and dwarves move through them equally.  You're creating artificial barriers to how you generate nodes simply because of your mindset of how z-levels work. 

In fact, since any revised node system should be capable of including proper pathfinding for flying creatures and swimming creatures, the assumption that all creatures will be pathing to points along a flat surface is simply not one you can make - you need to build cubic nodes if you want to allow for a proper swimmer or flier pathing system.

The difference between building a "square" and a "cube" based nodal system is trivial, as has been discussed at length in this thread.

Further, using a node-based system, as I already said, is something everyone agrees to immediately.  The point of contention is how to form and adjust and split those nodes, and how best to organize those nodes.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Setharnas on April 23, 2011, 03:57:33 pm
1. The heuristic estimate is of 1 per tile, not 2 per tile as it should be. That incurs an ridiculously huge performance penalty (1000x the cost or more in common otherwise optimal A* scenarios) for the sake of naive traffic cost agendas.

Unless you meant using FP instead of integer values and sqrt(2) for diagonal travel, I really don't see your point here. If you stay with integers, the only possible penalty is a (slightly) higher chance of reaching the point of sign overflow - with higher edge traversal costs nonetheless, not smaller.

2. The algorithm values the Z axis less than the horizontal axis. Optimized for ramp seeking greed, the A* algorithm searches every Z levels (between the origin and the target) in hope of finding a ramp. Incredibly stupid 'optimization' for the sake of trivial outdoor pathfinding. Sane DF heuristic should value underground Z levels as a top priority. Stairs/Ramps are relatively rare, and should be highly valued when they are found.

I don't think you can really solve that problem with heuristics alone, even though I agree that your suggestion might help a little.

3. The system uses taxicab heuristics, but non-taxicab movement costs. Wtf really.

I assume you mean Manhattan heuristic? That's the term I'm most familiar with, but I think it's the same.

- Optionally, outdoor heuristics should also have an option (on by default) to also use non-taxicab vertically, for the sake of the outdoor ramp layout. Ex.: max(abs(x1-x2), abs(y1-y2), abs(z1-z2))

But how do you propose to decide when to use which heuristic? I's doable, but you're likely to burn up any computational savings in having to make that decision on each new tile.



Any node system needs nodes.
There's no reason a node system would need to replace A*, supplementing it is far wiser.
If DF uses both a node system and a A*, it would be stupid to optimize the node system to solve the pathfinding problems that A* is already able to solve efficiently.
What A* can't handle efficiently are large/complex obstacles. 3D maps can increase both the size & complexity of obstacles exponentially.
Hence the worst case scenarios for A* will invariably involve Z levels, which requires vertical access points.
So by using vertical access points as nodes, you end up using the node system when and where you usually need it the most.

A node system cannot replace A* - they are two different things.

Node system = representation of an abstract graph structure.
A* = one type of search algorithm across a graph structure.

DF already has a node system built-in - the tile grid. There is actually no way around this, as long as DF keeps using a non-continuous space. A* is just one way to search across that, but it is a provable good choice, because pretty much any other way has a much worse ratio of "good in some cases / bad in other cases". It hasn't been the de facto general search algorithm of choice for four decades for no reason.

You are correct that optimizing the parts of the graph representation that A* already deals well with would be stupid. That's why large parts of this thread focus on A*'s weaknesses:

The focus has been on introducing a hierarchical or tree structure to the graph representation:

And optimizing the z-level connectivity is trivial in a node system, because it is abstract by nature - A* doesn't care if the search graph has edges representing 2, 3 or 42 dimensions; that's just a question of how much time and memory you can afford to throw at it.



Quote
But see how designing that system goes for you and how much Toady cares about the 'solution'.

Actually, the whole PF problem isn't even what I would guess to be the main problem of the game. Nor the single threadedness, or the exclusive 32bit compiling. All of these are nothing against the sheer amount of memory shuffling going on - optimizing that is where I put my money.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Phoebus on April 23, 2011, 04:14:52 pm
Every single fortress use the central stairway approach, it's just that some have more than others.
Why?
Because, literally, you can't build on vertical movement tiles, while even vertical movement tiles are horizontal movement tile, .
So, literally, all fortresses need to build their stuff next/away from vertical access tile, and the majority of that 'stuff' will not block horizontal movement.

Unless you want to build a fortress that specificaly designed to be a maze, your fortress will be much easier to navigate horizontally than it will be vertically.

This is how I build workshops, so as to be efficient, and control what stones are selected for products.
Spoiler (click to show/hide)

No matter how much I dig downward, I am only moving my workshops 1 step further away from the stockpile per 6 workshops I build.

I also have a layer of pure soil between the stockpile layer and workshops because I want to preserve the chance to have underground trees, so you can generally assume that trip is more vertical than horizontal. 

Generally speaking, I just segregate my fortress horizontally, and then do my "sprawl" vertically, preferring narrow, yet deep fortresses.

That's just building for a particular form of optimization, however. I wasn't feeling artsy when I was doing that, except to make a hexagon instead of a square, and just made it compact and efficient.  If we want to go for a truly extreme version, we can go look at
Undergrotto (http://www.bay12forums.com/smf/index.php?topic=50916.0) once again.

Your workshop example are perfect example of completely trivial pathfinding that can be handled by A* with absolutely no problem.
They are short & well structured pathways between destination.
Even as extreme as they are, they are all predominantly horizontal. On average your workers walk 6 tiles horizontally, and even if there's a layer of soil/mud in-between, only 2 tiles vertically.
And in your workshop example, you are using central shafts that are the logical and optimal location to build node points on.

Because, I'm being pragmatic.
Any node system needs nodes.
There's no reason a node system would need to replace A*, supplementing it is far wiser.
If DF uses both a node system and a A*, it would be stupid to optimize the node system to solve the pathfinding problems that A* is already able to solve efficiently.
What A* can't handle efficiently are large/complex obstacles. 3D maps can increase both the size & complexity of obstacles exponentially.
Hence the worst case scenarios for A* will invariably involve Z levels, which requires vertical access points.
So by using vertical access points as nodes, you end up using the node system when and where you usually need it the most.

But sure, you can try to design an algorithm to find navigation nodes in a complex 3D maze of rooms, that could be more effective at pathfinding.
But see how designing that system goes for you and how much Toady cares about the 'solution'.

Actually, there's little reason that a nodal system would really need to see a difference between a horizontal "hallway" and a vertical "hallway" made of stairs.  They theoretically cover the same distance, and dwarves move through them equally.  You're creating artificial barriers to how you generate nodes simply because of your mindset of how z-levels work. 

In fact, since any revised node system should be capable of including proper pathfinding for flying creatures and swimming creatures, the assumption that all creatures will be pathing to points along a flat surface is simply not one you can make - you need to build cubic nodes if you want to allow for a proper swimmer or flier pathing system.

The difference between building a "square" and a "cube" based nodal system is trivial, as has been discussed at length in this thread.

Further, using a node-based system, as I already said, is something everyone agrees to immediately.  The point of contention is how to form and adjust and split those nodes, and how best to organize those nodes.
No, as I explained, it is you that does not understand that the game has a concept called 'floors', which is not present on the horizontal version as walls need a whole tile. Those 'floors' are everywhere under and over your workshops and rooms, and they are a serious impairment to pathfinding.
If floors did not exist, if dwarves could fly and if buildings could float, then your argument would be valid, but it is not so.
Floors/Z-levels are the primary pathfinding obstacle in the game. By far.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Phoebus on April 23, 2011, 05:09:58 pm
1. The heuristic estimate is of 1 per tile, not 2 per tile as it should be. That incurs an ridiculously huge performance penalty (1000x the cost or more in common otherwise optimal A* scenarios) for the sake of naive traffic cost agendas.

Unless you meant using FP instead of integer values and sqrt(2) for diagonal travel, I really don't see your point here. If you stay with integers, the only possible penalty is a (slightly) higher chance of reaching the point of sign overflow - with higher edge traversal costs nonetheless, not smaller.
That has nothing to do with Manhattan vs Diagonal heuristic.
I'm talking about what heuristic are supposed to do: predict as accurately as possible the movement cost from point A to point B.
If the actual default movement cost is 2, but the heuristic calculates (as it currently) that the expected cost per tile of distance is 1, the heuristic is actually ridiculously off-chart and will result with something like this.

Top version uses the natural Diagonal heuristics with a D value of 2. (48 tiles explored.)
Bottom version uses DF's current Manhattan heuristics with a D value of 1. (233 tiles explored.)

(http://i.imgur.com/lL6Zk.png)
Legend: Black = Start. White = Destination. Grey = Viewed but not walked.

Traveling through a tile with a cost value above the heuristic's expected value makes the A* pathfinding algorithm try to find a path around said tile.
The game is currently using the bottom version, and mind you, that's only in 2D. If I could show you in 3D the damage in done by the bad heuristic, it is even more ridiculous. Think a needle vs a top.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 23, 2011, 05:20:28 pm
welcome to the endless thread,Phoebus.

using a tablet atm so typing is limited...

if you want I can fix my simulator to double the hueristic but I don't think it would help much. A*  likes getting lost and it easily get confused by hueristic. my approach for solving the complexity is by reducing the distance, and saving common pathes.

this is done by grouping nodes into rooms. all you have to do is to keep track of which room is connected to which and. then A* on rooms. my simulator can do a limitted form of room pathing but it gives up easily because it won't look at rooms 2 blocks away. in decent conditions it reduce a long distance A* to a few short distance A*. Afterwards the path can be smoothed but it's generally pretty good.

the z axis doesn't exist in my program,I can add it but it won't contribute much. a room system can help more and that's what I'm working on. the size and shape of the grid doesn't matter.

I noticed that even with a few user placed fully path cached to eachother you can get a performance boost when a path exists. when it doesn't... you go through worst case of A*....
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Phoebus on April 23, 2011, 05:34:35 pm
I don't think you can really solve that problem with heuristics alone, even though I agree that your suggestion might help a little.
if you want I can fix my simulator to double the hueristic but I don't think it would help much. A*  likes getting lost and it easily get confused by hueristic. my approach for solving the complexity is by reducing the distance, and saving common pathes.
Combined reply.
This is exactly my point. No amount of A* tweaking is ever going come even close to solve DF's pathfinding problems.
But that's the problem, A* is already heavily tweaked in attempt to solve DF's pathfinding problems.
It's tweaked so bad that even if a good node system is implemented in DF, the cost of using current A* to pathfind between nodes is still going to make the whole pathfinding process cost 2 to 5 time more processing power than it should.

I'm proposing to un-tweak the A* engine back to the actual standard way in which it's supposed to work.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Setharnas on April 23, 2011, 05:51:38 pm
...[beautiful Phoebus-diagrams :D]...

You are talking about admissible vs. inadmissible heuristics. General rule: having the heuristic overshootunderestimate the cost = admissible, meaning guaranteed shortest path. UnderOverestimation = inadmissible, meaning you get a path, but not a guaranteed shortest, and possibly with an open list like your example. OK; I see what you mean. Just... How did you come to the conclusion that DF uses inadmissible h(x)?

*EDIT* Oops - I messed up badly, switched around the over- and underestimating for admissibility. Estimating less than actual cost keeps heuristic admissible.


This is exactly my point. No amount of A* tweaking is ever going come even close to solve DF's pathfinding problems.
But that's the problem, A* is already heavily tweaked in attempt to solve DF's pathfinding problems.
It's tweaked so bad that even if a good node system is implemented in DF, the cost of using current A* to pathfind between nodes is still going to make the whole pathfinding process cost 2 to 5 time more processing power than it should.

I'm proposing to un-tweak the A* engine back to the actual standard way in which it's supposed to work.

I'm still heavily convinced that PF isn't the real problem in DF, and that a hierarchic search would even pretty much solve the worst case of 'no path exists' - because it would come to the same conclusion in a fraction of the effort it needs in a flat structure. It would be equivalent to having a cut-off depth in the current version equivalent to the number of nodes in the current strongly connected component (http://en.wikipedia.org/wiki/Strongly_connected_graph) of the high level graph.


Oh, and Niseg: kudos to you for being the only one in this thread (to my knowledge) who has actually coded up an example. Talk about putting your money where your mouth is. :)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Phoebus on April 23, 2011, 06:25:52 pm
...[beautiful Phoebus-diagrams :D]...

You are talking about admissible vs. inadmissible heuristics. General rule: having the heuristic overshoot the cost = admissible, meaning guaranteed shortest path. Underestimation = inadmissible, meaning you get a path, but not a guaranteed shortest, and possibly with an open list like your example. OK; I see what you mean. Just... How did you come to the conclusion that DF uses inadmissible h(x)?
I don't think I was ever arguing admissible (optimal final result) heuristics.
But the current heuristics can potentially be 'inadmissible' when you consider the misuses of Manhattan heuristics in a game with diagonal movement. Optimal paths can be missed by the engine due to that.
Heuristics for diagonals and ramps = 2. Heuristics for diagonal ramps = 3. Movement cost (High Traffic) for those is 1.
But, are optimal paths really that necessary?

Edit: Pure Diagonal heuristic with D = 1 and movement cost = 2:
(http://i.imgur.com/W1cB5.png)
Definitively not worth the extra cost.

This is exactly my point. No amount of A* tweaking is ever going come even close to solve DF's pathfinding problems.
But that's the problem, A* is already heavily tweaked in attempt to solve DF's pathfinding problems.
It's tweaked so bad that even if a good node system is implemented in DF, the cost of using current A* to pathfind between nodes is still going to make the whole pathfinding process cost 2 to 5 time more processing power than it should.

I'm proposing to un-tweak the A* engine back to the actual standard way in which it's supposed to work.

I'm still heavily convinced that PF isn't the real problem in DF, and that a hierarchic search would even pretty much solve the worst case of 'no path exists' - because it would come to the same conclusion in a fraction of the effort it needs in a flat structure. It would be equivalent to having a cut-off depth in the current version equivalent to the number of nodes in the current strongly connected component (http://en.wikipedia.org/wiki/Strongly_connected_graph) of the high level graph.
I can only agree with DF needing search algorithms that scale better.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Setharnas on April 23, 2011, 07:14:40 pm
But the game can currently be inadmissible when you consider the misuses of Manhattan heuristics in a game with diagonal movement. Optimal paths can be missed by the engine due to that.

True, diagonal movement needs both cost and heuristic of ~sqrt(2) (can be simplified to 1.4, or even lateral 5 / diagonal 7 if you want to keep integer math), else your diagram happens.

Thinking out loud though... Is that missed path even a non-optimal one, if movement costs the same in every direction? Sure, it may look idiotic if the dwarf walks straight-line NE first, then straight SE, only to arrive on the same y-coordinate as he started from. But if it takes him the same time and number of steps... ? (The path, not the search!)


Heuristics for diagonals and ramps = 2. Heuristics for diagonal ramps = 3. Movement cost (High Traffic) for those is 1.

Did you experiment with the traffic costs? I'd be interested in the !science!.


But, are optimal paths really that necessary?

Not in my humble opinion... (http://www.bay12forums.com/smf/index.php?topic=64580.msg1515644#msg1515644)


Quote
I can only agree with DF needing search algorithms that scale better.

Especially for history, material and item lists.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 23, 2011, 09:18:35 pm
No, as I explained, it is you that does not understand that the game has a concept called 'floors', which is not present on the horizontal version as walls need a whole tile. Those 'floors' are everywhere under and over your workshops and rooms, and they are a serious impairment to pathfinding.
If floors did not exist, if dwarves could fly and if buildings could float, then your argument would be valid, but it is not so.
Floors/Z-levels are the primary pathfinding obstacle in the game. By far.

No, as I explained, this needs to be capable of handling flying and swimming creatures, and there is no real benefit to having a pathfinding structure that penalizes vertical travel and makes the game incapable of pathfinding for two modes of travel for a minor optimization under a certain set of circumstances that you are just assuming will be more common.

The gains you are making are trivial, and the costs are serious.  It's just not worth it.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Phoebus on April 24, 2011, 01:13:58 am
But the game can currently be inadmissible when you consider the misuses of Manhattan heuristics in a game with diagonal movement. Optimal paths can be missed by the engine due to that.

True, diagonal movement needs both cost and heuristic of ~sqrt(2) (can be simplified to 1.4, or even lateral 5 / diagonal 7 if you want to keep integer math), else your diagram happens.

Thinking out loud though... Is that missed path even a non-optimal one, if movement costs the same in every direction? Sure, it may look idiotic if the dwarf walks straight-line NE first, then straight SE, only to arrive on the same y-coordinate as he started from. But if it takes him the same time and number of steps... ? (The path, not the search!)
Those missed paths could be optimal, movement cost wise, if it managed to connect with a direct path of High traffic (1 cost) tiles to the destination. Very uncommon, and suboptimal step wise.

The colors represent time in the pathfinding algorithm. The tiles in the back have an heuristic value of 27-29, if they manage to find a path of high traffic to the destination they will keep that heuristic value up to the destination and beat the direct normal cost paths (which will end with a cost of 30).

Heuristics for diagonals and ramps = 2. Heuristics for diagonal ramps = 3. Movement cost (High Traffic) for those is 1.

Did you experiment with the traffic costs? I'd be interested in the !science!.
I did a few tunnels with levers, I calculated the heuristic values that way.
One of my first test that left me puzzled was an obstacle course with tunnels.
(http://i.imgur.com/aejGG.png)
Strangely enough, the dwarves usually prefer to move through the underground tunnels. The tunnels have exact same traffic settings as overground tiles.
Somehow the dwarves prefer the path that's moving away both horizontally and vertically from the destination.
That only made some kind of sense after I figured the path cost debt caused by the D = 1 heuristic vs. 2 cost normal traffic. Even then that behavior is, even if explainable, still somewhat abnormal as the overland cost should be traced first. It's possible the engine is actually pathfinding several times over the same time (if the second pass has equal or better heuristic estimate), or at least overwriting early tracebacks with later ones of equal travel cost.

But, are optimal paths really that necessary?

Not in my humble opinion... (http://www.bay12forums.com/smf/index.php?topic=64580.msg1515644#msg1515644)
I agree with the sentiment about dwarves needing to think.
But delayed pathfinding (unless there's some techniques I do not know) will incur large memory penalties and will most likely lower performance even further due to cache hits.

Quote
I can only agree with DF needing search algorithms that scale better.

Especially for history, material and item lists.


No, as I explained, it is you that does not understand that the game has a concept called 'floors', which is not present on the horizontal version as walls need a whole tile. Those 'floors' are everywhere under and over your workshops and rooms, and they are a serious impairment to pathfinding.
If floors did not exist, if dwarves could fly and if buildings could float, then your argument would be valid, but it is not so.
Floors/Z-levels are the primary pathfinding obstacle in the game. By far.

No, as I explained, this needs to be capable of handling flying and swimming creatures, and there is no real benefit to having a pathfinding structure that penalizes vertical travel and makes the game incapable of pathfinding for two modes of travel for a minor optimization under a certain set of circumstances that you are just assuming will be more common.

The gains you are making are trivial, and the costs are serious.  It's just not worth it.
Must the game only use a single pathfinding algorithm for all creatures?
(That's a rhetorical question.)

This is the whole point around my argument. The current pathfinding algorithm has been broken to solve problems that it can't really solve. As you put it, serious costs for trivial gains.
The goal of fixing A* is not to fix the pathfinding problem (which it can't), the goal of fixing A* is to have a A* that does it's job, and then let other solutions take care of what A* can't handle.

A solution example that would improve things without breaking A* wouble be to have a different A* heuristics for creatures with different mode of travel.
This is not even some mind-blowing idea, that's just how heuristics are supposed to work.
It's also the reason why I proposed configurable A* settings options, because different fort design have different pathfinding expectancies. While those options will have minor benefits, they are also cheap to implement and have no actual costs as they are options.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 24, 2011, 01:28:00 am
Combined reply.
This is exactly my point. No amount of A* tweaking is ever going come even close to solve DF's pathfinding problems.
But that's the problem, A* is already heavily tweaked in attempt to solve DF's pathfinding problems.
It's tweaked so bad that even if a good node system is implemented in DF, the cost of using current A* to pathfind between nodes is still going to make the whole pathfinding process cost 2 to 5 time more processing power than it should.

I'm proposing to un-tweak the A* engine back to the actual standard way in which it's supposed to work.

I'm not sure what simulator you are using , mine is JS and I can change it to serve dinner but it doesn't show the nodes it adds to the queue (I can change a* function to keep track of that). All it does is count the visited nodes. And on a trivial straight line path with a good vector heuristic and no obstacle it always visit the number of nodes the length of the path. Sure it does have major penalty - O(n) find minimum cost.  This is why the node grouping approach is the leading solution to the complexity reduction.

here is one example(link to this maze in my simulator (http://niseg.50webs.com/test_maze.html?maze=v02AgAgAQEVEFBRwdHBwFEA0RAwAAAEAABABAAAQAQAAEAEAABABAAAQAQAAEAEAABABAAAQAQA7__97wBABQAAX_UAAFAVAABQFQAAV5UAAFLVAABWlQAAVtUAAFCVAABf1QAAQBEA7___7wBABAAAQAQAAEAEAABABAAAQAQAAEAEAABAAAAAQAQAAAAEAABABAA)):
Spoiler (click to show/hide)

-  top left pure A* ( no traffic ) is   - 812 node visits is too much
- top right is room based navigation - 13 node visits  which is a lot  less complex. R has the gray paths to eachother and A* between the closest node to start  and closest node to destination. It first find paths to an R1 and from an R2  , and then find path between them if there is no path it gives up. having a 4X4 grid reduce the penalty for no path to something more acceptable.
- bottom left is waypoint pathfinding - 'w's have a full cache - better but zigzags much like room navigation but more because of less wps.
- bottom right is the same as the one on the left but it's smoothed using a line of sight algorithm.

edit:updated link to backup site
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: warman45 on April 24, 2011, 02:32:01 am
obviously creating two different algorithms (vertically locked, and flying/swimming) would help (also remove the unnecessary vertical components for most animals and dwarfs at a negligible increase in program space.)

one thing i have noticed about the A* approach (and probably most others) is the exponential increase in calculations over greater distance (due to the exponential increase in path options, most of which are redundant and unnecessary)

there are two suggestions i have. one would help a lot for pathing in a fortress. by breaking the fortress down into rooms separated by doors, you could simplify the code by using a macroscopic version to calculate what rooms you need to go to, and a microscopic one for pathing through each room. even if it needs to preform the same amount of pathing checks it won't have to do them all at once, only once every time the object enters the room, spreading the lag more evenly. this also means numerous shorter distances instead of one long one minimizing the exponential growth in possibilities ( i know it is better then exponential but the algorithm hates distance. you could even use memory to store the path from one end of the room to the other (though this would have to be compiled and called on when needed because RAM is taxed as it is (i think))

the other method is a modified A* (don't kill me) i have a Wikipedia understanding of A* (meaning i looked at the Wikipedia animation) using the animation as an example, the program traces a line towards it's target. the line hits the wall, and instead of expanding from there, it follows the wall in both directions until one becomes free to move again. the program then begins to trace between these points, and if it collides again it repeats this task. then, after it arrives, it begins to continue it's course. i might create an example when im not exhausted and can think.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 24, 2011, 04:45:59 am

one thing i have noticed about the A* approach (and probably most others) is the exponential increase in calculations over greater distance (due to the exponential increase in path options, most of which are redundant and unnecessary)
The complexity is about min((k/2)^N ,Nmax) which means node explosion . A* is also fooled by dead ends . there are a few examples for this

there are two suggestions i have. one would help a lot for pathing in a fortress. by breaking the fortress down into rooms separated by doors, you could simplify the code by using a macroscopic version to calculate what rooms you need to go to, and a microscopic one for pathing through each room. even if it needs to preform the same amount of pathing checks it won't have to do them all at once, only once every time the object enters the room, spreading the lag more evenly. this also means numerous shorter distances instead of one long one minimizing the exponential growth in possibilities ( i know it is better then exponential but the algorithm hates distance. you could even use memory to store the path from one end of the room to the other (though this would have to be compiled and called on when needed because RAM is taxed as it is (i think))
I think that's around page 15-17 or so of this thread.

I did implement an arbitrary room generation with patch caching between them . you'll see it in the picture above your post(it's spoilered to save space). the cyan on gray Rs are the rooms and the path between them is shown in light gray. The path itself is cyan background floors.


here is a condensed version of my code with dest-path part choped (same as spath after reseting variable) but it's still pretty big though what it does is simple.
Spoiler (click to show/hide)

first thing it tries to find a path to the room closest to it but it limits its search to nodes 16 or less away. then if it fails it tries again with longer distance . (the complexity of the second search is much larger than the first). if it still fails it assumes that it's by a wall and the best candidate rooms are the ones not connected to it's closest room. if it fails to find a path to those rooms it gives up.

after it's done with path (xs,ys)->R(wprxs,wprys) it will then find the  path R(wprxd,wpryd) -> (xd,yd) the same way (this part is choped). then it look for a path from start room to end room on the room "maze" which is  a 4X4 size (atm) and if it doesn't find a path - it returns empty path. otherwise it goes and concatenate spath to all the subpaths of the room path (not necessary to save path  - short distance A* is usually pretty fast).

As I said before the begining of the function that got to do with room selection needs a lot of work because waypoint based rooms are just terrible in terms of finding "where you are"  . The last part is pretty simple once you find the connections.

Edit1:

After playing with the code a little I added a BFS  collider  to find edges between rooms - sure it goes through every node in the maze but it finds all the connections between rooms and their shape in one pass . All I need to do now is to add  the info to room data structure , then I'll need  to create a better navigation function then a room update scheme ... lots of work ;). I still need to fix the bfs limits scheme so it know when to update the depth counter correctly .

here is how it looks like - it puts the output at the bottom whenever updating rooms:
Spoiler (click to show/hide)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 24, 2011, 09:45:45 am
No, as I explained, it is you that does not understand that the game has a concept called 'floors', which is not present on the horizontal version as walls need a whole tile. Those 'floors' are everywhere under and over your workshops and rooms, and they are a serious impairment to pathfinding.
If floors did not exist, if dwarves could fly and if buildings could float, then your argument would be valid, but it is not so.
Floors/Z-levels are the primary pathfinding obstacle in the game. By far.

No, as I explained, this needs to be capable of handling flying and swimming creatures, and there is no real benefit to having a pathfinding structure that penalizes vertical travel and makes the game incapable of pathfinding for two modes of travel for a minor optimization under a certain set of circumstances that you are just assuming will be more common.

The gains you are making are trivial, and the costs are serious.  It's just not worth it.
Must the game only use a single pathfinding algorithm for all creatures?
(That's a rhetorical question.)

This is the whole point around my argument. The current pathfinding algorithm has been broken to solve problems that it can't really solve. As you put it, serious costs for trivial gains.
The goal of fixing A* is not to fix the pathfinding problem (which it can't), the goal of fixing A* is to have a A* that does it's job, and then let other solutions take care of what A* can't handle.

A solution example that would improve things without breaking A* wouble be to have a different A* heuristics for creatures with different mode of travel.
This is not even some mind-blowing idea, that's just how heuristics are supposed to work.
It's also the reason why I proposed configurable A* settings options, because different fort design have different pathfinding expectancies. While those options will have minor benefits, they are also cheap to implement and have no actual costs as they are options.

That's basically saying your solution to the problem is not to solve the problem.

The reason (or at least one of the reasons) why we can't have multi-tile creatures and vehicles right now is because the pathfinding code doesn't support them.  We need serious swimmer and flier pathfinding, because there's a reason why HFS will kill your framerate right now - the clowns are all fliers that use Breadth First Search.

Your tweak doesn't actually solve any problems, and creates larger ones.  The way to solve these problems is to use a nodal structure that saves the breadth of passage and required travel mode through the nodes.

When creating a hierarchical data structure that supports storing its permitted travel types (including passage width for multi-tiles), then the hierarchical structure itself can easily handle all forms of travel, and standard A*, if it is necessary at all, assuming we don't use the "convex cube" route, is only used in intra-node travel.  This allows every form of movement to easily use the same pathfinding system, doesn't require wheel-reinvention, and actually goes through the necessary step of allowing serious non-land-based travel.

I did a few tunnels with levers, I calculated the heuristic values that way.
One of my first test that left me puzzled was an obstacle course with tunnels.
Spoiler (click to show/hide)
Strangely enough, the dwarves usually prefer to move through the underground tunnels. The tunnels have exact same traffic settings as overground tiles.
Somehow the dwarves prefer the path that's moving away both horizontally and vertically from the destination.
That only made some kind of sense after I figured the path cost debt caused by the D = 1 heuristic vs. 2 cost normal traffic. Even then that behavior is, even if explainable, still somewhat abnormal as the overland cost should be traced first. It's possible the engine is actually pathfinding several times over the same time (if the second pass has equal or better heuristic estimate), or at least overwriting early tracebacks with later ones of equal travel cost.

Presuming that those ramps are just one z-level down, you actually ARE still returning an optimal path, because the costs of moving diagonally are the same as the costs of moving horizontally. 

That far left miner would take 22 steps to reach either lever whether he went through those little tunnels or not.

What you are seeing is just a preference to move diagonally, even diagonally vertically, that is amusingly distracting, but that test doesn't demonstrate actually performing sub-optimal behavior, although it does demonstrate exploitable and somewhat illogical-looking behavior.

Those missed paths could be optimal, movement cost wise, if it managed to connect with a direct path of High traffic (1 cost) tiles to the destination. Very uncommon, and suboptimal step wise.
I'd also have to say that what you are really harping over - the traffic costs - is something that actually has a very simple fix.  Either do what the system was meant for you to do, and set all your hallways to be high-traffic zones, which nobody really does, and hence proves this a broken system, or go into the init options, and set standard traffic weighting to be 1. 

Do that, and standard traffic weight is now 1, and the heuristic assumes it to be 1, which means there's no problem.  You can just use the restricted traffic settings when you really don't want dwarves pathing through a place, like in a bedroom, and maybe crank those traffic weights up while you're at it. 

Yes, that's a problem, and it's frankly some real low-hanging fruit, but it's not a problem that anyone is arguing with, and it's not going to solve the real issues.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on April 24, 2011, 10:46:58 am
These pointless threads come up all the time, kind of ignoring the fact that Toady knows math hehe.

I'm almost tempted to write a hack that lets you guys plug your own pathfinders into DF just so you can see how pointless your ideas are... it wouldn't be that hard...
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 24, 2011, 10:47:37 am
Something else when we are talking about splitting up pathfinding between movement types...

There is a cost you potentially aren't thinking about if you are actually using different connectivity maps.  We currently have fully aquatic, amphibious, walker, flier, amphibious flier, magma-walker, magma-swimmer, and all-terrain types of movement.

Now multiply all those types of movement by the number of different vehicle sizes we will be allowing in the game.

That's how many connectivity maps you will need if we don't use a system designed to allow all the different types of movement we will be needing to track in this game over the long haul.

On top of this, every time you change the map in any way (such as by even having water flow), you need to go through a connectivity map update check on all of those connectivity maps, as well. 

The requirements for this system is not that it returns an optimal path, but that it does not unduly strain the memory requirements of the system, that it is lighter on the processor (which really means making less memory fetches), that it is capable of handling constantly changing maps while spending the least time having to update the pathfinding data structures, and finally, that it returns an at least reasonably optimal path.

Oh, right, and then we have to go into the matter of having siegers that are capable of digging through walls and bridging over trenches and building ladders to climb walls. 

This system cannot be designed from the point of view that only dwarf movement matters. 

Building a system where all units, regardless of movement type uses the same map, but relies upon the different nodes having specific movement types and width allowances recorded is the only sensible option, and if we are doing this, there is little need to have different pathfinding algorithms for every movement type, since the simple node connectivity and movement types allowed recorded in the nodes themselves will handle all those other problems for you. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Phoebus on April 24, 2011, 11:04:20 pm
the other method is a modified A* (don't kill me) i have a Wikipedia understanding of A* (meaning i looked at the Wikipedia animation) using the animation as an example, the program traces a line towards it's target. the line hits the wall, and instead of expanding from there, it follows the wall in both directions until one becomes free to move again. the program then begins to trace between these points, and if it collides again it repeats this task. then, after it arrives, it begins to continue it's course. i might create an example when im not exhausted and can think.
That algorithm isn't applicable to DF because the heuristic is optimized for 2D. In DF there can be stairways/ramps in the middle of the room and that modified A* would just walk around them/ignore them.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Uristocrat on April 26, 2011, 03:42:10 am
These pointless threads come up all the time, kind of ignoring the fact that Toady knows math hehe.

I'm almost tempted to write a hack that lets you guys plug your own pathfinders into DF just so you can see how pointless your ideas are... it wouldn't be that hard...

Now *that* would be an interesting mod.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 26, 2011, 06:52:23 am
These pointless threads come up all the time, kind of ignoring the fact that Toady knows math hehe.

I'm almost tempted to write a hack that lets you guys plug your own pathfinders into DF just so you can see how pointless your ideas are... it wouldn't be that hard...

Now *that* would be an interesting mod.
:-\ I don't think I'll take any part of *that* . I'm here to suggest stuff not to "fix" the code through hacks. Controlling the game with external apps is one thing, changing the game  engine is borderline copyright infringement ~ .

I'm not  sure why devek is so resistant to any path-finding related suggestions. He might be right that path finding improvements would be a waste of time because it might not take as many CPU resources as we think. My limited test didn't suggest memory thrashing .

It still seems logical that path finding improvements would lead to FPS improvement because that what all creatures do most of the time. Recently I built the bridged snake access:
Spoiler (click to show/hide)

It seems that after enabaling bridges dwarves still go along the snake. Some of them did repath - it might be related to bumping into each other.

I think that repathing frequency along with the big penalty on blocked paths can cause slow down .I'm not really sure. some people suggest atom smashing helps. Maybe the search through many items isn't optimal. If anyone searching through items check its accessibility using A* it might cause  a huge slowdown when there are many items inaccessible.

This is where the "Room splitting suggestion" can help - help a lot. I'm now in the process of creating one in my simulator . my current scheme of "waypoint rooms" is not always going to find the path because of it's naive  way of selecting rooms (it assumes it's either in the room closest to it or a disconnected  neighbor that of  that room ). This point to a room selection problem and instead of fixing something that sometimes work I advanced to a well defined room scheme which is the natural advancement.

even though waypoint room sometimes don't work when it does it gives great results of about 15 node visits compared to 800 of A*. The blocked path penalty is about 15 node visit compared to the number of accessible nodes of the map (that's about a maximum 1000 in my simulator). Still it only work for special cases and like this  (http://niseg.moshela.com/test_maze.html?maze=v03AgAgAQEgIA~_A~_A~NAA4AAAAKAAAACgAAAAoAAAALwAAACA) . When it's blocked in the corner it does about 700 node visits because I  let it run wild ( high limit on search distance) in attempts to reach the destination .

My new room definition algorithm would make the room selection very deterministic which would save pathing retries and other problems related to the waypoint scheme. After that I'll add a room update scheme and when everything is done I'll switch to 3d . After that I may convert the mechanics into c code or find other ways to grind it for performance testing (JS's has pretty bad performance).
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on April 26, 2011, 08:52:00 am
:-\ I don't think I'll take any part of *that* . I'm here to suggest stuff not to "fix" the code through hacks. Controlling the game with external apps is one thing, changing the game  engine is borderline copyright infringement ~ .

Hacking isn't copyright infringement. Besides, Toady will never sue me because I would never do anything to harm him, I <3 the toad.

I'm not  sure why devek is so resistant to any path-finding related suggestions. He might be right that path finding improvements would be a waste of time because it might not take as many CPU resources as we think. My limited test didn't suggest memory thrashing .

You hit the nail on the head. Before Toady did DF, he was paid money to know math. It is kind of like going up to a race care driver and telling them they could take faster turns if they focused out for their weight distribution, it is kind of pretentious.

Don't get me wrong though, there is nothing wrong with pathfinding improvements. It would be nice if when a dwarf constructed a wall, that it did it from the closest tile instead of always building from one side, it would be nice if it grabbed the stone that was close or on the way, it would be nice if we had multi-tile monsters, etc. Toady isn't sitting around trying to figure out how to do it, he is simply busy working on other things(like hill dwarfs, taverns, and cities!). We will get those things when they get to the top of the enormous list of things left to do.

It still seems logical that path finding improvements would lead to FPS improvement because that what all creatures do most of the time.

It is also logical that you could improve FPS by improving any piece of code, but premature optimization is a killer waste of time. The truth is, exponential slowdowns in DF are the result of bugs. The most useful thing the user can do is upload saves before and after such slowdowns occur. Furthermore it is difficult sometimes figuring out how to properly write a piece of code when you don't know what it is going to do, DF is a huge work in progress.

For example, let me show you a graphed view of the function that determines what an object is when you look at it.
Spoiler (click to show/hide)

There is so much waste in that I could cut away with a few key strokes, but why bother? Right now it is flexible enough to add all sorts of cool new features and items to the game. The biggest performance gains are not possible to implement until you actually know what you are trying to do.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on April 26, 2011, 09:42:06 am
You hit the nail on the head. Before Toady did DF, he was paid money to know math. It is kind of like going up to a race care driver and telling them they could take faster turns if they focused out for their weight distribution, it is kind of pretentious.

Totally agree with your general point, you don't even know what you know until you profile. And you need to interpret the results correctly: even if the pathfinding function does end up accounting for a huge chunk of processor time when the game is profiled, it may be entirely due to some easily-detected edge case, meaning efforts to improve the pathfinding algorithm as a whole are unnecessary (if not counterproductive).

If "just wait until Toady gets around to it" isn't enough for people, then a real investigation into pathfinding should start with trying to reproduce the existing DF pathfinding on actual maps (via dfhack) and establish plausible test scenarios that demonstrate the slowdowns observed in real games. You can't make any progress on a solution until you know what problem you're trying to solve.

I was going to quibble with the idea that math knowledge might imply any particular ability when it comes to algorithms, but actually in this context I think it's fair enough. At least until someone has driven their own racecar around an identical track and has some evidence to back them up, it's unlikely that even a knowledgeable outsider's uninformed speculation is going to be any help.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 26, 2011, 10:14:57 am
You hit the nail on the head. Before Toady did DF, he was paid money to know math. It is kind of like going up to a race care driver and telling them they could take faster turns if they focused out for their weight distribution, it is kind of pretentious.
I'm not sure what Toady's background  but if someone wants to suggest a better pathfinding  algorithm they better know something in the field of computer science, discrete mathematics etc and be able to offer code or well outlined implementation.

I had no AI or pathfinding background other than having a CS degree and being able to code my way out of a plastic bag.  I found it interesting so I went and learn a little about  the subject.  After trying stuff myself I can make suggestions that work. I've been trying to convert some of the ideas on this thread into code. This also gave me another opportunity to experiment with JS and CSS etc.
Don't get me wrong though, there is nothing wrong with pathfinding improvements. It would be nice if when a dwarf constructed a wall, that it did it from the closest tile instead of always building from one side, it would be nice if it grabbed the stone that was close or on the way, it would be nice if we had multi-tile monsters, etc. Toady isn't sitting around trying to figure out how to do it, he is simply busy working on other things(like hill dwarfs, taverns, and cities!). We will get those things when they get to the top of the enormous list of things left to do.
The issue with dwarfs always building from top can  easily solved with some weighing and heuristics I don't think that it's such a major issue anyways. Just open the circus if you want FPS to drop ;) and there aren't that many clowns in there but they certainly kill fps in their marketing campaign . they got big k and big N to reach their customers and they can reach more nodes than anyone else.


It is also logical that you could improve FPS by improving any piece of code, but premature optimization is a killer waste of time. The truth is, exponential slowdowns in DF are the result of bugs. The most useful thing the user can do is upload saves before and after such slowdowns occur. Furthermore it is difficult sometimes figuring out how to properly write a piece of code when you don't know what it is going to do, DF is a huge work in progress.

For example, let me show you a graphed view of the function that determines what an object is when you look at it.
Spoiler (click to show/hide)

There is so much waste in that I could cut away with a few key strokes, but why bother? Right now it is flexible enough to add all sorts of cool new features and items to the game. The biggest performance gains are not possible to implement until you actually know what you are trying to do.

That looks like a call stack or something - look kinda blurry. I admit I have no Idea what's killing my CPU. If it's the dwarfs looking for items, thiefs looking for stuff to steal or 200 cats looking for who know what. All I know is that more Mobs = less fps which probably translate to pathfinding.  I know that turning off temperatures boosts FPS I haven't checked fluids flow. Maybe its the magma?!

This is why I like path finding optimization approach and you don't really have  to add much . It's a classic divide and conquer approach that every CS major should knows by heart .

My room scheme should offer great improvement and it has another advantage - you can do it over and over again to simplify the map farther.

Unfortunately my current [http://niseg.moshela.com/test_maze.html?maze=v05GAk0YzlSI1LhfmxHFkSulWNLiARSGSQJhJDJIZJAZJDJIZJAZJ9_x-UuNFMZC9HuMTTdIjx4hYifIzEWzFYj39cmIIvOSxJsRWJOjzJiAxKbpUADSixCQIxJEYkhkkBkkMkhkABkkAMhkkA]favorite maze [/url]doesn't show splitting it up too well :

0-1-2 3
|    /|
4 5-6 7
| |   |
8 9-A B
|     |
C-D-E-F


This is basically a strait line
2-1-0-4-8-C-D-E-F-B-7-3-6-5-9-A

If you look at it structurally you can divide it into the center region, the top left-region , the bottom region and top-right region

The problem with A* is that it can't see it as a strait line and it have to hit every wall in the general direction of  the target. If a dwarf wants  to look for an item and it's listed at 63,63 when the dwarf is at 1,1  it usually take 100-300 node traversal to get to the target  but if he know he's in room 0 and the item is in room F it takes 9 . That's only about 10-30 times faster . As the maze get larger and more complicated the gains get bigger and all you need to do is some pre-processing and maintaining the overlaying structure. The memory costs shouldn't be that big (my js program might be a hog but it doesn't have to be).


I do agree that profiling would get us far but I got no clue how to do it on someone else's code on a windows platform.  I am thinking of running some more tests with max fps to see the true effect of pathfinding . I'm not sure what else to concentrate on maybe item search  :-\ .... i'll do that after the path finding project  ;D.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on April 26, 2011, 10:17:49 am
I'm not sure what Toady's background  but if someone wants to suggest a better pathfinding  algorithm they better know something in the field of computer science, discrete mathematics etc and be able to offer code or well outlined implementation.

Math professor at a university.  I don't recall which one.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on April 26, 2011, 10:50:33 am
That looks like a call stack or something - look kinda blurry. I admit I have no Idea what's killing my CPU. If it's the dwarfs looking for items, thiefs looking for stuff to steal or 200 cats looking for who know what. All I know is that more Mobs = less fps which probably translate to pathfinding.  I know that turning off temperatures boosts FPS I haven't checked fluids flow. Maybe its the magma?!

It is a code flow analysis produced from the binary. Very useful when doing forensics. The large wide part at the top is where it switches on every item type (weapon, box, plant, etc). It is intentionally zoomed out far enough to not give any specific information hehe.

This is why I like path finding optimization approach and you don't really have  to add much . It's a classic divide and conquer approach that every CS major should knows by heart .

Learning and applying this stuff is a good thing. Sadly, most colleges don't teach up to date programming techniques :/ CPUs today are fast, like REALLY fast but memory isn't very fast. When you get it, you'll understand why it is just as expensive to path up one z-level as it is to path out 16 tiles horizontally. Check out this pdf from Sony for example...

http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf

It takes a common programming case and improves its performance from 20ms to 3ms with simple reorganization. The case is very similar to a lot of processing DF does :)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on April 26, 2011, 11:23:42 am
I do agree that profiling would get us far but I got no clue how to do it on someone else's code on a windows platform.

You can't, but you can maybe get far enough to know whether you are even asking the right questions.

You know DF uses A* with path costs modified by traffic designations, you know the heuristic used, and dfhack gives you access to actual game maps. So start by reproducing the DF pathfinding algorithm and observing its performance running on real maps.

Establish sets of test pathing requests (straight lines, expected worse case paths, impossible ones, paths between random tiles, different sets of "typical" requests as best as you can determine from surveying units in active games) to act as baselines for comparison.

At this point you can check your work: if you can make a terrain or traffic designation change in your test system that has a significant impact (positive or negative) on pathing performance, then you should be able to observe a similar result from making the same change in the actual game, and vice-versa. If one of your test cases does much worse than another, then see if you can get DF to slow down by recreating it in-game.

Only at that stage can you start to explore how alternative algorithms perform in comparison. And if your test cases were representative you'll have an idea whether any improvement you come up with might have an actual impact (i.e., improving the worst case may not mean much if the worst case is rare). When you think you have an improvement, you can grab another game off DFFD and confirm your results on fresh real data.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on April 26, 2011, 11:38:55 am
DFhack doesn't parse the pathfinding information in a mapblock, and if there were any issues or bugs that is where they would reside. He could reconstruct the information itself, but that may not match up with what DF is using.

I'm actually messing with that area right now due to a different reason(investigating smarter ways to make Foreman cut down trees)...
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on April 26, 2011, 12:10:43 pm
Yeah, I don't mean for finding bugs in the implementation or anything, just for benchmarking alternative pathfinding routines. Or does dfhack not give you traffic designations? I thought I saw it in the headers.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 26, 2011, 12:29:00 pm
If "just wait until Toady gets around to it" isn't enough for people, then a real investigation into pathfinding should start with trying to reproduce the existing DF pathfinding on actual maps (via dfhack) and establish plausible test scenarios that demonstrate the slowdowns observed in real games. You can't make any progress on a solution until you know what problem you're trying to solve.

This has been done, however.

There have been threads specifically on testing out FPS results from different build strategies.  This is why things like using ramps instead of regular stairs are used by those wanting a little extra edge in FPS.  As Phoebus was recently pointing out, the game prefers to look for ramps over looking for stairs.  The game will check for ramps before settling on stairs if no ramps are around, and as such, you save the game on 8 failed checks (although you probably will fail a number less than 8 if your spiral rampway requires going "backwards" horizontally in order to move the correct direction vertically, which will happen about half the time in a spiral ramp, but it is still faster than failing all eight diagonals every time before settling on just moving straight up or down).

While I disagree with Phoebus's assessment of what is the "tweak" and what is the "standard", his math is borne out by actual in-game results, and is verifiable.

Likewise, there have been threads which detail testing of how the A* is set up, and how the pseudo-ideal fort shape is a giant cube of up/down stairs that has no walls whatsoever, and allows dwarves to pathfind freely through space.  (Making everything ramps would be more ideal, but impossible since you can't stack ramps on ramps.)

The reason why pathfinding takes up so much processor time is because the game needs to randomly access very large amounts of memory in nonsequential (functionally random) order, meaning that the typical pipelining performance boosts generally just burn processor power for no gain.  The CPU has to idle while waiting for memory fetches of a huge number of tested tiles in a maze that are stored in very large vectors.

This is why the focus of all of this talk about pathfinding has been on one major issue: accessing memory less often. 

This is why nodal pathfinding is faster, because you are capable of bundling many accesses to memory all into one single access to memory.

The fact that nodal pathfinding is faster is entirely verifiable, regardless of how, specifically, Toady implemented some special alteration of A* or not.  Simply having to perform less idle times waiting on memory fetching will always result in faster performance, as you are basically getting the computer to make educated guesses about what tiles are going to be more likely to have an optimal result, and as such, no longer have to test every single individual tile by trial-and-error, waiting on a memory fetch for every single one.

Properly implemented hierarchical nodal pathfinding will undeniably result in less memory fetches because you bundle the guesses and data of multiple fetches into single accesses of memory.  The actual amount of memory bandwidth the game uses is fairly small, as the game has to wait on each memory fetch sequentially, meaning passing a larger abstract data structure would not have any negative performance consequence due to a memory bottleneck.  By passing a node that abstractly contains the data to pathfind through an area consisting of tens or even hundreds of tiles in a single fetch of memory as opposed to tens or hundreds of fetches as the computer blindly trial-and-errors through each individual tile, you are speeding up the pathfinding process by an order of magnitude or two, at the cost of the memory consumed by the data structure, and the processor cost of building and updating the data structure. 

These things are not really disputable.  What is really disputed is where, exactly, to strike the balance of the costs in return for the benefits.  (Or, in many cases, explaining how all these things work.)  To say that nothing about the process is knowable is an almost solipsistic approach.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on April 26, 2011, 12:33:10 pm
Designations are a separate 16x16 array per mapblock from the pathfinding data, they are for... designations like digging or channeling and such :) If it was up to me, that data would be replaced with a designation list but whatever hehe.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 26, 2011, 12:34:38 pm
Learning and applying this stuff is a good thing. Sadly, most colleges don't teach up to date programming techniques :/ CPUs today are fast, like REALLY fast but memory isn't very fast. When you get it, you'll understand why it is just as expensive to path up one z-level as it is to path out 16 tiles horizontally. Check out this pdf from Sony for example...

http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf

It takes a common programming case and improves its performance from 20ms to 3ms with simple reorganization. The case is very similar to a lot of processing DF does :)
Being an embedded programmer I know this kind of stuff. I can tell you a thing or two about udp packet transmission and the  downfalls of classic network stacks  ::) .  I am a big supporter of "link list = caching disaster" . I once improved udp transmission from 200us to 20us  ;D.

This is generally why I look at node accesses  as my benchmark . everytime you go through a node you don't know what kind of disastrous memory fetches you'll get unless the map is a very small bit vector.  just to think that you have to go to check the weights too. Who know what other useless data you are gonna fetch along with it.

This is why a room pather is so great. let assume our map is 192X192 (4X4) with depth 100 . If we choose room size of 16x16 we can divide each Z level into 12X12 rooms .  then instead of traversing a maximum of 3,686,400 nodes you'll traverse 14400 nodes. By saving the "edges" you can also make pathing between them cost nothing. You can also apply a smoothing algorithm and alternate paths . and if that isn't enough you can say those 12X12 rooms are 3X3 regions  then from 14000 you are down to major regions  and pathing inside them is 4X4 then a 16X16 intera-room pathing.You can also make regions cross the boundaries of Z levels.

This can make it possible to embark on 10X10 (provided you got enough memory) with little to no slow down.

on other news ;) I added room highlighting on my BFS-Collider output  ;). Now I know I got well defined rooms I can work with... Soon I'll have room pathing and I'll work on gaps.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on April 26, 2011, 02:01:01 pm
Designations are a separate 16x16 array per mapblock from the pathfinding data, they are for... designations like digging or channeling and such :) If it was up to me, that data would be replaced with a designation list but whatever hehe.

Right here I mean, it looks like traffic is stored as part of the designation data: https://github.com/peterix/dfhack/blob/master/library/include/dfhack/modules/Maps.h#L300

Or maybe I'm misreading.

This has been done, however.

...

As Phoebus was recently pointing out, the game prefers to look for ramps over looking for stairs.

...

Likewise, there have been threads which detail testing of how the A* is set up, and how the pseudo-ideal fort shape is a giant cube of up/down stairs that has no walls whatsoever, and allows dwarves to pathfind freely through space.

The part that hasn't been done (to my knowledge) is reproducing the DF pathfinding algorithm separately, so that it can be benchmarked in isolation and used as a baseline for evaluating other approaches. Which is the only way you can demonstrate that specific improvements can have any impact on actual performance.

Because something like this:

The reason why pathfinding takes up so much processor time is because the game needs to randomly access very large amounts of memory in nonsequential (functionally random) order, meaning that the typical pipelining performance boosts generally just burn processor power for no gain.

is an entirely empirical question and can't just be assumed.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on April 26, 2011, 02:21:34 pm
Designations are a separate 16x16 array per mapblock from the pathfinding data, they are for... designations like digging or channeling and such :) If it was up to me, that data would be replaced with a designation list but whatever hehe.

Right here I mean, it looks like traffic is stored as part of the designation data: https://github.com/peterix/dfhack/blob/master/library/include/dfhack/modules/Maps.h#L300

Or maybe I'm misreading.

No, you're not misreading *facepalm*. If that is true, then it means DF might be accessing more data than it needs to lol. The designation data for a mapblock is stored in a different memory allocation than the pathfinding data...

I had assumed it was packing all the data it needed for pathfinding into the pathfinding data :/ That still might be the case though, the traffic designations might be stored in both which wouldn't be a problem since its just 2 bits.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 26, 2011, 04:17:21 pm
It's not that bad even with 32 bit per block the weighted A* might cause it some trouble but the use of bit vectors means it should run pretty fast and should fit in cache easily enough.

Anyways I managed to create my first room navigation search based on the BFS-Collider rooms . The way I save the dimensions  isn't optimal(x,y,dx,dy,width,height,mask[8]). I should start node exchange soon.  My search function is fairly stupid it goes through all the rooms(it doesn't have to it can guess pretty well), find the start and end room , build a paths to their central points and then find the path between rooms( I need to fix that heuristic).

I think room pathing should cover anything the update scheme shouldn't be bad. if you dig a square you need to check which box it's in ,update bit vector or expand the box if needed. I guess I'll do it one step at a time  :D.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 26, 2011, 09:14:37 pm
Because something like this:

The reason why pathfinding takes up so much processor time is because the game needs to randomly access very large amounts of memory in nonsequential (functionally random) order, meaning that the typical pipelining performance boosts generally just burn processor power for no gain.

is an entirely empirical question and can't just be assumed.

It's not assumed, it's known that searching very large vector matrices thousands of times takes a lot of memory fetches.

This is also exactly what the others have just been saying:

This is generally why I look at node accesses  as my benchmark . everytime you go through a node you don't know what kind of disastrous memory fetches you'll get unless the map is a very small bit vector.  just to think that you have to go to check the weights too. Who know what other useless data you are gonna fetch along with it.

CPUs today are fast, like REALLY fast but memory isn't very fast.

The trick is to somehow require less accesses to memory because memory is slower than the CPU.  And when I say "slower", I mean we are comparing a CPU that can perform billions of tasks in a second to RAM, which can only be accessed thousands of times a second. 

You can shove more data through the bandwidth the RAM has, but you need to make the CPU stop and wait for less accesses to RAM, which means you either want to put more of the weight of pathfinding on either having a more complex data structure that takes up extra RAM space, but which requires less fetches because it stores paths, as almost all of these hierarchical data structures that almost everyone else, including Niseg and myself have been talking about. 

You can also try to put more of the burden upon the CPU and whatever data you can actually keep in the registers or cache, although I don't know of any trick for manipulating that sort of data that requires finding the solution to a maze without having to look at a tiny portion of the map, and relying purely upon computation, unless you combine it with a very wacky and sophisticated data structure I'm not imagining right now.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 27, 2011, 03:56:11 am
doh my response got erased  :'( .

anyways I said :

- I looked at some of the files and without optimization like a passible map it would be HFS for the CPU.
-Sorting creatures by start and destination  may help with caching using compare ={return hur(s1,s2) -hur(d1,d2} .stat from center go up x, go up x then go up x+1 , go down x+2 etc.

I also started writing about my progress so I made a new maze (http://niseg.moshela.com/test_maze.html?maze=v05GAk0Y1YsAEiKQAIhJ-_xxXKNFJAjEkRyTWjyB__xY5JAAAkEmd_jkzIkskiMQAI5Ji5yBPixCQIpAEYkzfkcmZEjEkRiSI5JmR44E6JGJIjEkACOQyTJjTTOlxY5JAAAkEkA) .

results a* 542 visits advanced room pathing 23 node visits.
here are times from chrome timeline in java console (just runtimes which are yellow):
a*-max(draw)    room-min(draw)    a*    room    redraw   
13971843740
85191304933
8691313945
96121414230
97111424138
Still that A* function I got isn't optimized and doesn't insert nodes in order.

Edit:
After messing with this maze (http://niseg.moshela.com/test_maze.html?maze=v05GAk0Y1YsxEgZhEY1I6I--P_Lx1lSJQM6UiZmpIWucwDxQkRyDRIkS5jQp_dRl1JE-QhICBMyYiKdSSBrnRpAIjkCTKSFzVJlGlNkyCJElhSpbQq-pQoCPIjoR5DQMoiUIsZoTpNEibIkRyDHIEmUkC) I found out that my A* needs fixing because it isn't pushing far nodes on my room grid , while it should...  :-\ I should be fixed by tomorrow.

EDIT: FIXED! now I need to add some kind of room spliting and node trading algorithms. someone managed to fool my program to go a silly distance when the destination was around the corner  ;D . I can overcome it by splitting rooms that are way too big and then comes some update scheme ... I can just recreate them a second pass won't be that bad.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on April 27, 2011, 05:20:45 am
It's not assumed, it's known that searching very large vector matrices thousands of times takes a lot of memory fetches.

That part is known. The assumption is that that phenomenon is the main factor determining the performance of the current pathfinding algorithm.

EDIT: Or maybe "hypothesis" is a better word. It's based on reasonable assumptions, and fits previous observations, but has yet to be tested against alternative hypotheses.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: kaenneth on April 28, 2011, 04:56:33 pm
So, not being totaly up to date on processor designs, is the time spent waiting on a memory fetch nearly completely idle on modern CPU's? or do other threads whos code/data are in cache get a chance to run? (and only 'hardware' threads, like Intel's 'Hyperthreading', or OS level threads/processes?

I'd love to see some benchmark results for DF on otherwise indentical CPU's except for L1 cache size.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on April 28, 2011, 05:41:05 pm
So, not being totaly up to date on processor designs, is the time spent waiting on a memory fetch nearly completely idle on modern CPU's? or do other threads whos code/data are in cache get a chance to run? (and only 'hardware' threads, like Intel's 'Hyperthreading', or OS level threads/processes?

I'd love to see some benchmark results for DF on otherwise indentical CPU's except for L1 cache size.

The whole point of threads and "slicing" is to transfer processor power onto another task while waiting for a memory fetch.  This is something that has existed for decades.  Thing is, DF is not multi-threaded, so all this means is that your processor will spend its time working on all the other programs running on your computer during this time.  (And please don't make this a multi-threading argument... there are enough threads on multi-threading already.)

Modern processors have the ability to make guesses about what data will be fetched, and just keep on processing based upon that guess, and then check if the guess was correct or not later on, when the memory fetch comes back... this is why I was talking about the problem of giant vector matrices making the data almost random, though.  The guesses are almost never correct, and all that processing based upon an assumption gets tossed out as soon as the fetch comes back, and proves it was a poor guess.

It's not assumed, it's known that searching very large vector matrices thousands of times takes a lot of memory fetches.

That part is known. The assumption is that that phenomenon is the main factor determining the performance of the current pathfinding algorithm.

EDIT: Or maybe "hypothesis" is a better word. It's based on reasonable assumptions, and fits previous observations, but has yet to be tested against alternative hypotheses.

Well, if we are agreeing that memory fetch time is a bottleneck, but not that it is the bottleneck, then what it comes down to is if there is something out there that is an even worse bottleneck that causes the CPU to burn tremendous numbers of cycles trying to calculate something when the math is actually fairly simple for a computer. 

A* is simple, processor-wise.  You generally just need to perform simple addition on a very small set of numbers, and test whether X, Y, and Z distance to destination is positive or negative or zero to determine preferred direction.  There's several if-then-else-then comparisons to go with that.  It's node accesses that consume time waiting on memory fetches.

It's theoretically possible that Toady did something extremely wasteful in coding how the game crunches numbers in something that is based on A*, but keep in mind that it takes about a million cycles of the CPU to equal one wait for a memory fetch, so it's hard to imagine someone doing that by accident.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on April 29, 2011, 06:57:35 am
Well, if we are agreeing that memory fetch time is a bottleneck, but not that it is the bottleneck, then what it comes down to is if there is something out there that is an even worse bottleneck that causes the CPU to burn tremendous numbers of cycles trying to calculate something when the math is actually fairly simple for a computer. 

Exactly. And if you're right about the bottleneck then it's easy to contrive test cases that demonstrate the pathological case. Not only do you confirm that you're solving the right problem, but you end up with a baseline reference against which to test your solutions.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on April 29, 2011, 03:13:09 pm
I'm happy to inform everyone I just wrote a non path caching 2 layer A* (it's called " advanced  rooms no path cache")  that simplify pathfinding cases to its most trivial cases. Room shapes and handling  need a lot of  work but it's not as important because it works with any shape room. It's also a very simple program. the only complexity in it is A* and it's changes (not that bad either)

In my early example (http://niseg.moshela.com/test_maze.html?maze=v05GAk0Y1YyI1PhfmxHFjSekhRSBEIjEkCUSQySGSQGSQySGSQGSff8flHjRTGQvR7rEwzyI8eIWInyMxFsRWI9_XJiCLzksSa0ViTo8yYgMSm6VAA0osQkCMSRGJIZJAZJDJIZAAZJADIZJA) A* finds a  110 length path visiting 813 nodes (it's really lost). My algorithm finds it in 203 this may sound bad compared to path caching but the big difference is that it finds to finding 13+1 paths with an  average length of about 8 steps . The "destination unreachable"  penalty is also really low about 16 node visits ( I got 16 rooms ).

The way it works is simple : it uses BFS collider to find rooms and saves their shape (square + bit vector). The collider also save the first collision point of the path ( I think I need to move it but it's not important) . The info about the destination id now also saves the collision point which means the room know at what coordinate is closest to the other room.
After building all the rooms all it does to get from S to D is find the path between the rooms

S and D exist in and then it pushes S to the output_path. There is a loop that looks for a path from the end of the   output_path to the next room's access point then it concatenate the path to  the output_path but it slice the last element for it.

With this system all a mob need to do is save the overlaying path and then calculate paths as it go from room to room . It's so trivial it runs as fast as the room pather with the caching.

Be aware though - you we have to recreate rooms whenever you change the maze. As I said I'm not updating the room structure when the maze is changed yet. It may still work if you keep access points between rooms.

you can check other examples it should work you may get unusual results because I just save the first access point and doesn't consider others in any way.

EDIT: I'm marking the subpathes now with 'O'
you can see it here

Spoiler (click to show/hide)
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 01, 2011, 03:01:17 am
Creating nodes(waypoints) over 2d space is pretty trivial, but you have to do it in 3d space.

Once you're done, you might as well be generating vectors. With a mesh you can do things like create monsters that take up more than one tile. Imagine a dragon that can't get in your fort because it is too tall. Imagine siege engines that can shoot downwards. Imagine a dwarf grabbing a nearby stone instead of crossing the entire map.

I brought this up once but you shot it down because it had to be generated and changed each time the map was modified, now that is exactly what you're talking about :P
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on May 01, 2011, 07:59:02 am
Creating nodes(waypoints) over 2d space is pretty trivial, but you have to do it in 3d space.
doing this in 3d space is trivial it's also not that necessary because you can keep 2d space per level and keep looking per z level . It might be a lot of memory but it's not too bad.  I can convert my simulator to work in 3d but the transitions between Z levels would need a modification to alow it to know if there are "stairs" or something like that in the node.

The no cache algorithm acts as a guide to tell A* where to go .

Once you're done, you might as well be generating vectors. With a mesh you can do things like create monsters that take up more than one tile. Imagine a dragon that can't get in your fort because it is too tall. Imagine siege engines that can shoot downwards.
The width can be handled easily by saving multiple access points and their width. I'm not sure A* can handle width anyways.
Imagine a dwarf grabbing a nearby stone instead of crossing the entire map.
Nearby stone  is simplified by this algorithm because if you need to find a path for each stone you will pay a smaller penalty for unreachable objects.

I brought this up once but you shot it down because it had to be generated and changed each time the map was modified, now that is exactly what you're talking about :P

The fact the my map has to be regenerated with each modification is  because I didn't finish the update scheme yet. It's not that bad.

If I know all the nodes that change I can check each room to see if something changed. I still need to fix my collider so it limits the depth correctly.  be aware that you can still change the maze without updating as long as you don't change the access points. There are many ways to implement an update scheme I"m just starting it.

About meshes .. I can convert my rooms into meshes using some interpolation scheme or something maybe after I split them up( or find the shapes using another way). I'm not sure what benefit would come of this because A* is not that bad when the distances are really small. I should add another monitor to A * which would say how many neighbors were pushed to the queues . this would show you the insanity in super long path A*.

I can also add a traffic zone handling to the no cache room pathing algorithm. It can look at traffic zones when doing sub-paths (it's really trivial).  The update scheme is a more important part of the simulation at the moment and after that's done it would be a pretty good alternative for super long A* paths. The solution I'm presenting is a simple application of the "divide and conquer" approach.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 01, 2011, 08:23:32 am
Well, its true you don't have to totally regenerate with any system. When someone digs out a room you just add to the nodes/mesh either way and optimizing it during spare cpu time.

What sucks (for any method)is when someone locks a door, currently you can feel DF hang for a second recalculating its pathfinding data.

Either way, your method will work and it is going in the right direction now. With a mesh or nodes, you're actually working with a proper graph now and this is where things actually improve. Feel free to burn as much cpu building/maintining your graph, in the end it is cheaper than traversing a suboptimal one.

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on May 01, 2011, 10:17:46 am
Well, its true you don't have to totally regenerate with any system. When someone digs out a room you just add to the nodes/mesh either way and optimizing it during spare cpu time.

What sucks (for any method)is when someone locks a door, currently you can feel DF hang for a second recalculating its pathfinding data.
I don't think it would hang for a second. With a non-caching method all you need to keep track of is weather a "room" is accessible or not. You should also consider the fact that the UI and user are significantly  slower than the back-end and CPU.  When you make a change you might want to go through  path validation but that's pretty quick on room paths(no guesswork either),  or let everyone hit the wall(like they do now.

 I think A* should be modified farther for this mode - it should consider the room shape and it's destination - it should consider nodes in other rooms to be blocked.  I can do that currently by quitting prematurely when it  start considering nodes that are significantly away from the target (it go to the closest ones first). It's too general and costly to do it this way.

Either way, your method will work and it is going in the right direction now. With a mesh or nodes, you're actually working with a proper graph now and this is where things actually improve. Feel free to burn as much cpu building/maintining your graph, in the end it is cheaper than traversing a suboptimal one.

It's not a matter of "proper" or not the current map is fine as a graph the problem is that it's really big and  too complicated. I've read in a book google scaned that they don't recommend using pure A* on "boards" larger than 60X60. What DF has in a 4X4 embark is a graph 192X192X100  ::)  or 3.7~ million nodes .  I'm not sure how Toady implemented his A* but if there is a dead end and you can  access to 1/10 of those nodes you are pushing 370000 nodes into a queue before you figure out it's a dead end.

The overlaying map model just leads A* to the right direction this way it doesn't get overly confused and kill your CPU. It also divide the A* of  a long path to many small A*s for short paths which spreads the load a little.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Fieari on May 01, 2011, 11:30:34 am
Don't forget that we know that connectivity maps are ALREADY used.  Requiring a connectivity map for certain implications doesn't imply things will be slower than now, just that it won't necessarily be faster.  You can use bit flags to create a single number for combinations of different movement types, and it wouldn't be any slower.  I'm not sure how you can get around avoiding connectivity maps anyway, even with nodes.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 01, 2011, 11:32:46 am
I don't think it would hang for a second. With a non-caching method all you need to keep track of is weather a "room" is accessible or not.

I meant, under the current system DF lags when you lock/unlock doors :P I'm not saying future systems will necessarily do it, but it is a case that will need to be described by your graph.

It's not a matter of "proper" or not the current map is fine as a graph the problem is that it's really big and  too complicated. I've read in a book google scaned that they don't recommend using pure A* on "boards" larger than 60X60. What DF has in a 4X4 embark is a graph 192X192X100  ::)  or 3.7~ million nodes.

Now we're starting to agree on stuff. Million of nodes isn't proper. Which is what goes back to my original argument, how you pathfind isn't a big deal. I can run a horrible algorithm, with no heuristic at all, over a proper graph faster than you can make the best algorithm ever scan over a non-proper graph.

Even putting the data in contiguous memory would have a bigger impact on performance than any other change you could possibly make in the pathfinding code itself. Right now to simply access a single tile, you have to dereference 5 pointers to get there. array->X->Y->Z->mapblock->data. Also, the 192x192x100 example you gave earlier has 14,400 mapblocks, with at least 2 vectors, a 512 alloc, 2=some 1024 allocs to go with each plus god knows what else that we haven't figured out and all of that is on the heap which probably puts around 100,000 items in the bucket allocator. Part of the main loop is that each of those 14,400 mapblocks has to be checked EVERY FRAME to see if the dirty bit is set. If the 16x16 mapblock is simply a #define statement and not based on actual code, changing them to 64x64 would make a bigger difference on performance than any pathfinding code change and only require changing 2 or 4 characters in the source. In many ways a 4x4 embark would become as fast as a 1x1 embark is now.. (not completely obviously)

The more you get into this, you will see why I hate people that are like, "derp, use this pathfinding function instead derp!" but you are clearly not one of those people now since you're analyzing the dataset so I like you now. <3
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on May 02, 2011, 01:31:12 pm
I added a new search mode to a_star.js - searching in rooms (I may improve it to search for the next room instead of just a destination). This mode doesn't add nodes to the open list if they are not in the starting room or destination room . It only made it twice as fast in term of complexity. I also calculate complexity a little better by incrementing a counters on most loops (except the ones that adds neighbors) . It doesn't display it on any of the path caching algorithms but I'll add that later.

if you try my example (http://niseg.moshela.com/test_maze.html?maze=v05GAk0Y1YyI1PhfmxHFjSekhRSBEIjEkCUSQySGSQGSQySGSQGSff8flHjRTGQvR7rEwzyI8eIWInyMxFsRWI9_XJiCLzksSa0ViTo8yYgMSm6VAA0osQkCMSRGJIZJAZJDJIZAAZJADIZJA). You'll get about 2.1 million for A* and 11502  for my newer no cache algorithm. A* is about 180 times more complex than my algorithm. When you consider the fact it makes a 13+1 subpathes the load spread out well with about 850~ iterations per search (my path smoother takes about 500 if you want to compare). The cache performance should also be much better than finding a huge path.

I'm thinking about optimizing the open set queue in A* so they insert stuff in order - it's about  log(n) insertion and O(1) (the best node is always in element 0). This should improve A* performance by a lot because it generally spends more time searching its queues than anything else . I might want to turn the closed set into another data structure like a hash table. Those improvement may help both algorithm run faster but it wouldn't affect the  potential memory thrashing of calculating many  extremely long paths.

Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on May 03, 2011, 09:48:53 am
The more you get into this, you will see why I hate people that are like, "derp, use this pathfinding function instead derp!" but you are clearly not one of those people now since you're analyzing the dataset so I like you now. <3

You know, starting from the viewpoint that you hate everyone until they prove themselves to you is problematic in what is fundamentally a board for persuasive argument (and this is endemic to almost all of your arguments). 

Even putting the data in contiguous memory would have a bigger impact on performance than any other change you could possibly make in the pathfinding code itself. Right now to simply access a single tile, you have to dereference 5 pointers to get there. array->X->Y->Z->mapblock->data. Also, the 192x192x100 example you gave earlier has 14,400 mapblocks, with at least 2 vectors, a 512 alloc, 2=some 1024 allocs to go with each plus god knows what else that we haven't figured out and all of that is on the heap which probably puts around 100,000 items in the bucket allocator. Part of the main loop is that each of those 14,400 mapblocks has to be checked EVERY FRAME to see if the dirty bit is set. If the 16x16 mapblock is simply a #define statement and not based on actual code, changing them to 64x64 would make a bigger difference on performance than any pathfinding code change and only require changing 2 or 4 characters in the source. In many ways a 4x4 embark would become as fast as a 1x1 embark is now.. (not completely obviously)

Anyway, while building from the bottom up, as opposed to starting from the top down is all well and good, you have to keep in mind that these things still need to actually work

You cannot simply cut the map into a series of 16x16x1 grids completely without regard for what is actually contained within those grids and still have a connectivity map that makes sense, which was what Draco18s and I were talking about when this whole concept was first aired. 

Again, consider this scenario:

Code: [Select]
###+####+#######
###+####+#######
###+####+#######
++++####+#######
########+#######
########+###++++
########+###+###
########+###+###
########+###+###
########+###+###
########+###+###
########+###+###
########+###+###
########+###+###
########+###+###
########+###+###

This node connects to nodes north, east, south, and west of itself.  Let's say, for the sake of argument, that the node to the north connects both paths that lead to the north, but both paths that lead to the south do not connect without a massive amount of backtracking. 

Now, if all you do is have a graph that says "this connects to the east, and it connects to the west", then you have a problem if you assume that this means it actually connects east to west, and that dwarves can traverse it. 

Trying to limit the use of vectors is fine as an idea, but you can't actually cripple functionality to get there. 
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 03, 2011, 11:52:14 am
The more you get into this, you will see why I hate people that are like, "derp, use this pathfinding function instead derp!" but you are clearly not one of those people now since you're analyzing the dataset so I like you now. <3

You know, starting from the viewpoint that you hate everyone until they prove themselves to you is problematic in what is fundamentally a board for persuasive argument (and this is endemic to almost all of your arguments). 

It is a simple fact that pretty much everyone who starts a pathfinding/threading/64-bit thread does so without the knowledge of how DF actually works. Anyone who does know how DF works also knows there are bigger problems. When someone makes those suggestions it proves(to me at least) they don't know how DF works. I'll try not to be such a dick about it though hehe. The decision of what should or should not be worked on is up to Toady, and I don't have to tell him what needs to be done because he already knows. DF receives new features while getting faster almost every release.

Anyway, while building from the bottom up, as opposed to starting from the top down is all well and good, you have to keep in mind that these things still need to actually work.

Of course things need to work. In fact, when people face exponential slowdowns in their fort they are the victim of something that doesn't work. Saves before and after are asked for time and time again on the bug tracker, to no avail. There totally are cases where pathfinding or whatever might be broken, but without a save to demonstrate it it is pretty damn hard to do anything about it. I personally haven't experienced it in any of my forts in a very long time, and if I did I could narrow it down and fix the bug myself.

You cannot simply cut the map into a series of 16x16x1 grids completely without regard for what is actually contained within those grids

Lets make something very clear.. pathfinding doesn't know or care about what it is looking at it. It could be looking at a massive grid, waypoint nodes, vector meshes, or even the BGP table. All it sees are paths it needs to travel to get where it wants to go. The reason I suggested changing the mapblock from 16x16 to 64x64 has nothing to do with pathfinding, since the pathfinding function itself doesn't even know the size of a mapblock. The 64x64 thing is just an example of memory optimization that would beat the snot out of anything pathfinding related while potentially only requiring the changing of 4 characters in the source. At the end of the day, pathfinding would have to process the same amount of data regardless of how the map was broken up if broken up at all.

I'm very certain Toady knows there needs to be changes to the dataset, and I am certain he has good reasons for not working on it right now. He hates putting bandaids on things, and he can't really rework the entire dataset without knowing what it needs to accomplish. DF is far from done, and having to rework the entire system all over again in order to add a new feature would suck and not be fun. The current dataset is flexible enough to do just about anything, and there is no evidence it is responsible for the exponential slowdowns. At the end of the day there are still huge performance gains to be made that have nothing to do with anything we are talking about, and those gains are made in every DF release. I have no reason to complain.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on May 03, 2011, 12:00:39 pm
Lets make something very clear.. pathfinding doesn't know or care about what it is looking at it. It could be looking at a massive grid, waypoint nodes, vector meshes, or even the BGP table. All it sees are paths it needs to travel to get where it wants to go. The reason I suggested changing the mapblock from 16x16 to 64x64 has nothing to do with pathfinding, since the pathfinding function itself doesn't even know the size of a mapblock. The 64x64 thing is just an example of memory optimization that would beat the snot out of anything pathfinding related while potentially only requiring the changing of 4 characters in the source. At the end of the day, pathfinding would have to process the same amount of data regardless of how the map was broken up if broken up at all.

Except that it matters.  In the case NW_Kohaku outlined, lets say a dwarf is traveling from the west to the east and passes through that block, and the one north of it (due to the two north-passages connecting there) and the one south of it (which leads east).  At least, that's the path that exists on the tile-level that we, as humans, can see.

The initial assumption about that block is West-side, this one, east side.

Except that no path actually exists there.

So it goes West-side, this, north, this, south (etc.).

"Wait a minute," the pathfinding algorithm says.  "We have a loop.  The path passes through this same node twice."  And it simplifies it: west-side, this, south (etc.).  Except that, once again, no actual path exists like that.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 03, 2011, 12:34:23 pm
I had to read that like 5 times to get what you guys were saying..

Are you saying that the mapblock itself is a node? If you are I can totally understand what you are saying. If you are not, disregard the rest of this post hehe :P

DF mapblocks are simple organizations of data inside of computer memory, they can't be nodes for the very reason you're saying. The pathfinding function doesn't look at mapblocks to find where it is going, it only looks at mapblocks to access the data inside of them. It would work the same regardless of if the mapblocks existed at all. If something I said sparked that confusion, I am really sorry.

You can either use each room as a node, or generate waypoints/vector meshes/rooms like Niseg/global and local connectivity maps/etc over the entire dataset and use those as nodes. The actual pathfinding works the exact same no matter what, and doesn't actually know or care what it is being given.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on May 03, 2011, 12:35:57 pm
I had to read that like 5 times to get what you guys were saying..

Are you saying that the mapblock itself is a node? If you are I can totally understand what you are saying. If you are not, disregard the rest of this post hehe :P

It has been suggested to use the mapblock (or similar data structure as a mapblock) as a node that gets passed to A*
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 03, 2011, 12:56:42 pm
Oh, well that is a bad suggestion. My brain is horrible at handling irrational thoughts, so if someone suggested it I probably didn't even see it.

I mean, how would that even handle fliers/magma walkers/swimmers? :P Hell, you could make the entire map off-limits to non magma walkers by putting a single piece of magma in each mapblock.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: NW_Kohaku on May 03, 2011, 06:29:00 pm
Alright, sorry, I was thinking you were talking about merging mapblock data and pathfinding into the same set of data.

Designations are a separate 16x16 array per mapblock from the pathfinding data, they are for... designations like digging or channeling and such :) If it was up to me, that data would be replaced with a designation list but whatever hehe.

Right here I mean, it looks like traffic is stored as part of the designation data: https://github.com/peterix/dfhack/blob/master/library/include/dfhack/modules/Maps.h#L300

Or maybe I'm misreading.

No, you're not misreading *facepalm*. If that is true, then it means DF might be accessing more data than it needs to lol. The designation data for a mapblock is stored in a different memory allocation than the pathfinding data...

I had assumed it was packing all the data it needed for pathfinding into the pathfinding data :/ That still might be the case though, the traffic designations might be stored in both which wouldn't be a problem since its just 2 bits.

If you were just talking about storing mapblock data, however, 64x64x1 z-level mapblocks can run into problems... what if you have a 2x2 embark?  That's 96x96xz tiles, which means that you have to use 4 sets of 64x64, with 7168 tiles of "overlap" that contain no data per z-level. 

I'm not actually even sure how Adventure Mode works, either.  I know that pathfinding is much easier for the system in general in Pathfinding mode, since right now, almost nobody does any pathfinding, but if we are introducing cities where, potentially, we have random peasants deciding they need to pathfind to a point in the city outside the currently loaded section of the map, we need to have some sort of system that allows for both abstract and observed travel, where different blocks of the map come into "focus" and then back out into abstraction again.

If we are dealing with a map where the size of the "chunks" of map expand in 48-tile increments, the size of mapblocks should be a denominator of 48.  Otherwise, it just becomes problematic when you are adding or subtracting chunks of embark tiles from the "view" of the computer. 

The same goes when we are considering "moving fortresses".

Anyway, right now, the one true failure of the current A* system (which is to say, disregarding lag, and only focusing on the functions it seriously cannot perform) is that it doesn't actually support multitile creatures at all, and that it doesn't support swimming or flying creatures very well.

The problem with how much lag the HFS produces is that fliers seem to actually use BFS over the entire map every time they try to pathfind, even if all access into the fortress is blocked.  That means flood-filling the HFS (at least) every frame for every creature. 

At the very least, we do need a system capable of handling more flexible movement types and it would make sense to build the system in a manner that allows for abstract overland travel and "watched" travel to be swapped in and out as the player may or may not "follow" an AI that is set to travel overland in an abstracted path, forcing it to switch to "watched" travel.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 03, 2011, 07:57:45 pm
Alright, sorry, I was thinking you were talking about merging mapblock data and pathfinding into the same set of data.

Aha! I was, sort of.. let me explain.

The mapblock data includes pointers toward data like desginations and pathfinding data. I don't think anyone has quite figured out what all the bits in the pathfinding data represent, but it seems imply things like a "flyer can go here", "a building destroyer can go here", "a magma walker can go here", etc. The traffic designations are stored in the designations data. A memory optimization would be to put the traffic designations into the pathfinding data(its just 2 bits), if would save a pointer deference and a memory read for each traversed node. I wasn't trying to say that the mapblock itself should be a node, and I apologize for not being clear (I suck at English).

If you reread the part I wrote now, it should make more sense. I was wanting to consolidate data inside the mapblock or even the mapblocks themselves, not use them as a node hehe. The gains for doing so would be pretty big and require few changes in the code compared to reworking entire systems.

If you were just talking about storing mapblock data, however, 64x64x1 z-level mapblocks can run into problems... what if you have a 2x2 embark?  That's 96x96xz tiles, which means that you have to use 4 sets of 64x64, with 7168 tiles of "overlap" that contain no data per z-level.

I should have said one embark tile and not 64x64.. For some reason I was thinking 4 mapblocks per embark tile. My mistake. 

Anyway, right now, the one true failure of the current A* system (which is to say, disregarding lag, and only focusing on the functions it seriously cannot perform) is that it doesn't actually support multitile creatures at all, and that it doesn't support swimming or flying creatures very well.

Multitile creatures are solved by vector meshes, they can't travel through nodes that are too narrow or not tall enough. Also consider that many times pathfinding won't be necessary at all with vectors (if the target is in the same node, the dwarf can just walk a direct path to it). Swimming and flying creatures seem to suffer from bugs more than any flaw in the system. It is really hard for hackers to debug that type of interaction without the source :/ We can do it, it just takes more time than we like to spend :/

The problem with how much lag the HFS produces is that fliers seem to actually use BFS over the entire map every time they try to pathfind, even if all access into the fortress is blocked.  That means flood-filling the HFS (at least) every frame for every creature.

*** The rest of this post is addressing a worst case situation. Few forts breach HFS without the intent of fighting them off. ***

Possibly flood-filling the HFS for every dwarf in your fortress for every creature that is in HFS hehe. 200 dwarfs and other creatures in/above your fort, 20 HFS without access to your fort, and half a million tiles in your HFS? 2,000,000,000 possible node operations per frame lol.

I still defend my position that it isn't a flaw in the pathfinding code. It isn't the pathfinders fault if it is being called unnecessarily. HFS creatures shouldn't be so aggressive that they seek targets every frame, if they are that should be fixed regardless of how anything else works. A nice bandaid optimization would be the storing of z levels searched during pathfinding when looking for dwarf A, then checking if dwarf B was within those z levels before trying to path to it.

The proper fix is fixing the dataset, but maybe that isn't wise during this stage of game development idk. There are problems with the dataset that hurt more than pathfinding, and Toady is aware of that. DF didn't always have Z levels and so many features have been tacked onto a once basic system. In the average case it isn't a big deal and it is flexible enough to do anything. In the meantime there are many other pressing issues when it comes to performance(mainly bugs) but at some point, it will be looked at. I just hope vector meshes are considered when that day comes, because tons of game developers make the mistake of not using them (even huge well funded ones) :/
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Fieari on May 04, 2011, 10:02:52 am
Once an HFS finds a target, I don't believe they continue the BFS every frame, but I do believe they will seek a target until they find one-- and I don't necessarily see anything wrong with that.  It could be and should be improved with a proper set of connectivity maps that take fliers into account, of course, but the aggressiveness isn't the problem.

HFS can be walled off once breached, which causes severe slowdowns.  Furthermore, there are MASSIVE numbers of HFS, and they respawn (albeit slowly).  This causes a LOT of said BFS.

Regardless though, the key here is to make a pathfinding system that is efficient for ANY movement type-- walking, flying, swimming, magma... heck, add in digging, climbing, maybe even jumping... and while we're at it, might as well add in multitile movement as well.  It must be robust to handle these kinds of things.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 04, 2011, 11:14:06 am
Once an HFS finds a target, I don't believe they continue the BFS every frame, but I do believe they will seek a target until they find one-- and I don't necessarily see anything wrong with that.

There is a lot wrong with that(if that is the way it works).

Think about your computer for a second, it is controlled by an operating system that runs processes. The processes can ether be event driven or they can can poll. Notepad for example is event driven, it never does anything until the operating system tells it there is something to do(user typed something on the keyboard notepad, do something about it). Windows update for example polls, it wakes up at certain intervals and sees if your system needs to be updated. If windows update was constantly checking to see if your computer needed to be updated, it would be using up 100% of your cpu all of your time slowing down the rest of your machine. How often a polling process checks to see if it has something to do is referred to "aggressiveness". If windows update was too aggressive, it wouldn't be the fault of the update code it would be the fault of how aggressive it was trying to update.

Game design works the same way. Enemies are logical processes inside of your game, if they are spending all of their time looking for something to do that will slow down your game. Just like windows update, you need to tell them to chill and only check for work as often as necessary.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on May 05, 2011, 04:26:39 am
Once an HFS finds a target, I don't believe they continue the BFS every frame, but I do believe they will seek a target until they find one-- and I don't necessarily see anything wrong with that.  It could be and should be improved with a proper set of connectivity maps that take fliers into account, of course, but the aggressiveness isn't the problem.

HFS can be walled off once breached, which causes severe slowdowns.  Furthermore, there are MASSIVE numbers of HFS, and they respawn (albeit slowly).  This causes a LOT of said BFS.

you are talking about the O((k/2)^N)~ complexity of A* and the no-path penalty = worst case. HFS has a big N and the clowns have big k (the got lots of flags).

Regardless though, the key here is to make a pathfinding system that is efficient for ANY movement type-- walking, flying, swimming, magma... heck, add in digging, climbing, maybe even jumping... and while we're at it, might as well add in multitile movement as well.  It must be robust to handle these kinds of things.
That stuff is trivial  I can easily do it  with my room system (have to turn simulator to 3d add obsticles of diffrent types). All I'll do is add in all the collisions of interest to the list and go through them to calsify movement type on an edge.


Anyways I went alittle crazy with my simulator and made a 128X128 version  ;D . you'll see most of the stuff I did in this thread.
http://www.bay12forums.com/smf/index.php?topic=83804.0

My algorithm runs 1000 times faster than A* and needs about 100ms~ preparation type (no cache version). A* runs on a graph that size using 190~ million iterations (13~ seconds) . I manage to keep it small at about 47000 (14~ms) which is about 2000 iterations per subpath.

EDIT: I made A* run much faster using two bit vectors - one for open and one for closed set.
EDIT2:  insert in order is in now.  A* is orders of magnitudes faster than the original  by replacing linear search with the bit vectors and making all the pushes inserts in order which is log N time (best node always in front). With a regular A* Which is a node explosion it reduced runtime by a lot because it's (k/2)^N is much larger.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: sockless on May 19, 2011, 03:44:17 am
http://en.wikipedia.org/wiki/Ant_colony_optimization

Might be something interesting for you folks to look into. Essentially a DFS with Heuristics if I'm not mistaking.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Draco18s on May 19, 2011, 08:32:55 am
The problem with an Ant Colony Optimization is that it depends entirely on a single starting location compared to a single ending location (the traveling salesman solution is also not viable for DF, as it's a round trip through multiple locations) when what DF needs is a multi-start, multi-end solution.  The "get from any stockpile to any other stockpile" type solution.  You can't just track pheromones, as it'll just end up a useless mess (observe blood in a fort: in any tile that has blood, assume that it has high pathing frequency, thus large pheromone count, is this collection of tiles useful?).

The problem is one of "multiple actors, same job" versus "single actor, many jobs."  The Ant Colony is the former, DF is the latter.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: ferok on May 19, 2011, 03:55:02 pm
The whole point of threads and "slicing" is to transfer processor power onto another task while waiting for a memory fetch.  This is something that has existed for decades.  Thing is, DF is not multi-threaded, so all this means is that your processor will spend its time working on all the other programs running on your computer during this time.
That's the point of multi-threading in a single processor environment, but that environment exists in very few places anymore. Not to derail, just to be pedantic.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on May 19, 2011, 04:45:15 pm
that ant farm reminds me of path caching which has a big penelty when a path to the destination doesn't exist. you also need a path smoother but that is not to bad in terms of complexity.

my room spliting is a beter choise but i need to figure out an update scheme. you can practicaly regenerate all of them every 1000 frames and be fine. that is not optimal though.

it reduces complexity,  split the path and has a low penalty.  the room system can also help finding the closest item.

it has. room for improvment but. it works. well as is.

posted from a PDA sorry for the bad English ...
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: tps12 on May 19, 2011, 07:49:53 pm
That's the point of multi-threading in a single processor environment, but that environment exists in very few places anymore. Not to derail, just to be pedantic.

Interesting! I think this whole thread is dedicated to extreme pedantry, so no worries.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: devek on May 19, 2011, 10:07:41 pm
The whole point of threads and "slicing" is to transfer processor power onto another task while waiting for a memory fetch.  This is something that has existed for decades.  Thing is, DF is not multi-threaded, so all this means is that your processor will spend its time working on all the other programs running on your computer during this time.
That's the point of multi-threading in a single processor environment, but that environment exists in very few places anymore. Not to derail, just to be pedantic.

If we are going to be pedantic... Threading was not invented to split work between cpus, as threads were invented long before any computers that had multiple processors. To say that the environment of threading in single processor environments only exist in very few places would only be correct if you never made a phone call or drove an automobile.

Userland threads, or N:1, are so useful for their low overhead that there is an entire programming language called erlang for it. 1:1 threading overhead on lesser platforms like Linux and Windows are so horrible, programmers go out of their way to make as few threads as possible because many programs end up being faster single threaded or compiled with userland threading.
Title: Re: Improving Pathfinding. (Computer sciency)
Post by: Niseg on May 26, 2011, 08:36:34 am
I'm thinking of improving my room model by removing the bitvector description of from the room object and leaving the edges. I'll use the output of my BFS collider as a lookup table of O(1) to find if a node is in a room . Then adding an update scheme would be much easier but the data structure might take a lot of memory but I can add some kind of scheme to reduce it to 1 byte per node or less .

The update scheme would look at a collection of nodes that changed from either wall->floor or floor->wall. A floor->wall is the easier case because at worst it would block or or more access point and removing edges is the easy. a wall->floor change would require looking at all its neighbors and decide which room it should be added to and then update that room and its neighbors .

Other than that I'm thinking about defining the access point using some kind of line or vector . I think the rooms I created can be easily converted to nav meshes and then path finding between them would be very trivial. due to a polygon shape you can just draw line between then without any collisions .  I can also implement a vector method with an A* to walk around obstetrical . This should usually reduce the complexity to almost nothing because it would shorten the space A* would have to look at to nothing.

Even though my rooms don't look nice and rounded it is not really critical for the scheme to work.  I might have mentioned this before but my scheme only look at around 3-4% of the nodes as opposed to A* who looks at over 40%. A* also take more iterations to find the target - about 20 times more (come from insert in order optimization only it used to be more computationally intensive) .  My scheme also support spreading the pathfinding algorithm to many time slices instead of one huge step. no path penalty is extremely low while A* penalty is extremely high .

More things can be added to this scheme like finding the closest item according to the room it's in . This way dwarves won't use a blind heuristic to pick their stones. This can also be fixed with a line of site penalty heuristic like i did in my calculator it draws a line, validate it and add 2 for every  wall it hits (the minimum distance to go around it).it can be made smarter than that.