Pathfinding algorithm - path-finding

I'm doing a project where the objective is to find the less turn-cost way to send X ants from point A to point B with the restriction that only one ant at a time can stand on "in-between platforms" - don't know how to say that in English - with the exception of point A and B.
I've already looked to algorithms such as A* or the Dijkstra's but they only focus on the shortest path to get from point A to point B which, in some cases, isn't the best as you'd rather take 2 longer path and send more ants in one turn.
And this is where I'm needing you. Do you guys know such an algorithm ?
Hope I'm being clear with my question and will be looking forward to an answers.
Thanks.
EDIT : Here is an example of where the A* is not going to work :
-L-M-N-O-P-S-T-U-V-W-X-Y-Z--| Going from one letter
| | | to another costs 1 turn
H-----I-----J------K |
| | |
START--A-B-C-D-E-F-G-------END
If I have 17 ants, the best option available is sending 2 ants at a time in directions :
START-H-I-J-K-W-X-Y-Z-END
START-A-B-C-D-E-F-G-END
rather than all in START-H-I-J-K-G-END as A* would suggest as best option.

you can use A* to solve your problem you just need to adjust dynamically your map to take the position of your ants into account

You could use floodfill. What floodfill does is it traces every possible pathway and determines the best solution, but you get to define "best". For example, you can create a total time variable that tracks the time through recursion. You can make a recursive method that only returns the time variable when it reaches B, and then select the shortest value.

Related

Tile Based A* Pathfinding, but with a bomb

I've written a simple A* path finding algorithm to quickly find a way through a tile based dungeon in which the tiles contain the information of walls.
An example of a dungeon (only 1 path for simplicity):
However now I'd like to add a variable amount of "Bombs" to the algorithm which would allow the path-finding to ignore 1 wall. However now it doesn't find the best paths anymore,
for example with use of only 1 bomb the generated path looks like the first image here:
Edit: actually it would look like this: https://i.stack.imgur.com/kPoAA.png
While the correct path would be the second image
The problem is that "Closed Nodes" now interfere with possible paths. Any ideas of how to tackle this problem would be greatly appreciated!
Your "game state" will no longer only be defined by your location, but also by an integer representing the number of bombs you have left. If you're following the pseudocode of A* on wikipedia, this means you cannot simply implement the closedSet as a grid of booleans. It should probably be implemented as, for example, a hash map / hash set, where every entry holds the following data:
x coordinate
y coordinate
number of bombs left
By visiting a certain position in the search process, you'll no longer mark just that position as closed. You'll mark the combination of position + number of bombs left as closed. That way, if later on in the same search process you run into a position where you're at the same location, but have more bombs left, you will not ignore it as closed but will actually continue searching that possibility.
Note that, if the maximum possible number of bombs is relatively low, you could also implement the closedSet as an array of boolean grids, where you first index by number of bombs, then by x and y coordinates to find out if a specific position is closed or not.
Doesn't this mean that you just pretend to not have any walls at all?
Use A* to find the shortest path from start to end and then check how many walls you'd have to go through. If you have enough bombs, you can use the path. Otherwise, try the next longest path and so on.
By the way: you might want to check http://gamedev.stackexchange.com for questions like this one.
You need to tweak the cost function to cost something for a bomb, then run the algorithm normally with an infinite cost for a second bomb. To get the bomb approximately halfway, play about with cost function, it should probably cost about the heuristic A-B distance times the cost for an empty tile. If you have two bombs, half the cost and of course then use of three bombs costs infinite.
But don't expect very good results. A* isn't designed for that kind of optimisation.

Find solution minimum spanning tree (with conditions) when extending graph

