i implemented a simple A* and noticed that it does get into an infity loop if all 4 spots around my Character are filled. Current i am stuck how i get it work so they start running into the nearest possible spot. Any Guesses on it? (sorry for the long code)
the A*
private Node aStarSearch(int startX, int startY) {
openList.clear();
closeList.clear();
successor.clear();
Node startNode = new Node(null, startX, startY, 0, 0);
openList.add(startNode);
while (openList.size() != 0) {
// sort the list
Collections.sort(openList, nodeComperator);
Node q = openList.remove(0); // get the first object
int qx = q.x;
int qy = q.y;
// start adding the successors
// left
Node left = createNeighbor(q, qx - 1, qy);
if (left != null && !closeList.contains(left))
successor.add(left);
// right
Node right = createNeighbor(q, qx + 1, qy);
if (right != null && !closeList.contains(right))
successor.add(right);
// // down
Node down = createNeighbor(q, qx, qy - 1);
if (down != null && !closeList.contains(down))
successor.add(down);
// up
Node up = createNeighbor(q, qx, qy + 1);
if (up != null && !closeList.contains(up))
successor.add(up);
// calc
for (Node suc : successor) {
if (suc.x == (int) this.screen.character.mapPos.x
&& suc.y == (int) this.screen.character.mapPos.y)
return suc;
boolean add = true;
if (betterIn(suc, openList)) // openList und der
add = false;
if (betterIn(suc, closeList)) // closedList
add = false;
if (add)
openList.add(suc);
}
closeList.add(q);
}
return null;
}
private Node createNeighbor(Node parrent, int x, int y) {
if (x >= 0 && y >= 0 && x < this.screen.map.width
&& y < this.screen.map.height
&& this.screen.map.mapArray[x][y] != Config.CANTMOVEONPOSITION
&& this.screen.map.mapArray[x][y] != Config.MONSTERSTATE) {
Node n = new Node(parrent, x, y);
n.g = calcG(n);
n.h = calcH(n, (int) this.screen.character.mapPos.x,
(int) this.screen.character.mapPos.y);
return n;
}
return null;
}
private float calcG(Node n) {
Node p = n.getParrent();
return p.g + 1;
}
private float calcH(Node n, int targetX, int targetY) {
float dx = Math.abs(n.x - targetX);
float dy = Math.abs(n.y - targetY);
return (float) Math.sqrt((float) (dx * dx) + (dy * dy));
}
private boolean betterIn(Node n, List<Node> l) {
for (Node no : l) {
if (no.x == n.x && no.y == n.y && (no.g + no.h) <= (n.g + n.h))
return true;
}
return false;
}
My Node:
public class Node {
public int x, y;
public float g, h;
private Node parrent;
public Node(Node parrent, int x, int y, float g, float h) {
this.parrent = parrent;
this.x = x;
this.y = y;
this.g = g;
this.h = h;
}
public Node(Node parrent, int x, int y) {
this.parrent = parrent;
this.x = x;
this.y = y;
}
public Node getParrent() {
return parrent;
}
public void setParrent(Node parrent) {
this.parrent = parrent;
}
#Override
public boolean equals(Object o) {
// override for a different compare
return ((Node) o).x == this.x && ((Node) o).y == this.y;
}
#Override
public int hashCode() {
// if x and y are the same they are the same
return x + y;
}
}
If i do use nodes that are blocked but give them a high h they do not walk correct anymore so i dont know whats going wrong here.
Your A* algorithm seems a little bit screwy. But the code's not very clear -- for UP, DOWN, LEFT, RIGHT you repeat the same section (which should be broken out to a method).
It's not clear whether "discovered" nodes are clearly represented -- they should be a Set -- whereas you have "open", "closed" and "successor".
Checking each of your UP,DOWN,LEFT,RIGHT neighbors should be factored out to a method, which you call 4 times with neighborX and neighborY positions.
There isn't a single clear line which correctly tests whether a given neighbor (it's a neighbor, not a successor) has already been "discovered".
Neither am I sure about the post-processing of successors. Viz:
// calc
for (Node suc : successor) {
if (suc.x == (int) this.screen.character.mapPos.x
&& suc.y == (int) this.screen.character.mapPos.y)
return suc;
boolean add = true;
if (betterIn(suc, openList)) // openList und der
add = false;
if (betterIn(suc, closeList)) // closedList
add = false;
if (add)
openList.add(suc);
}
Since you sort "open nodes" on every iteration & pick the probable best, this doesn't really make sense to me & may be erroneous.
Presumably the algorithm should terminate promptly, when all four directions around the character are blocked. Failure to terminate implies that openList is not be processed correctly/ or incorrect nodes are being added.
Put some Log4J logging in & write a simple unit-test to verify it's correct behaviour in these conditions.
I also recommend rolling the 'createNeighbor', 'discovered check' and 'add to successor list' code into one method exploreNeighbor( Node q, int offsetX, int offsetY).
I've improved style & variable naming somewhat. You should also move towards using getters -- getX(), getY() for example.
exploreNeighbor( q, -1, 0); // left
exploreNeighbor( q, +1, 0); // right
exploreNeighbor( q, 0, -1); // up
exploreNeighbor( q, 0, +1); // down
protected boolean exploreNeighbor (Node parent, int offsetX, int offsetY) {
int x = q.getX() + offsetX;
int y = q.getY() + offsetY;
if (x < 0 || x >= screen.map.width)
return null;
if (y < 0 || y >= screen.map.height)
return false;
int content = screen.map.mapArray[x][y];
if (content == Contents.CANTMOVEONPOSITION ||
content == Contents.MONSTERSTATE) {
return false;
}
// represent Neighbor Position;
//
Node n = new Node(parent, x, y);
n.g = calcG(n);
n.h = calcH(n, (int) this.screen.character.mapPos.x,
(int) this.screen.character.mapPos.y);
// check if Discovered yet;
//
if (discoveredSet.contains( n)) {
// already queued or visited.
return false;
}
// queue it for exploration.
openQueue.add( n);
return true;
}
Good luck..
Related
I am writing an A* path finding algorithm for class. It works perfectly, I am able to click my character and move them to the correct location. However, after running for about 30 seconds of enemies also calling out to the A* algorithm it throws a java.lang.StackOverflowError.
The call directly before this is to the ArrayList library function grow. I can't imagine what I am doing wrong, as I am instantiating the object and am just calling ArrayList.add(Node);
What I am thinking is happening is that there are many ai characters that rely on this functionality, and after many of them calling to it, the program runs out of memory and surpasses the maximum stack size allocated for the program. However, Eclipse is not saying that Java ran out of memory or anything like this, which I would imagine would happen if the program actually ran out of memory.
Is there something that I am doing wrong? Or am I running out of memory? If so, is there a way to increase my allocated memory (I can see that I have tons of RAM left)? Or is there a better way that I could be storing my data to reduce memory loads?
Thanks! Here is the code I have currently written up, please let me know if there is any more information needed.
public class AStar {
class Node
{
public double x, y, g, h;
public Node parent;
public Node(double _x, double _y, double _g, double _h, Node _parent)
{
x = _x;
y = _y;
g = _g;
h = _h;
parent = _parent;
}
}
double start_x, start_y, goal_x, goal_y;
private double heuristic(double s_x, double s_y)
{
double x = Math.abs(s_x - goal_x);
double y = Math.abs(s_y - goal_y);
return x + y;
}
private Node GenerateRelativeNode(Node origin, double dX, double dY, List<Node> closed, List<Node> open)
{
double newX = origin.x + dX;
double newY = origin.y + dY;
Node temp = new Node(newX, newY, origin.g+1, heuristic(newX, newY), origin);
for(int i = 0; i < closed.size(); ++i)
{
if(closed.get(i).x == temp.x && closed.get(i).y == temp.y)
return null;
}
for(int i = 0; i < open.size(); ++i)
{
if(open.get(i).x == temp.x && open.get(i).y == temp.y)
{
return null;
}
}
return temp;
}
private int GetLowestFIndex(List<Node> set)
{
double min = 1000000;
int index = -1;
for(int i = 0; i < set.size(); ++i)
{
double f = set.get(i).h + set.get(i).g;
if(f < min)
{
min = f;
index = i;
}
}
return index;
}
private List<Pair<Double, Double>> PathFromNode(Node _n)
{
List<Pair<Double, Double>> path = new ArrayList<Pair<Double, Double>>();
List<Node> nodes = new ArrayList<Node>();
Node curr = _n;
while(curr.parent != null)
{
nodes.add(curr);
curr = curr.parent;
}
//now need to reverse the list.
for(int i = nodes.size()-1; i >= 0; --i)
{
Pair<Double, Double> pair = pairFromNode(nodes.get(i));
path.add(pair);
}
return path;
}
private Pair<Double, Double> pairFromNode(Node _n)
{
return new Pair<Double, Double>(new Double(_n.x), new Double(_n.y));
}
public static int pathDistance(double start_x, double start_y, double goal_x, double goal_y,
S3PhysicalEntity i_entity, S3 the_game) {
AStar a = new AStar(start_x,start_y,goal_x,goal_y,i_entity,the_game);
List<Pair<Double, Double>> path = a.computePath();
if (path!=null) return path.size();
return -1;
}
public AStar(double sX, double sY, double gX, double gY,
S3PhysicalEntity i_entity, S3 the_game) {
start_x = sX;
start_y = sY;
goal_x = gX;
goal_y = gY;
}
public List<Pair<Double, Double>> computePath() {
double start_h = heuristic(start_x, start_y);
Node start = new Node(start_x, start_y, 0, start_h, null);
List<Node> OpenSet = new ArrayList<>();
List<Node> ClosedSet = new ArrayList<>();
OpenSet.add(start);
while(!OpenSet.isEmpty())
{
int index = GetLowestFIndex(OpenSet);
Node N = OpenSet.get(index);
OpenSet.remove(index);
if(N.x == goal_x && N.y == goal_y)
{
return PathFromNode(N);
}
ClosedSet.add(N);
Node Up = GenerateRelativeNode(N, 0, 1, ClosedSet, OpenSet);
Node Left = GenerateRelativeNode(N, -1, 0, ClosedSet, OpenSet);
Node Right = GenerateRelativeNode(N, 1, 0, ClosedSet, OpenSet);
Node Down = GenerateRelativeNode(N, 0, -1, ClosedSet, OpenSet);
if(Up != null)
OpenSet.add(Up);
if(Left != null)
OpenSet.add(Left);
if(Right != null)
OpenSet.add(Right);
if(Down != null)
OpenSet.add(Down);
}
return null;
}
}
Here is the stack at the time of the StackOverflow
The WPeasant(WTroop).moveTowardsTarget(S3, int, int) line: 202 gets called thousands of times in a row at this point. The code for this function is not in any kind of while loop or for loop or anything.
This could be getting called multiple times however, due to the game object colliding with something, as I have not taken obstructions into account in the pathfinding.
It is hard to say for sure that this is the issue, as I wrote none of this engine, I only have to implement the A*. I can try and include obstacle avoidance and see if this fixes things.
This question already has answers here:
Algorithm for finding all paths in a NxN grid
(11 answers)
Closed 6 years ago.
Imagine a robot sitting on the upper left hand corner of an NxN grid. The robot can only move in two directions: right and down. Imagine certain squares are “off limits”, such that the robot can not step on them. Design an algorithm to get all possible paths for the robot.
Here is the reference implementation I got, I think the implementation is wrong since it only find one path, other than all possible paths (more details, in line 10, the robot only goes down if no valid path in right. But to find all possible paths, the robot should try both right and down)? Want to confirm my understanding is correct.
ArrayList<Point> current_path = new ArrayList<Point>();
public static boolean getPaths(int x, int y) {
Point p = new Point(x, y);
current_path.add(p);
if (0 == x && 0 == y) return true; // current_path
boolean success = false;
if (x >= 1 && is_free(x - 1, y)) { // Try right
success = getPaths(x - 1, y); // Free! Go right
}
if (!success && y >= 1 && is_free(x, y - 1)) { // Try down
success = getPaths(x, y - 1); // Free! Go down
}
if (!success) {
current_path.remove(p); // Wrong way!
}
return success;
}
thanks in advance,
Lin
Here's what you can do:
public static class Point {
int x, y;
public Point (int x, int y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return String.format("[%d, %d]", x, y);
}
}
public static void getPathsRec(int x, int y, Deque<Point> currentPath,
List<List<Point>> paths) {
if (x == 0 && y == 0) {
List<Point> path = new ArrayList<Point>();
for (Point p : currentPath)
path.add(p);
paths.add(path);
//System.out.println(currentPath);
return;
}
if (x > 0 && is_free(x-1, y)) {
currentPath.push(new Point(x-1, y));
getPathsRec(x-1, y, currentPath, paths);
currentPath.pop();
}
if (y > 0 && is_free(x, y-1)) {
currentPath.push(new Point(x, y-1));
getPathsRec(x, y-1, currentPath, paths);
currentPath.pop();
}
}
static int n = 2;
public static List<List<Point>> getPaths() {
List<List<Point>> paths = new ArrayList<List<Point>>();
Deque<Point> d = new ArrayDeque<Point>();
d.push(new Point(n-1, n-1));
getPathsRec(n - 1, n - 1, d, paths);
//System.out.println(paths);
return paths;
}
This is a simple backtracking. The idea is to visit the next state recursively but to make sure that after the call the state goes back to it's previous state(like it was before the call). Here this is done with popping the element from the Deque.
Notice that for simplicity you could introduce new class Path which would be something like:
class Path {
List<Point> points;
}
to make the code more readable. Then getPaths() would return List<Path> which is much nicer.
Also consider redefining getPathsRec to have the signature getPathsRec(Point p, Deque<Point>, List<Path> ), that is having one argument Point instead of having x, y. Having x, y seems redundant considering the fact that you've defined class Point. Again this would make it look better.
Your solution is wrong because once the it reach (0 == x && y==0), the success value will always set to true. Hence, it wouldn't go into later if
Below is the sample answer for your problem. It uses backtracking algorithm:
public class test {
static int n = 3; //substitute your n value here
static ArrayList<Point> current_path = new ArrayList<Point>();
static boolean[][] blockedCell = new boolean[n][n];
public static void FindAllWay(int x, int y)
{
if (x <0 || y < 0) return;
Point p = new Point(x, y);
current_path.add(p);
if (0 == x && 0 == y){
System.out.println(current_path.toString());
current_path.remove(current_path.size()-1);
return;
}
if ((x > 0) && !blockedCell[x-1][y]) //go right
{
blockedCell[x-1][y] = true;
FindAllWay(x-1, y);
blockedCell[x-1][y] = false;
}
if ((y > 0) &&!blockedCell[x][y-1]) // go down
{
blockedCell[x][y-1] = true;
FindAllWay(x, y-1);
blockedCell[x][y-1] = false;
}
current_path.remove(current_path.size()-1);
}
public static void main(String[] args)
{
FindAllWay(n-1,n-1);
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm trying to implement the A* algorithm in Java. I followed this tutorial,in particular, this pseudocode: http://theory.stanford.edu/~amitp/GameProgramming/ImplementationNotes.html
The problem is my code doesn't work. It goes into an infinite loop. I really don't know why this happens... I suspect that the problem are in F = G + H function implemented in Graph constructors. I suspect I am not calculate the neighbor F correclty.
Here's my code:
List<Graph> open;
List<Graph> close;
private void createRouteAStar(Unit u)
{
open = new ArrayList<Graph>();
close = new ArrayList<Graph>();
u.ai_route_endX = 11;
u.ai_route_endY = 5;
List<Graph> neigh;
int index;
int i;
boolean finish = false;
Graph current;
int cost;
Graph start = new Graph(u.xMap, u.yMap, 0, ManhattanDistance(u.xMap, u.yMap, u.ai_route_endX, u.ai_route_endY));
open.add(start);
current = start;
while(!finish)
{
index = findLowerF();
current = new Graph(open, index);
System.out.println(current.x);
System.out.println(current.y);
if (current.x == u.ai_route_endX && current.y == u.ai_route_endY)
{
finish = true;
}
else
{
close.add(current);
open.remove(open.indexOf(current)); //EDITED LATER
neigh = current.getNeighbors();
for (i = 0; i < neigh.size(); i++)
{
cost = current.g + ManhattanDistance(current.x, current.y, neigh.get(i).x, neigh.get(i).y);
if (open.contains(neigh.get(i)) && cost < neigh.get(i).g)
{
open.remove(open.indexOf(neigh));
}
else if (close.contains(neigh.get(i)) && cost < neigh.get(i).g)
{
close.remove(close.indexOf(neigh));
}
else if (!open.contains(neigh.get(i)) && !close.contains(neigh.get(i)))
{
neigh.get(i).g = cost;
neigh.get(i).f = cost + ManhattanDistance(neigh.get(i).x, neigh.get(i).y, u.ai_route_endX, u.ai_route_endY);
neigh.get(i).setParent(current);
open.add(neigh.get(i));
}
}
}
}
System.out.println("step");
for (i=0; i < close.size(); i++)
{
if (close.get(i).parent != null)
{
System.out.println(i);
System.out.println(close.get(i).parent.x);
System.out.println(close.get(i).parent.y);
}
}
}
private int findLowerF()
{
int i;
int min = 10000;
int minIndex = -1;
for (i=0; i < open.size(); i++)
{
if (open.get(i).f < min)
{
min = open.get(i).f;
minIndex = i;
System.out.println("min");
System.out.println(min);
}
}
return minIndex;
}
private int ManhattanDistance(int ax, int ay, int bx, int by)
{
return Math.abs(ax-bx) + Math.abs(ay-by);
}
And, as I've said. I suspect that the Graph class has the main problem. However I've not been able to detect and fix it.
public class Graph {
int x, y;
int f,g,h;
Graph parent;
public Graph(int x, int y, int g, int h)
{
this.x = x;
this.y = y;
this.g = g;
this.h = h;
this.f = g + h;
}
public Graph(List<Graph> list, int index)
{
this.x = list.get(index).x;
this.y = list.get(index).y;
this.g = list.get(index).g;
this.h = list.get(index).h;
this.f = list.get(index).f;
this.parent = list.get(index).parent;
}
public Graph(Graph gp)
{
this.x = gp.x;
this.y = gp.y;
this.g = gp.g;
this.h = gp.h;
this.f = gp.f;
}
public Graph(Graph gp, Graph parent)
{
this.x = gp.x;
this.y = gp.y;
this.g = gp.g;
this.h = gp.h;
this.f = g + h;
this.parent = parent;
}
public List<Graph> getNeighbors()
{
List<Graph> aux = new ArrayList<Graph>();
aux.add(new Graph(x+1, y, g,h));
aux.add(new Graph(x-1, y, g,h));
aux.add(new Graph(x, y+1, g,h));
aux.add(new Graph(x, y-1, g,h));
return aux;
}
public void setParent(Graph g)
{
parent = g;
}
//Added later. Generated by Eclipse
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Graph other = (Graph) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
Little Edit:
Using the System.out and the Debugger I discovered that the program ALWAYS is check the same "current" graph, (15,8) which is the (u.xMap, u.yMap) position. Looks like it keeps forever in the first step.
You don't remove your start node from open list (i mean, that after each cycle in while you need to remove node that was just eximining).
Also, some hints:
there is priority queue in java. So, you don't need to do it on list by yourself
int f,g,h; try to rename variables. it is impossible to understand their meaning in the code.
then you create neighbors, check that they are in the area (i.e: x,y>0 and less that maxX,maxY)
I am working on a method to recursively solve made up of cells.
The method just quite isn't working. Any suggestions would be appreciated.
Parameters: srow = starting x value. scol = staring y value erow = end
x value. ecol = end y value. L = Linked List of solved path points
Code:
private InputGraphicMaze2 maze;
private int R, C;
//code added by me
private String[] [] cell; //an array to keep track of cells that are proven dead ends.
public YourMazeWithPath2()
{
// an R rows x C columns maze
maze = new InputGraphicMaze2();
R=maze.Rows(); C=maze.Cols();
//code added by me
cell = new String[R+2][C+2];
for (int i=0; i<R+2; i++) {
for (int k=0; k<C+2; k++) {
cell[i][k] = "no";
}
}
// Path holds the cells of the path
LinkedList<Point> Path = new LinkedList<Point>();
// Create the path
CreatePath(maze, 1, 1, R, C, Path);
// show the path in the maze
maze.showPath(Path);
}
private void setDead(int x, int y) {
cell[x][y] = "dead";
}
private void setVisited(int x, int y) {
cell[x][y] = "visited";
}
public boolean CreatePath(InputGraphicMaze2 maze,
int srow, int scol, int erow, int ecol, LinkedList<Point> L)
{
int x = srow;
int y = scol;
Point p = new Point(x, y);
if ((x<1) || (y<1) || (x>R) || (y>C)) {
return false; //cell is out of bounds
}
else if ((x==R) && (y==C)) {
return true; // cell is the exit cell
}
else {
if ((maze.can_go(x, y, 'U')) && (x!=1) && (!cell[x-1][y].equals("dead")) && (!cell[x-1][y].equals("visited"))) {
L.addLast(p);
setVisited(x,y);
CreatePath(maze, x-1, y, R, C, L);
return false;
}
else if ((maze.can_go(x, y, 'R')) && (y!=C) && (!cell[x][y+1].equals("dead")) && (!cell[x][y+1].equals("visited"))) {
L.addLast(p);
setVisited(x, y);
CreatePath(maze, x, y+1, R, C, L);
return false;
}
else if ((maze.can_go(x, y, 'D')) && (x!=R) && (!cell[x+1][y].equals("dead")) && (!cell[x+1][y].equals("visited"))) {
L.addLast(p);
setVisited(x, y);
CreatePath(maze, x+1, y, R, C, L);
return false;
}
else if ((maze.can_go(x, y, 'L')) && (y!=1) && (!cell[x][y-1].equals("dead")) && (!cell[x][y-1].equals("visited"))) {
L.addLast(p);
setVisited(x, y);
CreatePath(maze, x, y-1, R, C, L);
return false;
}
else {
if ((maze.can_go(x, y, 'U')) && (x!=1) && (cell[x][y-1].equals("visited"))) {
setDead(x, y);
if (L.contains(p))
L.remove(p);
CreatePath(maze, x-1, y, R, C, L);
return false;
}
else if ((maze.can_go(x, y, 'R')) && (y!=C) && (cell[x][y+1].equals("visited"))) {
setDead(x, y);
if (L.contains(p))
L.remove(p);
CreatePath(maze, x, y+1, R, C, L);
return false;
}
else if ((maze.can_go(x, y, 'D')) && (x!=R) && (cell[x+1][y].equals("visited"))) {
setDead(x, y);
if (L.contains(p))
L.remove(p);
CreatePath(maze, x+1, y, R, C, L);
return false;
}
else if ((maze.can_go(x, y, 'D')) && (y!=1) && (cell[x][y-1].equals("visited"))) {
setDead(x, y);
if (L.contains(p))
L.remove(p);
CreatePath(maze, x, y-1, R, C, L);
return false;
}
else {
return false;
}
}
}
}
From Another similar thread, just for seeing the problem in a less verbose language, take a look at
this tiny JS recursive maze solver made by user #Sergey Rudenko
var map = [
[1,1,0,0,0,0,0,0],
[0,1,1,0,0,0,0,0],
[1,1,1,0,0,0,0,0],
[1,0,0,1,1,1,1,1],
[1,1,0,0,1,0,0,1],
[0,1,1,0,1,0,0,1],
[1,1,1,0,1,0,0,1],
[1,0,0,0,1,1,1,1]
]
var goalx = 7;
var goaly = 7;
function findpath(x,y){
// illegal move check
if (x < 0 || x > (map[0].length -1) || y < 0 || y > (map.length - 1)) return false; //if it is outside of map
if (map[y][x]==0) return false; //it is not open
// end move check
if (x== goalx && y== goaly){
console.log('Reached goal at: ' + x + ':' + y);
return true; // if it is the goal (exit point)
}
if(map[y][x] == 9 || map[y][x] == 8)
return false;
console.log('Im here at: ' + x + ':' + y);
map[y][x]=9; //here marking x,y position as part of solution path outlined by "9"
if(findpath(x+1,y))
return true;
if(findpath(x,y+1))
return true;
if(findpath(x,y-1))
return true;
if(findpath(x-1,y))
return true;
return false;
};
findpath(0, 0);
JSfiddle
Yep. Its tiny, simplistic, naive and lacking but heck, its recursive and it works!
Besides, you see clearly common parts to many maze traversing algorithm.
For a more serious reading, this page has excellent in-depth-but-not-scientific-paper tutorials about many game related algorithms.
There are some pertinent questions to answer when shopping for an algorithm:
Need any solution?
Need every solution?
Need the fastest?
Whats the topography of the maze? A grid? A graph?
Want to implement movement cost in the future?
Want to implement heuristics to choose best route?
Finally, if you didn't come across it yet, check a* algorithm. Very popular.
Have fun!
This is a basic graph-traversal problem. I suggest you use dfs as opposed to bfs. Pretty much any textbook on algorithms and datastructure will have the implementation.
You simply have to tweak the recursive part to stop searching once you have reached the goal. On the other hand, if you are looking for all paths to the goal, just do all-to-all path and then go from there. For hints, you can look up Bellman–Ford or Dijkstra's algorithm (http://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm). Again, any good textbook with a chapter on graphs.
I used Fortune's Algorithm to find the Voronoi diagram of a set of points.
What I get back is a list of line segments, but I need to know which segments form closed polygons, and put them together in an object hashed by the original point they surround.
What might be the fastest way to find these??
Should I save some crucial information from from the algorithm? If so what?
Here is my implementation of fortune's algorithm in Java ported from a C++ implementation here
class Voronoi {
// The set of points that control the centers of the cells
private LinkedList<Point> pts;
// A list of line segments that defines where the cells are divided
private LinkedList<Edge> output;
// The sites that have not yet been processed, in acending order of X coordinate
private PriorityQueue sites;
// Possible upcoming cirlce events in acending order of X coordinate
private PriorityQueue events;
// The root of the binary search tree of the parabolic wave front
private Arc root;
void runFortune(LinkedList pts) {
sites.clear();
events.clear();
output.clear();
root = null;
Point p;
ListIterator i = pts.listIterator(0);
while (i.hasNext()) {
sites.offer(i.next());
}
// Process the queues; select the top element with smaller x coordinate.
while (sites.size() > 0) {
if ((events.size() > 0) && ((((CircleEvent) events.peek()).xpos) <= (((Point) sites.peek()).x))) {
processCircleEvent((CircleEvent) events.poll());
} else {
//process a site event by adding a curve to the parabolic front
frontInsert((Point) sites.poll());
}
}
// After all points are processed, do the remaining circle events.
while (events.size() > 0) {
processCircleEvent((CircleEvent) events.poll());
}
// Clean up dangling edges.
finishEdges();
}
private void processCircleEvent(CircleEvent event) {
if (event.valid) {
//start a new edge
Edge edgy = new Edge(event.p);
// Remove the associated arc from the front.
Arc parc = event.a;
if (parc.prev != null) {
parc.prev.next = parc.next;
parc.prev.edge1 = edgy;
}
if (parc.next != null) {
parc.next.prev = parc.prev;
parc.next.edge0 = edgy;
}
// Finish the edges before and after this arc.
if (parc.edge0 != null) {
parc.edge0.finish(event.p);
}
if (parc.edge1 != null) {
parc.edge1.finish(event.p);
}
// Recheck circle events on either side of p:
if (parc.prev != null) {
checkCircleEvent(parc.prev, event.xpos);
}
if (parc.next != null) {
checkCircleEvent(parc.next, event.xpos);
}
}
}
void frontInsert(Point focus) {
if (root == null) {
root = new Arc(focus);
return;
}
Arc parc = root;
while (parc != null) {
CircleResultPack rez = intersect(focus, parc);
if (rez.valid) {
// New parabola intersects parc. If necessary, duplicate parc.
if (parc.next != null) {
CircleResultPack rezz = intersect(focus, parc.next);
if (!rezz.valid){
Arc bla = new Arc(parc.focus);
bla.prev = parc;
bla.next = parc.next;
parc.next.prev = bla;
parc.next = bla;
}
} else {
parc.next = new Arc(parc.focus);
parc.next.prev = parc;
}
parc.next.edge1 = parc.edge1;
// Add new arc between parc and parc.next.
Arc bla = new Arc(focus);
bla.prev = parc;
bla.next = parc.next;
parc.next.prev = bla;
parc.next = bla;
parc = parc.next; // Now parc points to the new arc.
// Add new half-edges connected to parc's endpoints.
parc.edge0 = new Edge(rez.center);
parc.prev.edge1 = parc.edge0;
parc.edge1 = new Edge(rez.center);
parc.next.edge0 = parc.edge1;
// Check for new circle events around the new arc:
checkCircleEvent(parc, focus.x);
checkCircleEvent(parc.prev, focus.x);
checkCircleEvent(parc.next, focus.x);
return;
}
//proceed to next arc
parc = parc.next;
}
// Special case: If p never intersects an arc, append it to the list.
parc = root;
while (parc.next != null) {
parc = parc.next; // Find the last node.
}
parc.next = new Arc(focus);
parc.next.prev = parc;
Point start = new Point(0, (parc.next.focus.y + parc.focus.y) / 2);
parc.next.edge0 = new Edge(start);
parc.edge1 = parc.next.edge0;
}
void checkCircleEvent(Arc parc, double xpos) {
// Invalidate any old event.
if ((parc.event != null) && (parc.event.xpos != xpos)) {
parc.event.valid = false;
}
parc.event = null;
if ((parc.prev == null) || (parc.next == null)) {
return;
}
CircleResultPack result = circle(parc.prev.focus, parc.focus, parc.next.focus);
if (result.valid && result.rightmostX > xpos) {
// Create new event.
parc.event = new CircleEvent(result.rightmostX, result.center, parc);
events.offer(parc.event);
}
}
// Find the rightmost point on the circle through a,b,c.
CircleResultPack circle(Point a, Point b, Point c) {
CircleResultPack result = new CircleResultPack();
// Check that bc is a "right turn" from ab.
if ((b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y) > 0) {
result.valid = false;
return result;
}
// Algorithm from O'Rourke 2ed p. 189.
double A = b.x - a.x;
double B = b.y - a.y;
double C = c.x - a.x;
double D = c.y - a.y;
double E = A * (a.x + b.x) + B * (a.y + b.y);
double F = C * (a.x + c.x) + D * (a.y + c.y);
double G = 2 * (A * (c.y - b.y) - B * (c.x - b.x));
if (G == 0) { // Points are co-linear.
result.valid = false;
return result;
}
// centerpoint of the circle.
Point o = new Point((D * E - B * F) / G, (A * F - C * E) / G);
result.center = o;
// o.x plus radius equals max x coordinate.
result.rightmostX = o.x + Math.sqrt(Math.pow(a.x - o.x, 2.0) + Math.pow(a.y - o.y, 2.0));
result.valid = true;
return result;
}
// Will a new parabola at point p intersect with arc i?
CircleResultPack intersect(Point p, Arc i) {
CircleResultPack res = new CircleResultPack();
res.valid = false;
if (i.focus.x == p.x) {
return res;
}
double a = 0.0;
double b = 0.0;
if (i.prev != null) // Get the intersection of i->prev, i.
{
a = intersection(i.prev.focus, i.focus, p.x).y;
}
if (i.next != null) // Get the intersection of i->next, i.
{
b = intersection(i.focus, i.next.focus, p.x).y;
}
if ((i.prev == null || a <= p.y) && (i.next == null || p.y <= b)) {
res.center = new Point(0, p.y);
// Plug it back into the parabola equation to get the x coordinate
res.center.x = (i.focus.x * i.focus.x + (i.focus.y - res.center.y) * (i.focus.y - res.center.y) - p.x * p.x) / (2 * i.focus.x - 2 * p.x);
res.valid = true;
return res;
}
return res;
}
// Where do two parabolas intersect?
Point intersection(Point p0, Point p1, double l) {
Point res = new Point(0, 0);
Point p = p0;
if (p0.x == p1.x) {
res.y = (p0.y + p1.y) / 2;
} else if (p1.x == l) {
res.y = p1.y;
} else if (p0.x == l) {
res.y = p0.y;
p = p1;
} else {
// Use the quadratic formula.
double z0 = 2 * (p0.x - l);
double z1 = 2 * (p1.x - l);
double a = 1 / z0 - 1 / z1;
double b = -2 * (p0.y / z0 - p1.y / z1);
double c = (p0.y * p0.y + p0.x * p0.x - l * l) / z0 - (p1.y * p1.y + p1.x * p1.x - l * l) / z1;
res.y = (-b - Math.sqrt((b * b - 4 * a * c))) / (2 * a);
}
// Plug back into one of the parabola equations.
res.x = (p.x * p.x + (p.y - res.y) * (p.y - res.y) - l * l) / (2 * p.x - 2 * l);
return res;
}
void finishEdges() {
// Advance the sweep line so no parabolas can cross the bounding box.
double l = gfx.width * 2 + gfx.height;
// Extend each remaining segment to the new parabola intersections.
Arc i = root;
while (i != null) {
if (i.edge1 != null) {
i.edge1.finish(intersection(i.focus, i.next.focus, l * 2));
}
i = i.next;
}
}
class Point implements Comparable<Point> {
public double x, y;
//public Point goal;
public Point(double X, double Y) {
x = X;
y = Y;
}
public int compareTo(Point foo) {
return ((Double) this.x).compareTo((Double) foo.x);
}
}
class CircleEvent implements Comparable<CircleEvent> {
public double xpos;
public Point p;
public Arc a;
public boolean valid;
public CircleEvent(double X, Point P, Arc A) {
xpos = X;
a = A;
p = P;
valid = true;
}
public int compareTo(CircleEvent foo) {
return ((Double) this.xpos).compareTo((Double) foo.xpos);
}
}
class Edge {
public Point start, end;
public boolean done;
public Edge(Point p) {
start = p;
end = new Point(0, 0);
done = false;
output.add(this);
}
public void finish(Point p) {
if (done) {
return;
}
end = p;
done = true;
}
}
class Arc {
//parabolic arc is the set of points eqadistant from a focus point and the beach line
public Point focus;
//these object exsit in a linked list
public Arc next, prev;
//
public CircleEvent event;
//
public Edge edge0, edge1;
public Arc(Point p) {
focus = p;
next = null;
prev = null;
event = null;
edge0 = null;
edge1 = null;
}
}
class CircleResultPack {
// stupid Java doesnt let me return multiple variables without doing this
public boolean valid;
public Point center;
public double rightmostX;
}
}
(I know it wont compile, the data structures need to be initialized, and its missing imports)
What I want is this:
LinkedList<Poly> polys;
//contains all polygons created by Voronoi edges
class Poly {
//defines a single polygon
public Point locus;
public LinkedList<Points> verts;
}
The most immediate brute force way I can think of to do this is to create an undirected graph of the points in the diagram (the endpoints of the edges), with a single entry for each point, and a single connection for each edge between a point (no duplicates) then go find all the loops in this graph, then for each set of loops that share 3 or more points, throw away everything but the shortest loop. However this would be way too slow.
The Voronoi diagram's dual is the Delaunay triangulation. That means each vertex on the Voroni diagram is connected to three edges - meaning each vertex belongs to three regions.
My algorithm to use this would be:
for each vertex in Voronoi Diagram
for each segment next to this point
"walk around the perimeter" (just keep going counter-clockwise)
until you get back to the starting vertex
That should be O(N) as there are only 3 segments for each vertex. You also have to do some bookkeeping to make sure you don't do the same region twice (a simple way is to just keep a bool for each outgoing edge, and as you walk, mark it off), and keeping in mind the point at infinity, but the idea should be enough.