I'm working on an A* algorithm. This is the code for the pathfinding method. For reference, this is the board I am working with: http://i.imgur.com/xaAzNSw.png?1 Each color tile represents a different heuristic value. For some unknown reason, it finds a path every single time, just not always the correct path. Here is the code for the pathfinding method. If anyone needs any clarifications, I'd be happy to provide them.
public List<Point> findPath(Point start, Point end) {
//declarations and instantiations
List<PathState> closedList = new ArrayList<PathState>(); //the nodes already considered
List<PathState> openList = new ArrayList<PathState>(); //nodes to be considered
openList.add(new PathState(start, end, tm)); //add starting point
PathState current = openList.get(0);
while(!current.isGoal()){
//sort open list to find the pathstate with the best hscore(sorts by hscore)
Collections.sort(openList);
current = openList.get(openList.size() - 1);
closedList.add(current);
openList.remove(current);
//get the valid children of current node
List<PathState> children = current.getChildren();;
if(!current.isGoal()){
for(int i = 0; i < children.size(); i++){
if(!closedList.contains(children.get(i))){
if(openList.contains(children.get(i))){
if(openList.get(openList.indexOf(children.get(i))).getgScore() > children.get(i).getgScore()){
//child is already on the open list, but this node has lower g value
//change g value and parent of node on open list
openList.get(openList.indexOf(children.get(i))).setG(children.get(i).getgScore());
openList.get(openList.indexOf(children.get(i))).changeParent(current);
}
}else{
//child not in closed list
openList.add(children.get(i));
//repaint the terrain panel with shades
tp.addAstarState(children.get(i));
tp.repaint();
try {
Thread.sleep(25);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
}
}
//returns the path from winning node to start for output
return current.getPath();
}
A* is basically Djikstra's algorithm but you direct your search to the destination by combining your distance function with an estimate of the remaining distance.
At node x, the cost or "score" is (distance_so_far) for djikstra
at A*, it is (distance_so_far + estimate_of_remaining_distance)
To make sure that A* finds the shortest path, the estimate_of_remaining_distance must be a true lower bound. That means it must always be less than the actual remaining distance. That means, you can never overestimate this distance otherwise it becomes an inexact heuristic in which case it won't necessarily find the shortest path.
This is a good reference: http://theory.stanford.edu/~amitp/GameProgramming/AStarComparison.html
It links to this reference which explains more about heuristic functions: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html
Related
Not sure how to implement depth first search algorithmn into my code. Here is an example of breadth first search algorithm solving a 8 puzzle:
public direction[] Solve(nPuzzle puzzle) {
//This method uses the fringe as a queue.
//Therefore, nodes are searched in order of cost, with the lowest cost
// unexplored node searched next.
//-----------------------------------------
//put the start state in the Fringe to get explored.
addToFrontier(puzzle.StartState);
ArrayList<PuzzleState> newStates = new ArrayList<PuzzleState>();
while(Frontier.size() > 0)
{
//get the next item off the fringe
PuzzleState thisState = popFrontier();
//is it the goal item?
if(thisState.equals(puzzle.GoalState))
{
//We have found a solution! return it!
return thisState.GetPathToState();
}
else
{
//This isn't the goal, just explore the node
newStates = thisState.explore();
for(int i = 0; i < newStates.size(); i++)
{
//add this state to the fringe, addToFringe() will take care of duplicates
addToFrontier(newStates.get(i));
}
}
}
//No solution found and we've run out of nodes to search
//return null.
return null;
}
There is more code here
Would really appreciate any help
a. The main difference in implementation is: in DFS the nodes to be explored are stored in a stck, while in BFS they are stored in a queue.
b. For the puzzle you are trying to solve I think BFS is more appropriate because you are searching for the shortest path.
For more help post mcve so we do not have to do a lot of guesswork.
I implemented Held-Karp in Java following Wikipedia and it gives the correct solution for total distance of a cycle, however I need it to give me the path (it doesn't end on the same vertex where is started). I can get path if I take out the edge with largest weight from the cycle, but there is a possibility that 2 different cycles have same total distance, but different maximum weight, therefore one of the cycles is wrong.
Here is my implementation:
//recursion is called with tspSet = [0, {set of all other vertices}]
private static TSPSet recursion (TSPSet tspSet) {
int end = tspSet.endVertex;
HashSet<Integer> set = tspSet.verticesBefore;
if (set.isEmpty()) {
TSPSet ret = new TSPSet(end, new HashSet<>());
ret.secondVertex = -1;
ret.totalDistance = matrix[end][0];
return ret;
}
int min = Integer.MAX_VALUE;
int minVertex = -1;
HashSet<Integer> copy;
for (int current: set) {
copy = new HashSet<>(set);
copy.remove(current);
TSPSet candidate = new TSPSet(current, copy);
int distance = matrix[end][current] + recursion(candidate).totalDistance;
if (distance < min) {
min = distance;
minVertex = current;
}
}
tspSet.secondVertex = minVertex;
tspSet.totalDistance = min;
return tspSet;
}
class TSPSet {
int endVertex;
int secondVertex;
int totalDistance;
HashSet<Integer> verticesBefore;
public TSPSet(int endVertex, HashSet<Integer> vertices) {
this.endVertex = endVertex;
this.secondVertex = -1;
this.verticesBefore = vertices;
}
}
You can slightly alter the dynamic programming state.
Let the path start in a node S. Let f(subset, end) be the optimal cost of the path that goes through all the vertices in the subset and ends in the end vertex (S and end must always be in the subset). A transition is just adding a new vertex V not the subset by using the end->V edge.
If you need a path that ends T, the answer is f(all vertices, T).
A side note: what you're doing now is not a dynamic programming. It's an exhaustive search as you do not memoize answers for subsets and end up checking all possibilities (which results in O(N! * Poly(N)) time complexity).
Problem with current approach
Consider this graph:
The shortest path visiting all vertices (exactly once each) is of length 3, but the shortest cycle is 1+100+200+300, which is 301 even if you remove the maximum weight edge.
In other words, it is not correct to construct the shortest path by deleting an edge from the shortest cycle.
Suggested approach
An alternative approach to convert your cycle algorithm into a path algorithm is to add a new node to the graph which has a zero cost edge to all of the other nodes.
Any path in the original graph corresponds to a cycle in this graph (the start and end points of the path are the nodes that the extra node connects to.
Hi I'm working on this little project which requires me to build a matrix in Java which resembles a chess board. I'm supposed to get the Knight to get from a point to another(In the way Knight moves). So I need to find the shortest way to get there in the end.
My problem is, I can't get to connect the edges to get to that point. I can find out if the vertex is a valid move but I can't seem to find a way to create nodes to get to that point. For Example,
0 XXXXX
1 XXXOX
2 XXXXX
3 XXKXX
4 XXXXX
5 XXXXX
I need to create nodes that connect K to O to find out shortest distance later.
PS. I'll be okay with just hints of how to get there or just some tips. Don't really need the exact code. Thank you very much!
I know it's a bad representation of matrix up there but spare me the critique please
A classic Breadth-First-Search is probably the simplest approach:
class Location {
int x;
int y;
List<Location> adjacent() {
// TODO return list of locations reachable in a single step
}
}
List<Location> findShortestPath(Location start, Location destination) {
Location[][] previous = new Location[8][8];
Deque<Location> queue = new ArrayDeque<>();
queue.add(start);
do {
Location loc = queue.poll();
for (Location n : loc.neighbors()) {
if (previous[n.x][n.y] == null) {
previous[n.x][n.y] = loc;
queue.add(n);
if (n.x == destination.x && n.y == destination.y) {
// we've found a way, let's reconstruct the list of steps
List<Location> path = new ArrayList<>();
for (Location l = n; l != start; l = previous[l.x][l.y]) {
path.add(l);
}
path.reverse();
return path;
}
}
}
} while (!queue.isEmpty());
return null; // no path exists
}
This code enumerates all paths from the start location. Therefore, if there is a path to destination, it will find it. In addition, because paths are enumerated in order or ascending length, the first such path will be a shortest one.
The chess board can be implemented by a 2d array. Each cell in the matrix can be considered to be a node (or vertex) in the graph. Edge is composed of two nodes (in this case two cells) one being the from or source [ lets call it Nod A] and other being the to or neighbor or destination node [ Lets call it node B].
Edge exits if there is a possibility of moving from node A to node B.
You can use Dijkstra's algorithm.
http://krishnalearnings.blogspot.in/2015/07/implementation-in-java-for-dijkstras.html
For Node with the Knight's position you can see the possibilities of the cells where Knight can move to and add in the Min Heap. The weight of each edge is constant. You just need to update the cost of the Node.
So, I've been implementing Dijkstra's algorithm for pathfinding through a maze I generate (I know some of you might think something like A* would be better, but Dijkstra's perfectly fits my needs), and I've run into a small issue. I feel like I'm overlooking something, but when I return the "path" from the start node to the end node, it returns the entire search path the algorithm took (every node it visited), and not the path to the node.
//Uses djikstra's algorithm to find the shortest path between two nodes
//"vertices" is the global ArrayList in the class with all vertices in the graph.
#Override
public ArrayList<Vertex> pathfind(Vertex v1, Vertex v2) {
ArrayList<Vertex> path = new ArrayList<Vertex>();
ArrayList<Vertex> unvisited = new ArrayList<Vertex>();
ArrayList<Vertex> visited = new ArrayList<Vertex>();
if (!vertices.contains(v1) || !vertices.contains(v2)) {
return path;
}
//initialize distances
v1.setDistance(0);
for(Vertex vert : vertices) {
if(vert != v1) {
vert.setDistance(Integer.MAX_VALUE);
}
unvisited.add(vert);
}
Vertex current = v1;
//begin
while (!unvisited.isEmpty()) {
//for all adjacent vertices that are unvisited
for (Vertex v : current.adjacentVertices()) {
if (!visited.contains(v)) {
//if the distance of that vertex is greater than
//the added distance of the current node + the edge connecting the two
int pathDist = current.getDistance() + findEdge(current, v).getElement();
if (v.getDistance() > pathDist) {
//assign the new distance
v.setDistance(pathDist);
}
}
}
//remove the current node from the visited set and add it to visited
visited.add(current);
unvisited.remove(current);
//add current node to the path
path.add(current);
//return if we found the destination
if (current == v2)) {
return path;
}
//else move to the lowest value node
current = findSmallest(unvisited);
}
return path;
}
I know it must be something painfully obvious but I'm hitting my head against the wall, any help would be appreciated. Thanks!
You might want to calculate the distances first/ stabilize the distance to minimum value using the algo, then run over the graph to get the nodes for the path.
As current = findSmallest(unvisited) might get you node from a path which is not connected.
Thanks for the help everyone, I ended up making a HashMap with links to the previous nodes, and traversed that back to the start.
I am writing a small section of a program in which i have to write up a pathfinding algorithm. The function takes in what will be known as 'routes' that each define a start and end point in 2D space. The algorithm is required to find the shortest and most efficient (to a degree) path (from the origin) to take through these routes, minimising the total distance traveled overall.
I did a bit of research and started down a path that i thought might work. So far i have converted the routes into a directed graph which is all linked up as if it were an idealised road map. I then attempted to perform an A* search on this graph. The heuristic i used calculates the total distance of the 'routes' left to travel and the distance from start (G) value i used was just the cumulative distance traveled to get to the current point. This works for some input but others return no path at all and i cant seem to figure out why.
Is is possible that my heuristic is wrong and this is causing a miscalculation somewhere or is it more likely that the A* procedure itself is wrong? or am i just on completely the wrong track here?
I'll put the getPath function below (written in Java) just in case that helps.
Thanks in advance.
public ArrayList<Vector2> getPath()
{
PriorityQueue<SearchNode> openList = new PriorityQueue<SearchNode>(10, new SearchNodeComparator());
ArrayList<SearchNode> closedList = new ArrayList<SearchNode>();
map.startJobs();
searchDepth = 0;
SearchNode start = searchableGraph.getNode(new Vector2(0, 0));
int goalsLeft = map.getJobCount();
start.setDistanceTraveled(0);
openList.add(start);
while (openList.size() > 0)
{
SearchNode current = openList.peek();
searchDepth++;
if (map.isJobEndPoint(current.getValue()))
{
map.completeJob(current.getValue());
goalsLeft--;
}
if (reachedGoalState(current, searchableGraph.getNodes().size()))
{
return getFinalPath(current);
}
else
{
ArrayList<SearchNode> neighbours = getNeighbours(current);
for (int i = 0; i < neighbours.size(); i++)
{
SearchNode node = neighbours.get(i);
System.out.print("Inspecting node" + node.getValue().toString());
float distanceTraveled = current.getDistanceTraveled() + getDistance(current.getValue(), node.getValue());
float heuristic = heuristic(node);
if (!openList.contains(node) && !closedList.contains(node))
{
node.setDistanceTraveled(distanceTraveled);
node.setDistanceToGoal(distanceTraveled + heuristic);
node.setParent(current);
openList.add(node);
}
else if(openList.contains(node))
{
if (node.getDistanceTraveled() <= distanceTraveled)
{
node.setDistanceToGoal(distanceTraveled + heuristic);
node.setParent(current);
}
}
}
openList.remove(current);
closedList.add(current);
}
}
return new ArrayList<Vector2>();
}
The heuristic i used calculates the total distance of the 'routes' left to travel
The heuristic used by A* must be admissible; that is, it must never overestimate the distance to the end.
If I understand your description correctly, your heuristic is not admissible, so is not guaranteed to work.