I have a logic question, therefore chose from two explanations:
Mathematical:
I have a undirected weighted complete graph over 2-14 nodes. The nodes always come in pairs (startpoint to endpoint). For this I already have the minimum spanning tree, which considers that the pairs startpoint always comes before his endpoint. Now I want to add another pair of nodes.
Real life explanation:
I already have a optimal taxi route for 1-7 people. Each joins (startpoint) and leaves (endpoint) at different places. Now I want to find the optimal route when I add another person to the taxi. I have already the calculated subpaths from each point to each point in my database (therefore this is a weighted graph). All calculated paths are real value, not heuristics.
Now I try to find the most performant solution to solve this. My current idea:
Find the point nearest to the new startpoint. Add it a) before and b) after this point. Choose the faster one.
Find the point nearest to the new endpoint. Add it a) before and b) after this point. Choose the faster one.
Ignoring the case that the new endpoint comes before the new start point, this seams feasible.
I expect that the general direction of the taxi is one direction, this eliminates the following edge case.
Is there any case I'm missing in which this algorithm wouldn't calculate the optimal solution?
There are definitely many cases were this algorithm (which is a First Fit construction heuristic) won't find the optimal solution. Given a reasonable sized dataset, in my experience, I would guess to get improvements of 10-20% by simply taking that result and adding metaheuristics (or other optimization algo's).
Explanation:
If you have multiple taxis with a limited person capacity, it has an inherit bin packing problem, which is NP-complete (which is proven to be suboptimally solved by all known construction heuristics in P).
But even if you have just 1 taxi, it is similar to TSP: if you have the optimal solution for 10 locations and add 1 location, it can create a snowball effect in the optimal solution to make the optimal solution look completely different. (sorry, no visual image of this yet)
And if you need to any additional constraints on top of that later on, you need to be aware of these false assumptions.

Prolog Accumulators. Are they really a "different" concept?

