Problems with with A* algorithm [closed] - java

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)

Related

Printing and comparing array data in java

I recently started learning Java and I'm having some trouble understanding how to make arrays to work the way I want them to.
Here I have an assignment of creating a polygon class with different methods inside.
Basically the class represents a convex polygon in a plane.
The array receives user input that consists of x and y coordinates and places them inside. (max number of vertices is 10).
There are some functions that I have no idea how to do and I would really appreciate some help with.
Point Class - which is used to get coordinates
public class Point {
private double _x;
private double _y;
public Point() {
this._x = 0.0D;
this._y = 0.0D;
}
public Point(double x, double y) {
this._x = x;
this._y = y;
}
public Point(Point other) {
this._x = other._x;
this._y = other._y;
}
public double getX() {
return this._x;
}
public double getY() {
return this._y;
}
public void setX(double x) {
if (x >= 0.0D)
this._x = x;
}
public void setY(double y) {
if (y >= 0.0D)
this._y = y;
}
public boolean isAbove(Point other) {
return (this._y > other._y);
}
public boolean isUnder(Point other) {
return other.isAbove(this);
}
public boolean isLeft(Point other) {
return (this._x < other._x);
}
public boolean isRight(Point other) {
return other.isLeft(this);
}
public double distance(Point other) {
double distance = Math.sqrt(Math.pow(this._x - other._x, 2.0D) + Math.pow(this._y - other._y, 2.0D));
return distance;
}
public void move(double dx, double dy) {
double x = this._x + dx;
double y = this._y + dy;
if (x >= 0.0D && y >= 0.0D) {
this._x = x;
this._y = y;
}
}
public boolean equals(Point other) {
return (this._x == other._x && this._y == other._y);
}
public String toString() {
return "(" + this._x + "," + this._y + ")";
}
}
Polygon Class - main class im working on
/**
* Write a description of class Polygon here.
*
* #author [REDACTED]
* #version (Ver 1.0)
*/
public class Polygon {
private Point[] _vertices;
private int _noOfVertices;
public Polygon() {
_vertices = (Point[]) new Point[10];
_noOfVertices = 0;
}
public Polygon(Point[] arr) {
_vertices = (Point[]) new Point[10];
_noOfVertices = 0;
if (arr.length > 10) {
return;
}
// for (Point P : arr)
for (int i = 0; i < arr.length; i++) {
if (arr[i] != null) {
_vertices[i] = arr[i];
_noOfVertices++;
}
}
}
public boolean addVertex(double x, double y) {
if (_noOfVertices >= 10)
return false;
Point p = new Point(x, y);
_vertices[_noOfVertices] = p;
_noOfVertices++;
return true;
}
public Point highestVertex() {
for (int i = 0; i < _noOfVertices; i++) {
}
}
public String toString() {
}
public double calcPerimeter() {
for (int i = 0; i < arr.length; i++) {
}
}
public double caclArea() {
Point ppp = _vertices[zzz]
}
public boolean isBigger(Polygon other) {
}
public int findVertex(Point p) {
for (int i = 0; i < _noOfVertices; i++) {
if (p.equals(_vertices[i])) {
return i;
}
}
return -1;
}
public Point getNextVertex(Point p) {
for (int i = 0; i < _noOfVertices; i++) {
if (p.equals(_vertices[i])) {
if (i == _noOfVertices - 1) {
return new Point(_vertices[0]);
}
return new Point(_vertices[i + 1]);
}
}
return null;
}
public Polygon getBoundingBox() {
}
}
I have no idea how to do these functions:
Line 44: public Point highestVertex() {} - returns a copy of the highest point in the polygon. If there is more than one vertice at the same Y - the method will return the first one it encountered (with the said Y) If there are no vertices aka the array is empty it will return null.
Line 52: public String toString() {} - method that returns a string of points representing the polygon. The string should be in the following format:
The polygon has 5 vertices:
((2.0,1.0),(5.0,0.0),(7.0,5.0),(4.0,6.0),(1.0,4,0))
If there are no vertices the method will return a string in the following format:
The polygon has 0 vertices.
English is not my first language so I apologize for any grammar mistakes in advance.
First, it's not really the best to ask homework questions here, this is a concept that you should learn.
In highestVertex(), they outline the 3 cases for you:
1st case: If point-y is equal to another point-y, return the first vertex that has point-y.
2nd case: if arr has no elements return null.
3rd case: in loop, check each element's y value in the array and compare it to the biggest y so far.
Use this line before your loop:
int max = Integer.MIN_VALUE;
Inside loop:
if (arr[i] > max) max = arr[i]
For toString(), again loop throughout the array, and add each point to a tracker string that you will return.
String str = "";
loop
str += arr[i].toString() + ",";
This works except you need to loop until arr's second to last element, as you will have an extraneous comma after the last point.

