I am getting a NullPointerException on an image that I have loaded. When I render the image using a JFrame everything works, however, my goal is to load each pixel into an ArrayList that contains the RBG color of that pixel. Whe nI try to use getRGB(x,y) I receive a NullPoint Exception. I have marked in the comments on the code where the error occurs. I will load my code, thank you for your time and help!
public static void populateMapNode(BufferedImage image)
{
int width = image.getWidth();
int height = image.getHeight();
int pixel;
int i = 0, j= 0;
System.out.println("width = " + width);
System.out.println("height = " + height);
pixel = image.getRGB(j, i); //error occurs here
System.out.println("pixel = " + pixel);
MapNodes.add(new MapNode(new ArrayList<MapNode>(), new MapNode(), j, i, pixel, 0, 0, 0, 0, null));
System.out.println("do i get here?");
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
pixel = image.getRGB(j, i);
MapNodes.add(new MapNode(MapNode.neighbors, MapNode.neighbors.get(j-1), j, i, pixel, 0, 0, 0, 0, null));
}
}
}
public static void loadMap() //if I just go to the JFrame the picture loads.
{
//Util.loadImage("AntWorld.png", null);
BufferedImage antMap = Util.loadImage("AntWorld.png", new Container());
populateMapNode(antMap);
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new JLabel(new ImageIcon(antMap)));
frame.pack();
frame.setVisible(true);
//System.out.println(Util.manhattanDistance(MapNode.x, MapNode.y, MapNode.parent.x, MapNode.parent.y));
}
public static void main(String[] args)
{
loadMap();
}
/* helper class Util for loadImage */
import java.awt.Container;
import java.awt.MediaTracker;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
public class Util
{
/**
* Loads a image file with the given path into a new bufferedImage. Blocks
* until the image has finished loading. widit is the component on which the
* images will eventually be drawn.
*
* #return A buffered image containing the loaded image.
*/
public static BufferedImage loadImage(String imagePath, Container widgit)
{
if (imagePath == null) return null;
if (widgit == null)
{
widgit = new Container();
}
// Create a MediaTracker instance, to montior loading of images
MediaTracker tracker = new MediaTracker(widgit);
BufferedImage loadedImage = null;
URL fileURL = null;
try
{ // System.out.println("imagePath="+imagePath);
imagePath = "resources/" + imagePath;
fileURL = new URL("file:" + imagePath);
loadedImage = ImageIO.read(fileURL);
// Register it with media tracker
tracker.addImage(loadedImage, 1);
tracker.waitForAll();
}
catch (Exception e)
{
System.out.println("Cannot Open image: " + imagePath);
e.printStackTrace();
System.exit(0);
}
return loadedImage;
}
/**************** Stack Trace ***************************/
Exception in thread "main" java.lang.NullPointerException
at custom.MapNode.<init>(MapNode.java:32)
at custom.Demo.populateMapNode(Demo.java:56)
at custom.Demo.loadMap(Demo.java:72)
at custom.Demo.main(Demo.java:91)
/***************MapNode *********************************/
package custom;
import java.util.*;
import java.io.*;
public class MapNode implements Comparable <MapNode>
{
public static List<MapNode> neighbors = new ArrayList<MapNode>(); //Used for creating a path for an ant to follow
public static MapNode parent = null;
public static int x, y; //x and y coordinates for each map node (i.e. pixel)
private int pixelWeight; //the weight or cost of each pixel based off it's color
//this can also be modified to contain the color of food or water
private int hCost; // the heuristic cost from this node to another
public int gCost; // determines which node has a smaller weight based off the pixelWeight
private int fCost;
private int rCost;
private boolean isOccupied; //determines whether or not the node is occupied by food/ant/water/sea/nest
public MapNode(Object object, Object object2, int j, int i, int rgb, int k, //These match up to corresponding variables listed above.
int l, int m, int n, Object object3)
{
MapNode.neighbors = (List<MapNode>) object;
this.parent = (MapNode) object2;
this.x = j;
this.y = i;
this.pixelWeight = rgb;
this.hCost = k;
this.gCost = l;
this.fCost = m;
this.rCost = n;
this.isOccupied = (boolean) object3;
// TODO Auto-generated constructor stub
}
public MapNode() {
// TODO Auto-generated constructor stub
}
public MapNode(int x, int y) {
this.x = x;
this.y = y;
// TODO Auto-generated constructor stub
}
/* getter and setter land starts here */
/* getter then setter/variable */
public int getPixelWeight(){return pixelWeight;}
public void setPixelWeight(int pixelWeight){this.pixelWeight = pixelWeight;}
public int getHCost(){return hCost;}
public void setHCost(int hCost){this.hCost = hCost;}
public int getFCost(){return fCost;}
public void setFCost(int fCost){this.fCost = fCost;}
public int getRCost(){return rCost;}
public void setRCost(int rCost){this.rCost = rCost;}
public boolean getIsOccupied(){return isOccupied;}
public void setIsOccupied(boolean isOccupied){this.isOccupied = isOccupied;}
/* end of getter and setter land */
private int setHCost(MapNode end){return Math.abs(this.x - end.x) + Math.abs(this.y - end.y);} //finds heuristic cost from current node to destination
private int setGCost(int prevGCost, int prevValue)
{
if (prevValue > pixelWeight) return 1;
if (prevValue < pixelWeight) return 2;
return 1;
}
private int setRCost()
{
return 0;
}
public void setCosts(MapNode end, int prevGCost, int prevValue)
{
this.hCost = setHCost(end);
this.gCost = setGCost(prevGCost, prevValue);
this.rCost = setRCost();
this.fCost = this.hCost + this.gCost + this.rCost;
}
public boolean isPassable() //this needs to modified to determine multiple forms of occupiedness descibed in variable
{
if (this.pixelWeight > 255) return false;
return true;
}
public boolean isAbove(MapNode a) //determines open nodes above the ant(or will this be a pixel?)
{
return (a.y - this.y == -1) && (a.x == this.x);
}
public boolean isBelow(MapNode a) //determines open nodes below the ant(or will this be a pixel?)
{
return (a.y - this.y == 1) && (a.x == this.x);
}
public boolean isLeft(MapNode a)
{
return (a.x - this.x == -1) && (a.y == this.y); //determines open nodes left of the ant(or will this be a pixel?)
}
public boolean isRight(MapNode a) //determines open nodes right of the ant(or will this be a pixel?)
{
return (a.x - this.x == 1) && (a.y == this.y);
}
public boolean isNE(MapNode a) //determines open nodes northeast of the ant(or will this be a pixel?)
{
return (a.x - this.x == 1) && (a.y - this.y == -1);
}
public boolean isSE(MapNode a) //determines open nodes southeast of the ant(or will this be a pixel?)
{
return (a.x - this.x == 1) && (a.y - this.y == 1);
}
public boolean isNW(MapNode a) //determines open nodes northwest of the ant(or will this be a pixel?)
{
return (a.x - this.x == -1) && (a.y - this.y == -1);
}
public boolean isSW(MapNode a) //determines open nodes southwest of the ant(or will this be a pixel?)
{
return (a.x - this.x == -1) && (a.y - this.y == 1);
}
public void SetNeighbors(List<MapNode> nodes) //determines the neighbors of the current MapNode,
{ //if MapNode is not passible then the node is not added to the neightbors list
int count = 0;
for (MapNode n : nodes)
{
if (n.isPassable())
{
if (isAbove(n) || isBelow(n) || isLeft(n) || isRight(n) ||
isNE(n) || isSE(n) || isNW(n) || isSW(n))
{
count++;
this.neighbors.add(n);
}
}
if (count == 8) break; //8 directional nodes to look at
}
}
/* http://stackoverflow.com/questions/15175109/equals-method-in-java */
#Override
public boolean equals(Object o)
{
if (!(o instanceof MapNode)) return false;
if (this.x == ((MapNode) o).x && this.y == ((MapNode) o).y) return true;
return false;
}
/* http://docs.oracle.com/javase/tutorial/collections/interfaces/order.html */
public static Comparator<MapNode> CompareNodes = new Comparator<MapNode>()
{
#Override
public int compare(MapNode a, MapNode b)
{
// return (a.fCost > b.fCost ? 1 : (a.fCost == b.fCost ? 0 : 1));
if (a.fCost > b.fCost) return +1;
else if (a.fCost < b.fCost) return -1;
else return 0;
}
};
#Override
public int compareTo(MapNode o) {
// TODO Auto-generated method stub
return 0;
}
}
Okay, so you constructor MapNode with...
MapNodes.add(new MapNode(new ArrayList<MapNode>(), new MapNode(), j, i, pixel, 0, 0, 0, 0, null));
And then you do this within the constructor...
this.isOccupied = (boolean) object3;
object3 is the last parameter to the constructor, to which you pass null
new MapNode(
new ArrayList<MapNode>(),
new MapNode(),
j,
i,
pixel,
0,
0,
0,
0,
null // Look ma, I'm null!!
)
Related
I have a bunch of points in a 3d environment that I want to solve the traveling salesman problem with, for that I first need to convert the game world to a graph.
The world is around 1km wide, 1.5 km long and 250m high = 375 000 000 possible location. Each location either has an obstacle or is walkable.
There are 150 location that I want to connect in this world. What would be the best approach to solve this?
Here is how the pathfinder looks right now, which is the bidirectional a* that also takes into account telporters
package me.mmaxi.pathfinder;
import me.mmaxi.utils.Location;
import me.mmaxi.utils.TeleportDirection;
import java.util.*;
public class PathFinder {
private final Map<Location, Block> blocks = new HashMap<>();
public List<Location> getPath(Location start, Location goal, IWalkHandler walkHandler, ITeleportHandler teleportHandler) {
// initializing start queue
PriorityQueue<PathFindStep> queueFromStart = new PriorityQueue<>();
Block startBlock = getBlock(start);
startBlock.distanceFromStart = 0;
startBlock.fScore = start.h(goal, teleportHandler, TeleportDirection.FORWARD);
queueFromStart.add(new PathFindStep(startBlock, startBlock.fScore));
// initializing goal queue
PriorityQueue<PathFindStep> queueFromGoal = new PriorityQueue<>();
Block goalBlock = getBlock(goal);
goalBlock.distanceFromGoal = 0;
goalBlock.fScore = goal.h(start, teleportHandler, TeleportDirection.BACKWARD);
queueFromGoal.add(new PathFindStep(goalBlock, goalBlock.fScore));
// here we will store the meeting point
Block meetingPoint = null;
// for debug purposes
int furthestAwayFromStartSoFar = 0;
int furthestAwayFromGoalSoFar = 0;
// working on the queues
while (!queueFromStart.isEmpty() || !queueFromGoal.isEmpty()) {
// coming from start
PathFindStep currentStepFromStart = queueFromStart.poll();
if (currentStepFromStart == null) {
throw new RuntimeException("We can no longer reach any blocks from the start. Maybe it's inside a wall?");
} else {
Block current = currentStepFromStart.toVisit;
if (Double.compare(currentStepFromStart.fScore, current.fScore) != 0) {
// we already found a better fScore in the meantime
continue;
}
if (current.location.equals(goal) || current.lastComingFromGoal != null) {
// we found the goal or meeting point
System.out.println("Breaking condition:\n" +
"* current.location.equals(goal):" + current.location.equals(goal) + "\n" +
"* current.lastComingFromGoal != null:" + (current.lastComingFromGoal != null));
meetingPoint = current;
break;
}
Set<Block> neighbours = getNeighbours(current);
Location teleportTarget = teleportHandler.getDestination(current.location);
if (teleportTarget != null) {
System.out.println("Found teleport target: " + teleportTarget);
neighbours.add(getBlock(teleportTarget));
}
for (Block neighbour : neighbours) {
if (!walkHandler.canWalk(neighbour.location) && !neighbour.location.equals(goal)) {
// we can't go there so ignoring this neighbour but only if it's not the goal
continue;
}
int pendingDistanceFromStart = current.distanceFromStart + 1;
if (pendingDistanceFromStart < neighbour.distanceFromStart) {
neighbour.lastComingFromStart = current;
neighbour.distanceFromStart = pendingDistanceFromStart;
neighbour.fScore = neighbour.location.h(goal, teleportHandler, TeleportDirection.FORWARD) + pendingDistanceFromStart;
queueFromStart.add(new PathFindStep(neighbour, neighbour.fScore));
if (pendingDistanceFromStart > furthestAwayFromStartSoFar) {
furthestAwayFromStartSoFar = pendingDistanceFromStart;
if (pendingDistanceFromStart % 25 == 0) {
System.out.println("Furthest from start: " + pendingDistanceFromStart);
}
}
}
}
}
// coming from goal
PathFindStep currentStepFromGoal = queueFromGoal.poll();
if (currentStepFromGoal == null) {
throw new RuntimeException("We can no longer reach any blocks from the goal. Maybe it's inside a wall?");
} else {
Block current = currentStepFromGoal.toVisit;
if (Double.compare(currentStepFromGoal.fScore, current.fScore) != 0) {
// we already found a better fScore in the meantime
continue;
}
if (current.location.equals(start) || current.lastComingFromStart != null) {
// we found the start or meeting point
System.out.println("Breaking condition:\n" +
"* current.location.equals(start):" + current.location.equals(start) + "\n" +
"* current.lastComingFromStart != null:" + (current.lastComingFromStart != null));
meetingPoint = current;
break;
}
Set<Block> neighbours = getNeighbours(current);
Location teleportStart = teleportHandler.getStart(current.location);
if (teleportStart != null) {
System.out.println("Found teleport start: " + teleportStart);
neighbours.add(getBlock(teleportStart));
}
for (Block neighbour : neighbours) {
if (!walkHandler.canWalk(neighbour.location) && !neighbour.location.equals(start)) {
// we can't go there so ignoring this neighbour but only if it's not the start
continue;
}
int pendingDistanceFromGoal = current.distanceFromGoal + 1;
if (pendingDistanceFromGoal < neighbour.distanceFromGoal) {
neighbour.lastComingFromGoal = current;
neighbour.distanceFromGoal = pendingDistanceFromGoal;
neighbour.fScore = neighbour.location.h(start, teleportHandler, TeleportDirection.BACKWARD) + pendingDistanceFromGoal;
queueFromGoal.add(new PathFindStep(neighbour, neighbour.fScore));
if (pendingDistanceFromGoal > furthestAwayFromGoalSoFar) {
furthestAwayFromGoalSoFar = pendingDistanceFromGoal;
if (pendingDistanceFromGoal % 25 == 0) {
System.out.println("Furthest from goal: " + pendingDistanceFromGoal);
}
}
}
}
}
}
if (meetingPoint == null) {
throw new RuntimeException("Could not find a meeting point.");
}
System.out.println("Found a meeting point! " + meetingPoint.location);
// reversing the one side coming from the goal, so we can then backtrack
System.out.println("Reversing side that started from goal.");
while (meetingPoint.lastComingFromGoal != null) {
meetingPoint.lastComingFromGoal.lastComingFromStart = meetingPoint;
meetingPoint = meetingPoint.lastComingFromGoal;
}
// now we can backtrack
System.out.println("Backtracking.");
Block tmp = goalBlock;
if (tmp.lastComingFromStart == null) {
throw new RuntimeException("Could not find the target block from that start block.");
}
System.out.println("Found goal. Starting to backtrack.");
List<Location> path = new ArrayList<>();
while (tmp != null) {
path.add(tmp.location);
tmp = tmp.lastComingFromStart;
}
Collections.reverse(path);
return path;
}
private Block getBlock(Location location) {
return blocks.computeIfAbsent(location, block -> new Block(location));
}
private Set<Block> getNeighbours(Block block) {
Set<Block> neighbours = new HashSet<>();
for (BlockFace blockFace : BlockFace.values()) {
Location targetLocation = block.location.clone().add(blockFace.vector);
if (targetLocation.getBlockY() > 255 || targetLocation.getBlockY() < 0) {
continue;
}
neighbours.add(getBlock(targetLocation));
}
return neighbours;
}
static class PathFindStep implements Comparable<PathFindStep> {
Block toVisit;
double fScore;
public PathFindStep(Block toVisit, double fScore) {
this.toVisit = toVisit;
this.fScore = fScore;
}
#Override
public int compareTo(PathFindStep o) {
return Double.compare(fScore, o.fScore);
}
}
static class Block {
Location location;
Block lastComingFromStart;
Block lastComingFromGoal;
double fScore;
int distanceFromStart = Integer.MAX_VALUE;
int distanceFromGoal = Integer.MAX_VALUE;
public Block(Location location) {
this.location = location;
}
}
enum BlockFace {
POS_Y(new Location(+0, +1, +0)),
NEG_Y(new Location(+0, -1, +0)),
POS_X(new Location(+1, +0, +0)),
NEG_X(new Location(-1, +0, +0)),
POS_Z(new Location(+0, +0, +1)),
NEG_Z(new Location(+0, +0, -1));
final Location vector;
BlockFace(Location vector) {
this.vector = vector;
}
}
}
public class Location implements Cloneable {
private double x, y, z;
public Location(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public int getBlockX() {
return (int) x;
}
public int getBlockY() {
return (int) y;
}
public int getBlockZ() {
return (int) z;
}
public Location add(double x, double y, double z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public Location add(Location other) {
this.x += other.x;
this.y += other.y;
this.z += other.z;
return this;
}
public double distanceSquared(Location other) {
double dx = x - other.x;
double dy = y - other.y;
double dz = z - other.z;
return dx * dx + dy * dy + dz * dz;
}
public double mhd(Location other) {
double dx = Math.abs(x - other.x);
double dy = Math.abs(y - other.y);
double dz = Math.abs(z - other.z);
return Math.max(dx, Math.max(dy, dz));
}
public double h(Location other, ITeleportHandler teleportHandler, TeleportDirection teleportDirection) {
double h = mhd(other);
if (teleportHandler != null) {
Location[] closestTeleport = teleportHandler.getClosestTeleport(this, teleportDirection);
if (closestTeleport != null) {
if (teleportDirection == TeleportDirection.FORWARD) {
h = Math.min(h, mhd(closestTeleport[0]) + closestTeleport[1].mhd(other));
} else {
h = Math.min(h, mhd(closestTeleport[1]) + closestTeleport[0].mhd(other));
}
}
}
return h;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Location location = (Location) o;
return Double.compare(location.x, x) == 0 && Double.compare(location.y, y) == 0 && Double.compare(location.z, z) == 0;
}
#Override
public int hashCode() {
return Objects.hash(x, y, z);
}
#Override
public String toString() {
String xString = Double.compare(x, (int) x) == 0 ? Integer.toString((int) x) : Double.toString(x);
String yString = Double.compare(y, (int) y) == 0 ? Integer.toString((int) y) : Double.toString(y);
String zString = Double.compare(z, (int) z) == 0 ? Integer.toString((int) z) : Double.toString(z);
return "[" + xString + " " + yString + " " + zString + "]";
}
#Override
public Location clone() {
try {
return (Location) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
After reading more on Java GUIs, I thought I'd adapt a BST to a GUI form. The idea is pretty basic: Insert a node and see as the tree gets painted every time you click the insert button.
However, no tree is being painted in my program, and I'm not getting any error messages.
My BinarySearchTree Class
public class BinarySearchTree {
class Node {
int key;
Node left;
Node right;
public Node(int item) {
key = item;
left = right = null;
}
}
int height;
Node root;
BinarySearchTree(){
root = null;
}
Node insert(int key) {
root = recursion(root, key);
return root;
}
Node recursion(Node root, int key) {
if(root == null) {
root = new Node(key);
return root;
}
if(key < root.key) {
root.left = recursion(root.left, key);
} else if (key > root.key) {
root.right = recursion(root.right, key);
}
return root;
}
private void height(Node key, int depth) {
if (key != null) {
height(key.left, depth + 1);
height = depth;
height(key.right, depth + 1);
}
}
public int getHeight() {
height(root, 1);
return height;
}
public JPanel getGraph() {
return new BSTGraph(this);
}
public void makeEmpty() {
root = null;
}
public boolean isEmpty() {
if(root==null)
return true;
else
return false;
}
}
My BSTGraph Class
public class BSTGraph extends JPanel{
private BinarySearchTree bst;
private HashMap nodeMap = null;
private HashMap subtreeSizes = null;
private boolean dirty = true;
private int parentToChild = 20, childToChild = 30;
private Dimension empty = new Dimension(0,0);
private FontMetrics fm = null;
public BSTGraph(BinarySearchTree bst)
{
this.bst = bst;
this.setBackground(Color.WHITE);
nodeMap = new HashMap();
subtreeSizes = new HashMap();
dirty = true;
repaint();
}
private void getPositions()
{
nodeMap.clear();
subtreeSizes.clear();
BinarySearchTree.Node root = this.bst.root;
if (bst.root != null)
{
getChildTreeSize(bst.root);
getPosition(root, Integer.MAX_VALUE, Integer.MAX_VALUE, 0);
}
}
private void getPosition(BinarySearchTree.Node n, int left, int right, int top)
{
if (n == null)
return;
Dimension ld = (Dimension) subtreeSizes.get(n.left);
if (ld == null)
ld = empty;
Dimension rd = (Dimension) subtreeSizes.get(n.right);
if (rd == null)
rd = empty;
int center = 0;
if (right != Integer.MAX_VALUE)
center = right - rd.width - childToChild/2;
else if (left != Integer.MAX_VALUE)
center = left + ld.width + childToChild/2;
int width = fm.stringWidth(n.key+"");
nodeMap.put(n,new Rectangle(center - width/2 - 3, top, width + 6, fm.getHeight()));
getPosition(n.left, Integer.MAX_VALUE, center - childToChild/2, top + fm.getHeight() + parentToChild);
getPosition(n.right, center + childToChild/2, Integer.MAX_VALUE, top + fm.getHeight() + parentToChild);
}
private Dimension getChildTreeSize(BinarySearchTree.Node n)
{
if (n == null)
return new Dimension(0,0);
Dimension ld = getChildTreeSize(n.left);
Dimension rd = getChildTreeSize(n.right);
int h = fm.getHeight() + parentToChild + Math.max(ld.height, rd.height);
int w = ld.width + childToChild + rd.width;
Dimension d = new Dimension(w, h);
subtreeSizes.put(n, d);
return d;
}
private void graphTree(Graphics2D g, BinarySearchTree.Node n, int x, int y, int yOffSet)
{
if (n == null)
return;
Rectangle r = (Rectangle) nodeMap.get(n);
g.draw(r);
g.drawString(n.key+"", r.x + 3, r.y + yOffSet);
if (x != Integer.MAX_VALUE)
g.drawLine(x, y, (int)(r.x + r.width/2), r.y);
graphTree(g, n.left, (int)(r.x + r.width/2), r.y + r.height, yOffSet);
graphTree(g, n.right, (int)(r.x + r.width/2), r.y + r.height, yOffSet);
}
#Override
public void paint(Graphics g)
{
super.paint(g);
fm = g.getFontMetrics();
if (dirty)
{
getPositions();
dirty = false;
}
Graphics2D g2d = (Graphics2D) g;
g2d.translate(getWidth() / 2, parentToChild);
graphTree(g2d, this.bst.root, Integer.MAX_VALUE, Integer.MAX_VALUE,
fm.getLeading() + fm.getAscent());
fm = null;
}
}
Finally, a complement method in my GUI class which takes care of adding the "drawing" to a JInternalFrame element called graficoFrame
public void complement(){
Rectangle size = this.graficoFrame.getBounds();
this.graficoFrame = null;
this.graficoFrame = new JInternalFrame("Representación gráfica", true);
this.graficoFrame.setBounds(size);
this.graficoFrame.setEnabled(false);
this.repaintTree();
}
private void repaintTree() {
Rectangle size = this.graficoFrame.getBounds();
this.graficoFrame = null;
this.graficoFrame = new JInternalFrame("Representación gráfica", true);
this.graficoFrame.setBounds(size);
this.graficoFrame.setEnabled(false);
this.graficoFrame.add(bst.getGraph(), BorderLayout.CENTER);
this.graficoFrame.setVisible(true);
}
I've confirmed that the nodes are being correctly added and stored, however, the drawing never shows up, the JInternalFrame is still empty. Any visible reason why? based on this code
EDIT: I'm noticing it's not even creating the drawing, it's not giving it a title
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
The goal is to draw a maze after resolving it (using BFS) with the shortest path from start to exit.
OUTPUT must be like this
***************************************************
[20,19]
***************************************************
#####################
..#...........#.....#
#.#.#########.#.###.#
#...#.........#.#...#
###############.#.###
#.....#.......#.#...#
#.#######.###.#.#.#.#
#...#...#...#...#.#.#
###.###.###.###.#.#.#
#.#.#.#...#.#...#.#.#
#.#.#.#.#1#.#.###.#.#
#...#.#.#1#.#...#.#.#
#####.###1#.#####.###
#.#1111111#.#...#...#
#.#1#######.#.#.###.#
#.#1#...#...#.#.#...#
#.#1###.#.#####.#####
#.#11111111111111111#
#.##.####.#########1#
#..................11
#####################
There are many path to go to the exit [20,19] , but we must draw with the shortest path.
My code is below but it doesn't print the shortest path.
CODE
class Maze {
public static void main(String args[]) {
int W = 21;
int H = 21;
int X = 9;
int Y = 10;
String[] mazeString = {
"##########.##########",
"..#...........#.....#",
"#.#.#########.#.###.#",
"#...#.........#.#...#",
"###############.#.###",
"#.....#.......#.#...#",
"#.#######.###.#.#.#.#",
"#...#...#...#...#.#..",
"###.###.###.###.#.#.#",
"#.#.#.#...#.#...#.#.#",
"#.#.#.#.#.#.#.###.#.#",
"#...#.#.#.#.#...#.#.#",
"#####.###.#.#####.###",
"#.#.......#.#...#...#",
"#.#.#######.#.#.###.#",
"#.#.#...#...#.#.#...#",
"#.#.###.#.#####.#####",
"#.#.................#",
"#.##.####.#########.#",
"#.........#..........",
"####.######.#########"
};
Node[][] nodes = new Node[W][H];
Node start = null;
List<Node> result = new ArrayList<>();
Boolean[][] visited = new Boolean[W][H];
Boolean[][] blocked = new Boolean[W][H];
Boolean[][] exits = new Boolean[W][H];
for (int i = 0; i < H; i++) {
String R = mazeString[i];
for (int j = 0; j < W; j++) {
Node node = new Node(j, i);
blocked[j][i] = R.charAt(j) == '#';
node.blocked = R.charAt(j) == '#';
exits[j][i] = (!node.blocked) && (i == (H - 1) || j == (W - 1) || i == 0 || j == 0);
visited[j][i] = false;
node.exit = (!node.blocked) && (i == (H - 1) || j == (W - 1) || i == 0 || j == 0);
nodes[j][i] = node;
if (X == j && Y == i) {
start = nodes[j][i];
}
}
}
List<List<Node>> paths = new ArrayList<>();
findExits(start, nodes, visited, W, H, result, paths);
if (!result.isEmpty()) {
Collections.sort(result, new Comparator<Node>() {
#Override
public int compare(Node o1, Node o2) {
if (Integer.compare(o1.x, o2.x) == 0) {
return Integer.compare(o1.y, o2.y);
} else {
return Integer.compare(o1.x, o2.x);
}
}
});
}
for (List<Node> path : paths) {
System.out.println("***************************************************");
System.out.println("[" + path.get(0).x + "," + path.get(0).y + "]");
System.out.println("***************************************************");
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
String s = blocked[j][i] ? "#" : path.contains(new Node(j, i)) ? "1" : ".";
System.out.print(s);
}
System.out.println("");
}
}
}
public static void findExits(Node start, Node[][] nodes, Boolean[][] visited, int W, int H, List<Node> result, List<List<Node>> paths) {
int x = start.x;
int y = start.y;
visited[x][y] = true;
if (start.exit) {
result.add(start);
visited[x][y] = false;
List<Node> path = new ArrayList<Node>();
while (start.parent != null) {
path.add(start);
start = start.parent;
}
path.add(start);
paths.add(path);
}
//TOP
if ((y - 1) >= 0) {
if (!visited[x][y - 1] && (!nodes[x][y - 1].blocked)) {
nodes[x][y - 1].parent = start;
findExits(nodes[x][y - 1], nodes, visited, W, H, result, paths);
}
}
//BOT
if ((y + 1) < H) {
if (!visited[x][y + 1] && (!nodes[x][y + 1].blocked)) {
nodes[x][y + 1].parent = start;
findExits(nodes[x][y + 1], nodes, visited, W, H, result, paths);
}
}
//LEFT
if ((x - 1) >= 0) {
if (!visited[x - 1][y] && (!nodes[x - 1][y].blocked)) {
nodes[x - 1][y].parent = start;
findExits(nodes[x - 1][y], nodes, visited, W, H, result, paths);
}
}
//RIGHT
if ((x + 1) < W) {
if (!visited[x + 1][y] && (!nodes[x + 1][y].blocked)) {
nodes[x + 1][y].parent = start;
findExits(nodes[x + 1][y], nodes, visited, W, H, result, paths);
}
}
}
public static class Node {
public int x, y;
boolean blocked = false;
boolean exit = false;
Node parent = null;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Node other = (Node) obj;
if (this.x != other.x) {
return false;
}
if (this.y != other.y) {
return false;
}
return true;
}
}
}
I want to solve a maze and print the shortest path from start to exit usign BFS. I already solve the maze but my code doesnt print the shortest path, this is my problem.
NB (Additional informations, not questions) :
the maze can have many exit
W (width), H (height), [X,Y] (start point)
'#' (blocked cell), '.' (free cell)
the path from start and exit is represented by '11111...' on the output
Please review the following code. It lets you printout all paths found, as well as the shortest one found.
I did not change nor checked the search algorithm. I think it needs more work because I think it does not find the shortest path possible to each exit. I will look into it later.
I did not figure out yet what is the use of List<Node> result. Also I did not see you implement backtracking.
class Maze {
private static char NUMBER_SIGN = '#', DOT = '.', START = 'S';
private static char EXIT = 'E', PATH = '1';
private static Node[][] nodes;
private static Node start;
private static boolean[][] visited; //no need to use Boolean
//exit holds the same information as Node.blocked. No need to duplicate
//private static boolean[][] blocked;
//exit holds the same information as Node.exit. No need to duplicate
//private static boolean[][] exits;
private static int mazeWidth, mazeHeight, startH, startW; //use meaningful names
private static List<List<Node>> paths;
public static void main(String args[]) {
mazeWidth = 21;//use meaningful names
mazeHeight = 21;
startH = 9; startW = 10;
String[] mazeData = getMazeData() ;
makeMaze(mazeData);
drawMaze(); //draw maze as built from input data
List<Node> result = new ArrayList<>();
paths = new ArrayList<>();
findExits(start, nodes, visited, mazeWidth, mazeHeight, result, paths);
if (!result.isEmpty()) {
Collections.sort(result, new Comparator<Node>() {
#Override
public int compare(Node o1, Node o2) {
if (Integer.compare(o1.x, o2.x) == 0) {
return Integer.compare(o1.y, o2.y);
} else {
return Integer.compare(o1.x, o2.x);
}
}
});
}
drawAllPaths(); // see all paths found
List<Node> shortestPath = getShortestPath();
drawShortestPath(shortestPath);
}
private static void drawMaze() {
System.out.println("***************************************************");
System.out.println("Maze as defined by input");
System.out.println("***************************************************");
drawMaze(null);
}
private static void drawAllPaths() {
for (List<Node> path : paths) {
System.out.println("***************************************************");
System.out.println("Path to exit ["
+ path.get(0).x + "," + path.get(0).y + "] length:"+ path.size());
System.out.println("***************************************************");
drawMaze(path);
}
}
private static void drawShortestPath(List<Node> path) {
System.out.println("***************************************************");
System.out.println("Shortest path is to exit ["
+ path.get(0).x + "," + path.get(0).y + "] length:"+ path.size());
System.out.println("***************************************************");
drawMaze(path);
}
private static void drawMaze(List<Node> path) {
for(Node[] row : nodes ) {
for(Node node : row) {
char c = node.getGraphics();
if ((path != null) && path.contains(node)) {c = PATH;}
System.out.print(c);
}
System.out.println("");
}
}
private static void makeMaze(String[] mazeData) {
nodes = new Node[mazeHeight][mazeWidth];
visited = new boolean[mazeHeight][mazeWidth];
for (int height = 0; height < mazeHeight; height++) {
String row = mazeData[height];
for (int width = 0; width < mazeWidth; width++) {
Node node = new Node(height, width);
node.blocked = row.charAt(width) == NUMBER_SIGN;
visited[width][height] = false;
node.exit = (!node.blocked) && ((height == (mazeHeight - 1)) ||
(width == (mazeWidth - 1)) || (height == 0) || (width == 0));
nodes[height][width] = node;
}
}
start = nodes[startH][startW];//no need to set it in the loop
}
//use boolean instead of Boolean
private static void findExits(Node start, Node[][] nodes,
boolean[][] visited, int W, int H, List<Node> result, List<List<Node>> paths) {
int x = start.x;
int y = start.y;
visited[x][y] = true;
if (start.exit) {
result.add(start);
visited[x][y] = false;
List<Node> path = new ArrayList<>();
while (start.parent != null) {
path.add(start);
start = start.parent;
}
path.add(start);
paths.add(path);
}
//TOP
if ((y - 1) >= 0) {
if (!visited[x][y - 1] && (!nodes[x][y - 1].blocked)) {
nodes[x][y - 1].parent = start;
findExits(nodes[x][y - 1], nodes, visited, W, H, result, paths);
}
}
//BOT
if ((y + 1) < H) {
if (!visited[x][y + 1] && (!nodes[x][y + 1].blocked)) {
nodes[x][y + 1].parent = start;
findExits(nodes[x][y + 1], nodes, visited, W, H, result, paths);
}
}
//LEFT
if ((x - 1) >= 0) {
if (!visited[x - 1][y] && (!nodes[x - 1][y].blocked)) {
nodes[x - 1][y].parent = start;
findExits(nodes[x - 1][y], nodes, visited, W, H, result, paths);
}
}
//RIGHT
if ((x + 1) < W) {
if (!visited[x + 1][y] && (!nodes[x + 1][y].blocked)) {
nodes[x + 1][y].parent = start;
findExits(nodes[x + 1][y], nodes, visited, W, H, result, paths);
}
}
}
public static class Node {
public int x, y;
boolean blocked = false;
boolean exit = false;
Node parent = null;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Node other = (Node) obj;
if (x != other.x) {
return false;
}
if (y != other.y) {
return false;
}
return true;
}
//it is simpler to have Node return its graphic representation
char getGraphics() {
char c = blocked ? NUMBER_SIGN : DOT;
if(equals(start)) { c=START;}
else if (exit) { c=EXIT;}
return c;
}
}
private static List<Node> getShortestPath() {
//initialize with an arbitrary path
List<Node> shortest = paths.get(0);
for (List<Node> path : paths) {
if(path.size() < shortest.size()) {
shortest = path;
}
}
return shortest;
}
private static String[] getMazeData() {
return new String[] {
"##########.##########",
"..#...........#.....#",
"#.#.#########.#.###.#",
"#...#.........#.#...#",
"###############.#.###",
"#.....#.......#.#...#",
"#.#######.###.#.#.#.#",
"#...#...#...#...#.#..",
"###.###.###.###.#.#.#",
"#.#.#.#...#.#...#.#.#",
"#.#.#.#.#.#.#.###.#.#",
"#...#.#.#.#.#...#.#.#",
"#####.###.#.#####.###",
"#.#.......#.#...#...#",
"#.#.#######.#.#.###.#",
"#.#.#...#...#.#.#...#",
"#.#.###.#.#####.#####",
"#.#.................#",
"#.##.####.#########.#",
"#.........#..........",
"####.######.#########"
};
}
}
EDIT
An improved version. Please test carefully.
class Maze {
private static char NUMBER_SIGN = '#', DOT = '.', START = 'S';
private static char EXIT = 'E', PATH = '1';
private static Node[][] nodes;
private static Node startNode;
private static boolean[][] visited; //no need to use Boolean
//exit holds the same information as Node.blocked. No need to duplicate
//private static boolean[][] blocked;
//exit holds the same information as Node.exit. No need to duplicate
//private static boolean[][] exits;
private static int mazeRows, mazeCols, startRow, startCol; //use meaningful names
private static List<List<Node>> paths;
public static void main(String args[]) {
mazeCols = 21; mazeRows = 21;//use meaningful and consistent names
startRow = 9; startCol = 10; //better keep h,w or height,width all over
String[] mazeData = getMazeData() ;
makeMaze(mazeData);
drawMaze(); //draw maze as built from input data
paths = new ArrayList<>();
findExits(startNode);
drawAllPaths(); // print all paths found
List<Node> shortestPath = getShortestPath();
drawShortestPath(shortestPath);
}
private static void drawMaze() {
System.out.println("*****************************************");
System.out.println("Maze as defined by input");
System.out.println("*****************************************");
drawMaze(null);
}
private static void drawAllPaths() {
for (List<Node> path : paths) {
System.out.println("*****************************************");
System.out.println("Path to exit ["
+ path.get(0).row + "," + path.get(0).col + "] length:"+ path.size());
System.out.println("*****************************************");
drawMaze(path);
}
}
private static void drawShortestPath(List<Node> path) {
System.out.println("*****************************************");
System.out.println("Shortest path is to exit ["
+ path.get(0).row + "," + path.get(0).col + "] length:"+ path.size());
System.out.println("*****************************************");
drawMaze(path);
}
private static void drawMaze(List<Node> path) {
for(Node[] row : nodes ) {
for(Node node : row) {
char c = node.getGraphics();
//overwrite c if node is in path
if ( (c != EXIT) && ( c != START ) &&
(path != null) && path.contains(node)) {c = PATH;}
System.out.print(c);
}
System.out.println("");
}
}
private static void makeMaze(String[] mazeData) {
nodes = new Node[mazeRows][mazeCols];
visited = new boolean[mazeRows][mazeCols];
for (int rowIndex = 0; rowIndex < mazeRows; rowIndex++) {
String row = mazeData[rowIndex];
for (int colIndex = 0; colIndex < mazeCols; colIndex++) {
Node node = new Node(rowIndex, colIndex);
node.blocked = row.charAt(colIndex) == NUMBER_SIGN;
visited[rowIndex][colIndex] = false;
node.exit = (!node.blocked) && ((rowIndex == (mazeRows - 1)) ||
(colIndex == (mazeCols - 1)) || (rowIndex == 0) || (colIndex == 0));
nodes[rowIndex][colIndex] = node;
}
}
startNode = nodes[startRow][startCol];//no need to set it in the loop
}
//use boolean instead of Boolean
private static void findExits(Node node) {
int row = node.row;
int col = node.col;
if(visited[row][col]) { return; }
if (node.exit) {
List<Node> path = new ArrayList<>();
while (node.parent != null) {
path.add(node);
node = node.parent;
}
path.add(node);
paths.add(path);
return; //do not continue to check exit neighbors
}
//LEFT
if ((col - 1) >= 0) {
Node testNode = nodes[row][col - 1];
//the following if statement repeats for all directions
//better put in a method
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node; //parent ! null indicates that cell is tested
findExits(testNode);
testNode.parent = null; //set back to null: test finished
}
}
//RIGHT
if ((col + 1) < mazeCols) {
Node testNode = nodes[row][col + 1];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
//TOP
if ((row - 1) >= 0) {
Node testNode = nodes[row-1][col];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
//BOTTOM
if ((row + 1) < mazeRows) {
Node testNode = nodes[row+1][col];
if ((testNode.parent == null) && ! testNode.blocked) {
testNode.parent = node;
findExits(testNode);
testNode.parent = null;
}
}
visited[row][col] = true; //mark as visited after all directions explored
node.parent = null;
}
public static class Node {
public int row, col;
boolean blocked = false;
boolean exit = false;
Node parent = null;
public Node(int row, int col) {
this.row = row;
this.col = col;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Node other = (Node) obj;
if (row != other.row) {
return false;
}
if (col != other.col) {
return false;
}
return true;
}
//it is simpler to have Node return its graphic representation
char getGraphics() {
char c = blocked ? NUMBER_SIGN : DOT;
if(equals(startNode)) { c=START;}
else if (exit) { c=EXIT;}
return c;
}
#Override
public String toString() {
return "Node " + row +"-"+ col +" ("+ getGraphics() + ")";
}
}
private static List<Node> getShortestPath() {
//initialize with an arbitrary path
List<Node> shortest = paths.get(0);
for (List<Node> path : paths) {
if(path.size() < shortest.size()) {
shortest = path;
}
}
return shortest;
}
private static String[] getMazeData() {
return new String[] {
"##########.##########",
"..#...........#.....#",
"#.#.#########.#.###.#",
"#...#.........#.#...#",
"###############.#.###",
"#.....#.......#.#...#",
"#.#######.###.#.#.#.#",
"#...#...#...#...#.#..",
"###.###.###.###.#.#.#",
"#.#.#.#...#.#...#.#.#",
"#.#.#.#.#.#.#.###.#.#",
"#...#.#.#.#.#...#.#.#",
"#####.###.#.#####.###",
"#.#.......#.#...#...#",
"#.#.#######.#.#.###.#",
"#.#.#...#...#.#.#...#",
"#.#.###.#.#####.#####",
"#.#.................#",
"#.##.####.#########.#",
"#.........#..........",
"####.######.#########"
};
}
}
Feedback would be appreciated.
You're on the right track where you're building a list of paths.
Try this:
create an empty list of paths
start at the starting point, create one path with one cell
look in the four directions and for each cell that is not blocked and not already included in any of the previous paths clone your current path, add that new cell to the end and add it to the list of paths
now loop through all your paths and repeat this progress, checking the four directions from the cell at the tip
stop building a path when it hits the exit or has no more legitimate moves to make, i.e. dead end
use the path with the shortest length
Here is the assignment:
Modify the maze problem in Chapter 4 so that it can start from a user defined starting position (other than 0, 0) and search for a user defined ending point.
The whole program seems to look fine, and I still have to mess with the user-inputted part, but there is one line that has an error and I don't know how to get rid of it. Any help would be appreciated.
The line that has the error is:
StackADT stack = new LinkedStackADT ();
And it is telling me that LinkedStackADT cannot be resolved to a type.
Also, how do I get the maze to take in user-defined starting positions and ending points? Thanks for any possible help!
public class Maze
{
public interface StackADT<T> {
public void push (T element);
public T pop();
public T peek();
public boolean isEmpty();
public int size();
public String toString();
}
public static void main(String[] args){
abstract class LinkedStack<T> implements StackADT<T>
{
private int count;
private LinearNode<T> top;
public LinkedStack()
{
count = 0;
top = null;
}
class LinearNode<T>
{
private LinearNode<T> next;
private T element;
public LinearNode()
{
next = null;
element = null;
}
public LinearNode(T elem)
{
next = null;
element = elem;
}
public LinearNode<T> getNext()
{
return next;
}
public void setNext(LinearNode<T> node)
{
next = node;
}
public T getElement()
{
return element;
}
public void setElement(T elem)
{
element = elem;
}
}
class Position
{
private int x;
private int y;
Position ()
{
x = 0;
y = 0;
}
public int getx()
{
return x;
}
public int gety()
{
return y;
}
public void setx1(int a)
{
x = a;
}
public void sety(int a)
{
y = a;
}
public void setx(int x2) {
}
}
private final int TRIED = 3;
private final int PATH = 7;
private int [][] grid = {{1,1,1,0,1,1,0,0,0,1,1,1,1},
{1,0,0,1,1,0,1,1,1,1,0,0,1},
{1,1,1,1,1,0,1,0,1,0,1,0,0},
{0,0,0,0,1,1,1,0,1,0,1,1,1},
{1,1,1,0,1,1,1,0,1,0,1,1,1},
{1,0,1,0,0,0,0,1,1,1,0,0,1},
{1,0,1,1,1,1,1,1,0,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1}};
public StackADT<Position> push_new_pos(int x, int y,
StackADT<Position> stack)
{
Position npos = new Position();
npos.setx1(x);
npos.sety(y);
if (valid(npos.getx(),npos.gety()))
stack.push(npos);
return stack;
}
public boolean traverse ()
{
boolean done = false;
Position pos = new Position();
Object dispose;
StackADT<Position> stack = new LinkedStackADT<Position> ();
stack.push(pos);
while (!(done))
{
pos = stack.pop();
grid[pos.getx()][pos.gety()] = TRIED; // this cell has been tried
if (pos.getx() == grid.length-1 && pos.gety() == grid[0].length-1)
done = true; // the maze is solved
else
{
stack = push_new_pos(pos.getx(),pos.gety() - 1, stack);
stack = push_new_pos(pos.getx(),pos.gety() + 1, stack);
stack = push_new_pos(pos.getx() - 1,pos.gety(), stack);
stack = push_new_pos(pos.getx() + 1,pos.gety(), stack);
}
}
return done;
}
private boolean valid (int row, int column)
{
boolean result = false;
if (row >= 0 && row < grid.length &&
column >= 0 && column < grid[row].length)
if (grid[row][column] == 1)
result = true;
return result;
}
public String toString ()
{
String result = "\n";
for (int row=0; row < grid.length; row++)
{
for (int column=0; column < grid[row].length; column++)
result += grid[row][column] + "";
result += "\n";
}
return result;
}
}
}
}
You don't have a type (or a class) defined as LinkedStackADT. You do have a type LinkedStack, but it's abstract so the new will fail. If you remove the abstract keyword from LinkedStack, it should be instantiatable. (note: instantiatable is not a real word)
I've been trying all day to get this algorithm up and running, but I cant for the life of me. I've read many tutorials on the net, and source code in AS3, javascript, and C++; but I cannot adapt what I am seeing to my own code.
I have created an AStar class that has a nested class named Node. The map is a 2D array named MAP.
The biggest problem that I am having is pulling the F value in the pathfind function.
I have implemented the F = G + H, my problem is the actual AStar algorithm. Can someone please help, this is how far I've got as of yet:
import java.util.ArrayList;
public class AStar
{
int MAP[][];
Node startNode, endNode;
public AStar(int MAP[][], int startXNode, int startYNode,
int endXNode, int endYNode)
{
this.MAP = MAP;
startNode = new Node(startXNode, startYNode);
endNode = new Node(endXNode, endYNode);
}
public void pathfinder()
{
ArrayList openList = new ArrayList();
ArrayList closedList = new ArrayList();
}
public int F(Node startNode, Node endNode)
{
return (H(startNode, endNode) + G(startNode));
}
//H or Heuristic part of A* algorithm
public int H(Node startNode, Node endNode)
{
int WEIGHT = 10;
int distance = (Math.abs(startNode.getX() - endNode.getX()) + Math.abs(startNode.getY() - endNode.getY()));
return (distance * WEIGHT);
}
public int G(Node startNode)
{
if(MAP[startNode.getX() - 1][startNode.getY()] != 1)
{
return 10;
}
if(MAP[startNode.getX() + 1][startNode.getY()] != 1)
{
return 10;
}
if(MAP[startNode.getX()][startNode.getY() -1] != 1)
{
return 10;
}
if(MAP[startNode.getX()][startNode.getY() + 1] != 1)
{
return 0;
}
return 0;
}
public class Node
{
private int NodeX;
private int NodeY;
private int gScore;
private int hScore;
private int fScore;
public Node(int NodeX, int NodeY)
{
this.NodeX = NodeX;
this.NodeY = NodeY;
}
public int getX()
{
return NodeX;
}
public int getY()
{
return NodeY;
}
public int getG()
{
return gScore;
}
public void setG(int gScore)
{
this.gScore = gScore;
}
public int getH()
{
return hScore;
}
public void setH(int hScore)
{
this.hScore = hScore;
}
public int getF()
{
return fScore;
}
public void setF(int fScore)
{
this.fScore = fScore;
}
}
}
This is the furthest I can ever get with the pathfinder function:
public void pathfinder()
{
LinkedList<Node> openList = new LinkedList();
LinkedList<Node> closedList = new LinkedList();
Node currentNode;
openList.add(startNode);
while(openList.size() > 0)
{
currentNode = (Node) openList.get(0);
closedList.add(currentNode);
for(int i = 0; i < openList.size(); i++)
{
int cost = F(currentNode, endNode);
}
}
}
I recently threw this A* code together to solve a Project Euler problem. You'll have to fill in the details for a matrix of Node objects. Use it at your own risk, however I can say it solved the problem :)
public class Node {
List<Node> neighbors = new ArrayList<Node>();
Node parent;
int f;
int g;
int h;
int x;
int y;
int cost;
}
public List<Node> aStar(Node start, Node goal) {
Set<Node> open = new HashSet<Node>();
Set<Node> closed = new HashSet<Node>();
start.g = 0;
start.h = estimateDistance(start, goal);
start.f = start.h;
open.add(start);
while (true) {
Node current = null;
if (open.size() == 0) {
throw new RuntimeException("no route");
}
for (Node node : open) {
if (current == null || node.f < current.f) {
current = node;
}
}
if (current == goal) {
break;
}
open.remove(current);
closed.add(current);
for (Node neighbor : current.neighbors) {
if (neighbor == null) {
continue;
}
int nextG = current.g + neighbor.cost;
if (nextG < neighbor.g) {
open.remove(neighbor);
closed.remove(neighbor);
}
if (!open.contains(neighbor) && !closed.contains(neighbor)) {
neighbor.g = nextG;
neighbor.h = estimateDistance(neighbor, goal);
neighbor.f = neighbor.g + neighbor.h;
neighbor.parent = current;
open.add(neighbor);
}
}
}
List<Node> nodes = new ArrayList<Node>();
Node current = goal;
while (current.parent != null) {
nodes.add(current);
current = current.parent;
}
nodes.add(start);
return nodes;
}
public int estimateDistance(Node node1, Node node2) {
return Math.abs(node1.x - node2.x) + Math.abs(node1.y - node2.y);
}
I dont know if you are trying only to use simple types, or if you just didn't think about it, but you need to have a PriorityQueue to get your A* working.
A good way to think is that you put your startpoint into a priority queue with distance 0, and then start a loop that only stops when the prioriy queue is empty.
In the loop you take the min-node out, and check to see if it hasnt been open before, or if it has, if you have now found a shorter way to it.
If either these are true, you add the distance to the new node, add the edge/from-square to a map, and then add the distance + heuristic to the priority queue.
I have written this to work on a grid of booleans, and a constant conversion between 1D and 2D arrays, but I hope it is readable:
public void AStarRoute()
{
gridDist = new double[rows][cols];
System.out.println("Start of AStarRoute");
MinPriorityQueue pq = new MinPriorityQueue(rows * cols);
edgeTo = new HashMap<Integer, Integer>();
gridDist[x1Dto2D(start)][y1Dto2D(start)] = 0;
pq.insert(start, 0);
int from;
while (!pq.isEmpty()) {
from = pq.delMin();
int x = x1Dto2D(from);
int y = y1Dto2D(from);
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
int newX = x + i;
int newY = y + j;
if (newX >= 0 && newY >= 0 && newX < cols && newY < rows && !(i == 0 && j == 0)) {
if (grid[newX][newY]) {
//System.out.println("NewDist: " + gridDist[newX][newY] + " - OldDist+dist: " + (gridDist[x][y] + ((Math.abs(i) == Math.abs(j)) ? 1.4 : 1.0)) + ":" + (int)(gridDist[x][y] + ((Math.abs(i) == Math.abs(j)) ? 1.4 : 1.0)));
if (!edgeTo.containsKey(convert2Dto1D(newX, newY)) || gridDist[newX][newY] > (gridDist[x][y] + ((Math.abs(i) == Math.abs(j)) ? 14 : 10))) {
gridDist[newX][newY] = (int)(gridDist[x][y] + ((Math.abs(i) == Math.abs(j)) ? 14 : 10));
maxDistToEnd = (int)Math.max(maxDistToEnd, gridDist[newX][newY]);
edgeTo.put(convert2Dto1D(newX, newY), convert2Dto1D(x, y));
pq.insert(convert2Dto1D(newX, newY), gridDist[newX][newY] + (int)Math.sqrt(Math.pow((newX - x1Dto2D(end))*10, 2) + Math.pow((newY - y1Dto2D(end))*10, 2)));
if(convert2Dto1D(newX, newY) == end){
System.out.println("End found at (" + newX + ", " + newY + ")");
paintGridDist = true;
route = new ArrayList<Integer>();
int n = convert2Dto1D(newX, newY);
route.add(n);
do{
n = edgeTo.get(n);
route.add(n);
}while(start != n);
repaint();
return;
}
}
}
}
}
}
}
paintGridDist = true;
repaint();
}