I am learning Prolog under my Artificial Intelligence Lab, from the source Learn Prolog Now!.
In the 5th Chapter we come to learn about Accumulators. And as an example, these two code snippets are given.
To Find the Length of a List
without accumulators:
len([],0).
len([_|T],N) :- len(T,X), N is X+1.
with accumulators:
accLen([_|T],A,L) :- Anew is A+1, accLen(T,Anew,L).
accLen([],A,A).
I am unable to understand, how the two snippets are conceptually different? What exactly an accumulator is doing different? And what are the benefits?
Accumulators sound like intermediate variables. (Correct me if I am wrong.) And I had already used them in my programs up till now, so is it really that big a concept?
When you give something a name, it suddenly becomes more real than it used to be. Discussing something can now be done by simply using the name of the concept. Without getting any more philosophical, no, there is nothing special about accumulators, but they are useful.
In practice, going through a list without an accumulator:
foo([]).
foo([H|T]) :-
foo(T).
The head of the list is left behind, and cannot be accessed by the recursive call. At each level of recursion you only see what is left of the list.
Using an accumulator:
bar([], _Acc).
bar([H|T], Acc) :-
bar(T, [H|Acc]).
At every recursive step, you have the remaining list and all the elements you have gone through. In your len/3 example, you only keep the count, not the actual elements, as this is all you need.
Some predicates (like len/3) can be made tail-recursive with accumulators: you don't need to wait for the end of your input (exhaust all elements of the list) to do the actual work, instead doing it incrementally as you get the input. Prolog doesn't have to leave values on the stack and can do tail-call optimization for you.
Search algorithms that need to know the "path so far" (or any algorithm that needs to have a state) use a more general form of the same technique, by providing an "intermediate result" to the recursive call. A run-length encoder, for example, could be defined as:
rle([], []).
rle([First|Rest],Encoded):-
rle_1(Rest, First, 1, Encoded).
rle_1([], Last, N, [Last-N]).
rle_1([H|T], Prev, N, Encoded) :-
( dif(H, Prev)
-> Encoded = [Prev-N|Rest],
rle_1(T, H, 1, Rest)
; succ(N, N1),
rle_1(T, H, N1, Encoded)
).
Hope that helps.
TL;DR: yes, they are.
Imagine you are to go from a city A on the left to a city B on the right, and you want to know the distance between the two in advance. How are you to achieve this?
A mathematician in such a position employs magic known as structural recursion. He says to himself, what if I'll send my own copy one step closer towards the city B, and ask it of its distance to the city? I will then add 1 to its result, after receiving it from my copy, since I have sent it one step closer towards the city, and will know my answer without having moved an inch! Of course if I am already at the city gates, I won't send any copies of me anywhere since I'll know that the distance is 0 - without having moved an inch!
And how do I know that my copy-of-me will succeed? Simply because he will follow the same exact rules, while starting from a point closer to our destination. Whatever value my answer will be, his will be one less, and only a finite number of copies of us will be called into action - because the distance between the cities is finite. So the total operation is certain to complete in a finite amount of time and I will get my answer. Because getting your answer after an infinite time has passed, is not getting it at all - ever.
And now, having found out his answer in advance, our cautious magician mathematician is ready to embark on his safe (now!) journey.
But that of course wasn't magic at all - it's all being a dirty trick! He didn't find out the answer in advance out of thin air - he has sent out the whole stack of others to find it for him. The grueling work had to be done after all, he just pretended not to be aware of it. The distance was traveled. Moreover, the distance back had to be traveled too, for each copy to tell their result to their master, the result being actually created on the way back from the destination. All this before our fake magician had ever started walking himself. How's that for a team effort. For him it could seem like a sweet deal. But overall...
So that's how the magician mathematician thinks. But his dual the brave traveler just goes on a journey, and counts his steps along the way, adding 1 to the current steps counter on each step, before the rest of his actual journey. There's no pretense anymore. The journey may be finite, or it may be infinite - he has no way of knowing upfront. But at each point along his route, and hence when ⁄ if he arrives at the city B gates too, he will know his distance traveled so far. And he certainly won't have to go back all the way to the beginning of the road to tell himself the result.
And that's the difference between the structural recursion of the first, and tail recursion with accumulator ⁄ tail recursion modulo cons ⁄ corecursion employed by the second. The knowledge of the first is built on the way back from the goal; of the second - on the way forth from the starting point, towards the goal. The journey is the destination.
see also:
Technical Report TR19: Unwinding Structured Recursions into Iterations. Daniel P. Friedman and David S. Wise (Dec 1974).
What are the practical implications of all this, you ask? Why, imagine our friend the magician mathematician needs to boil some eggs. He has a pot; a faucet; a hot plate; and some eggs. What is he to do?
Well, it's easy - he'll just put eggs into the pot, add some water from the faucet into it and will put it on the hot plate.
And what if he's already given a pot with eggs and water in it? Why, it's even easier to him - he'll just take the eggs out, pour out the water, and will end up with the problem he already knows how to solve! Pure magic, isn't it!
Before we laugh at the poor chap, we mustn't forget the tale of the centipede. Sometimes ignorance is bliss. But when the required knowledge is simple and "one-dimensional" like the distance here, it'd be a crime to pretend to have no memory at all.
accumulators are intermediate variables, and are an important (read basic) topic in Prolog because allow reversing the information flow of some fundamental algorithm, with important consequences for the efficiency of the program.
Take reversing a list as example
nrev([],[]).
nrev([H|T], R) :- nrev(T, S), append(S, [H], R).
rev(L, R) :- rev(L, [], R).
rev([], R, R).
rev([H|T], C, R) :- rev(T, [H|C], R).
nrev/2 (naive reverse) it's O(N^2), where N is list length, while rev/2 it's O(N).

Solving an extension of the Shortest Hamiltonian Path