Java StackOverflowException when calling java.util.ArrayList.grow

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.

Java populating a 3D linked list with recursion

I'm getting a stack overflow while trying to populate my 3D linked list. I don't understand why it's not stopping at the specified bounds, it just runs forever. It's probably a simple error, i just don't understand.
EDIT: Okay I have now updated the code and removed that silly mistake, however it's still not operating exactly as intended. It does seem to be generating the 10x10x10 list, however its running infinitely. Initialized with (10, 10, 10), it should create 10000 objects and stop. I'm just trying to create a list to represent a 3d coordinate plane and each integer coordinate is one node, accessible by direction pointer north, south, east, west, up, or down.
Any help appreciated
public class Main {
public static void main(String[] args) {
NodeController3D con = new NodeController3D(6,6, 6);
}
}
public class Node3D {
// public Node3D(Node3D... nodes) {
// if (nodes.length != 5) {
// throw new RuntimeException();
// }
// this.nodes = nodes;
// }
public Node3D[] nodes;
public int x, y, z;
public Node3D north() {
return nodes[0];
}
public Node3D south() {
return nodes[1];
}
public Node3D east() {
return nodes[2];
}
public Node3D west() {
return nodes[3];
}
public Node3D up() {
return nodes[4];
}
public Node3D down() {
return nodes[5];
}
}
public class NodeController3D {
public NodeController3D(int length, int width, int height) {
HEAD = new Node3D();
pnc(HEAD, length, width, height);
}
private void pnc(Node3D node, int xMax, int yMax, int zMax) {
if(node.nodes == null) {
node.nodes = new Node3D[5];
}
if (node.x < xMax) {
Node3D newNode = node.nodes[2] = new Node3D();
newNode.x = node.x + 1;
newNode.y = node.y;
newNode.z = node.z;
System.out.println(newNode.x + ", " + newNode.y + ", " + newNode.z);
pnc(newNode, xMax, yMax, zMax);
}
if (node.y < yMax) {
Node3D newNode = node.nodes[0] = new Node3D();
newNode.x = node.x;
newNode.y = node.y + 1;
newNode.z = node.z;
pnc(newNode, xMax, yMax, zMax);
}
if (node.z < zMax) {
Node3D newNode = node.nodes[4] = new Node3D();
newNode.x = node.x;
newNode.y = node.y;
newNode.z = node.z + 1;
pnc(newNode, xMax, yMax, zMax);
}
}
// public NodeController3D(int radius) {
//
// }
public final Node3D HEAD;
}
EDIT: Okay I have now updated the code and removed that silly mistake, however it's still not operating exactly as intended. It does seem to be generating the 10x10x10 list, however its running infinitely. Initialized with (10, 10, 10), it should create 10000 objects and stop. I'm just trying to create a list to represent a 3d coordinate plane and each integer coordinate is one node, accessible by direction pointer.
You are running into an infinite recursion.
So what is happening.
You are creating a new Array.
if(node.nodes == null) {
node.nodes = new Node3D[5];
}
You go on by using a Node3D as a newNode variable. This happens because node.x<xMax will be true. -> Node3D newNode = node.nodes[2] = new Node3D();.
You recursivly call pnc now, with this newNode.
So what happens now, node.y<yMax will be true .
Now you reassign the newNode. Node3D newNode = node.nodes[0] = new Node3D();.
and call pnc recursivly again. But you are running into a problem now. since it is a new Node3D your node.x<xMax will be true again and these two steps are happening again and ininite until you are getting your mentioned error.
To fix this error you might want to copy node.x and node.y into your newly created variable.
By changing the assignment you could jump out of the infinite recursion.
if (node.x < xMax) {
if (node.nodes[2] == null) {
node.nodes[2] = new Node3D();
}
Node3D newNode = node.nodes[2];
newNode.x = node.x + 1;
newNode.y = node.y;
newNode.z = node.z;
pnc(newNode, xMax, yMax, zMax);
}
if (node.y < yMax) {
if (node.nodes[0] == null) {
node.nodes[0] = new Node3D();
}
Node3D newNode = node.nodes[0];
newNode.x = node.x;
newNode.y = node.y + 1;
newNode.z = node.z;
pnc(newNode, xMax, yMax, zMax);
}
if (node.z < zMax) {
if (node.nodes[4] == null) {
node.nodes[4] = new Node3D();
}
Node3D newNode = node.nodes[4];
newNode.x = node.x;
newNode.y = node.y;
newNode.z = node.z + 1;
pnc(newNode, xMax, yMax, zMax);
}
But since i donĀ“t know what you are trying to achive with this specific elements at these specifics index in your array this might be a wrong solution for you.
Whenever you create a new Node3D, the variables x, y and z are not initialized, therefore they will evaluate to 0 if accessed.
In the pnc method, there will always be cases where either x < xMax, y < yMax or z < zMax since those are all set to 1.
A good practice is to make variables private and final where possible:
class Node3D {
private final Node3D[] nodes;
private final int x;
private final int y;
private final int z;
public Node3D(int x, int y, int z) {
this.nodes = new Node3D[6];
this.x = x;
this.y = y;
this.z = z;
}
}
This will prevent these kinds of errors in the future. You can create getter methods for the variables. If you really need to reassign the values for x, y or z, you could instead create a new Node3D so that the object can remain immutable.
You were navigating to nodes in the 3D grid in multiple ways. For example, you went to (1,1,0) both from (1,0,0) and (0,1,0), creating duplicates for the same coordinate. This way, you create a number of nodes equal to the total sum of cube paths for each node.
An other approach is to populate a cube of nodes, and give each node a reference to the cube that they are in. Then when you need to go North, you just let the cube return the right node, using the coordinates of the current node. You could use Apache's MultiKeyMap as a grid:
class Node3D {
private static int instances = 0;
public final int x;
public final int y;
public final int z;
public final int number;
public final MultiKeyMap<Integer, Node3D> gridMap;
public Node3D(MultiKeyMap<Integer, Node3D> gridMap, int x, int y, int z) {
this.gridMap = gridMap;
this.x = x;
this.y = y;
this.z = z;
this.number = instances++;
}
//Add/alter these methods according to your orientation
//Returns null if no value is present, you might want to handle this
public Node3D getNorthNode() {
return gridMap.get(this.x + 1, this.y, this.z);
}
//Other getters omitted
#Override
public String toString() {
return "Node3D#" + number + "[" + x + ", " + y + ", " + z + "]";
}
}
Now initialization can be done as follows:
MultiKeyMap<Integer, Node3D> gridMap = new MultiKeyMap<>();
for(int x = 0; x < xMax; x++) {
for(int y = 0; y < yMax; y++) {
for(int z = 0; z < zMax; z++) {
gridMap.put(x, y, z, new Node3D(gridMap, x, y, z));
}
}
}
System.out.println(gridMap.get(4, 4, 4).getNorthNode());

A* catch if unpossible to reach a point

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..

How to make my HashMap work as expected?

Suppose one has a simple class:
public class Point implements Comparable<Point> {
public int compareTo(Point p) {
if ((p.x == this.x) && (p.y == this.y)) {
return 0;
} else if (((p.x == this.x) && (p.y > this.y)) || p.x > this.x) {
return 1;
} else {
return -1;
}
}
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
And a HashMap from Point to something, let's say Cell:
cellMap = new HashMap<Point, Cell>();
Then one fills in cellMap as follows:
for (int x = -width; x <= width; x++) {
for (int y = -height; y <= height; y++) {
final Point pt = new Point(x,y);
cellMap.put(pt, new Cell());
}
}
}
And then one does something like (trivial) this:
for (Point pt : cellMap.keySet()) {
System.out.println(cellMap.containsKey(pt));
Point p = new Point(pt.getX(), pt.getY());
System.out.println(cellMap.containsKey(p));
}
And gets true and false in, respectively, first and second cases. What is going on? Is this map comparing hashes instead of values? How to make the example return true in both cases?
Since you are using HashMap, not TreeMap, you need to override hashCode and equals, not compareTo, in your Point class:
#Override
public int hashCode() {
return 31*x + y;
}
#Override
public bool equals(Object other) {
if (other == null) return false;
if (other == this) return true;
if (!(other instanceof Point)) return false;
Point p = (Point)other;
return x == p.x && y == p.y;
}

Categories