I was thinking about an extension to the Shortest Hamiltonian Path (SHP) problem, and I couldn't find a way of solving it. I know it is NP-complete, but I figured I'd ask here for ideas, since I do not want to simply brute force the problem.
The extension is fairly simply: Given an undirected, complete, weighted graph with n vertices, find the shortest hamiltonian path with end vertices v and u.
So, bruteforce would still take O(n!) time, since the remaining n-2 vertices can be visited in (n-2)! ways. I was trying to find a way to maybe solve this slightly faster. My efforts for finding a way to solve this problem in a beneficial manner has so far been fruitless.
Would anyone have an idea how to exploit the knowledge of the end-vertices? Preferably explained alongside some pseudocode. It is required for the solution found to be optimal.
I guess it could be solved by integer programming, since the knowledge of end nodes are fairly limiting, and makes it easy to avoid cycles, but it wouldn't really exploit the composition of the problem.
If you want to find the shortest path to connect all nodes, then you should look at travelling salesman algorithms. I don't exactly see why you approach it as an HSP. The only reason I can think of is that you want to specify your starting cities, but it should be easy to fix that (if you need that I can post it) by changing your graph a bit.
edit: adding how to tweak your graph
Add 1 node (call it E) and only connect it to your starting and ending nodes. A TSP will compute a solution to your problem by connecting all your nodes. As E is only reachable by going from start to E and then to end, the solution (a cycle yes) will contain start - E - end. Then you remove the 2 edges to and from E and you have the optimal solution. Within the TSP, the path from start to end will be optimal.
You can use a metaheuristic algorithm. There are many kinds of them (Local search, constructive search, etc.). One of them could be based on:
For each x belonging to the set of vertices X:
- Find the set of closest vertices to x C.
- Filter the set C in order to include one of them in the path P.
Repeat until all vertices of X have been included in the path P.
End.

general idea and maybe example on graph

I'm looking for a general idea (and maybe some code example or at least pseudocode)
Now, this is from a problem that someone gave me, or rather showed me, I don't have to solve it, but I did most of the questions anyway, the problem that I'm having is this:
Let's say you have a directed weighted graph with the following nodes:
AB5, BC4, CD8, DC8, DE6, AD5, CE2, EB3, AE7
and the question is:
how many different routes from C to C with a distance of less than x. (say, 10, 20, 30, 40)
The answer of different trips is: CDC, CEBC, CEBCDC, CDCEBC, CDEBC, CEBCEBC, CEBCEBCEBC.
The main problem I'm having with it is that when I do DFS or BFS, my implementation first chooses the node and marks it as visited therefore I'm only able to find 2 paths which are CDC and CEBC and then my algorithm quits. If I don't mark it as visited then on the next iteration (or recursive call) it will choose the same node and not next available route, so I have to always mark them as visited however by doing that how can I get for example CEBCEBCEBC, which is pretty much bouncing between nodes.
I've looked at all the different algorithms books that I have at home and while every algorithm describes how to do DFS, BFS and find shortest paths (all the good stufF), none show how to iterate indefinitively and stop only when one reaches certain weight of the graph or hits certain vertex number of times.
So why not just keep branching and branching; at each node you will evaluate two things; has this particular path exceeded the weight limit (if so, terminate the branch) and is this node where I started (in which case log my path history to an 'acceptable solutions' list); then make new branches which each take a step in each possible direction.
You should not mark nodes as visited; as MikeB points out, CDCDC is a valid solution and yet it revisits D.
I'd do it lke this:
Start with two lists of paths:
Solutions (empty) and
ActivePaths (containing one path, "C").
While ActivePaths is not empty,
Take a path out of ActivePaths (suppose it's "CD"[8]).
If its distance is not over the limit,
see where you are by looking at the last node in the path ("D").
If you're at "C", add a copy of this path to Solutions.
Now for each possible next destination ("C", "E")
make a copy of this path, ("CD"[8])
append the destination, ("CDC"[8])
add the weight, ("CDC"[16])
and put it in ActivePaths
Discard the path.
Whether this turns out to be a DFS, a BFS or something else depends on where in ActivePaths you insert and remove paths.
No offense, but this is pretty simple and you're talking about consulting a lot of books for the answer. I'd suggest playing around with the simple examples until they become more obvious.
In fact you have two different problems:
Find all distinct cycles from C to C, we will call them C_1, C_2, ..., C_n (done with a DFS)
Each C_i has a weight w_i, then you want every combination of cycles with a total weight less than N. This is a combinatorial problem (and seems to be easily solvable with dynamic programming).

Resources