I have this path finding code which does the first part of the finding by only going one square
public class PathFinding {
static Vector2 start;
static Vector2 end;
static Cell[][] cells;
static Node currentNode;
static Arena arena;
public static void calcPAth(Vector2 from, Vector2 to,
Cell[][] mapCells, Arena a) {
start = from;
end = to;
cells = mapCells;
arena = a;
List<Node> openList = new ArrayList<Node>();
List<Node> closedList = new ArrayList<Node>();
Gdx.app.log(PArena.LOG, "Lists Created");
currentNode = new Node(null, start);
openList.add(currentNode);
Gdx.app.log(PArena.LOG, "Added start to openList");
// check squares around this and add
int startPX = (int) currentNode.parentV.x / 32;
Gdx.app.log(PArena.LOG, "Start X" + startPX);
int startPY = (int) currentNode.parentV.y / 32;
Gdx.app.log(PArena.LOG, "Start Y" + startPY);
Gdx.app.log("", "");
//
int MIN_X = startPX - 1;
int MIN_Y = startPY - 1;
int MAX_X = startPX + 1;
int MAX_Y = startPY + 1;
int startPosX = (startPX - 1 < MIN_X) ? startPX : startPX - 1;
int startPosY = (startPY - 1 < MIN_Y) ? startPY : startPY - 1;
int endPosX = (startPX + 1 > MAX_X) ? startPX : startPX + 1;
int endPosY = (startPY + 1 > MAX_Y) ? startPY : startPY + 1;
// Check boundaries on start cell
for (int rowNum = startPosX; rowNum <= endPosX; rowNum++) {
for (int colNum = startPosY; colNum <= endPosY; colNum++) {
// All the neighbors will be grid[rowNum][colNum]
if (!cells[rowNum][colNum].getTile().getProperties()
.containsKey("blocked")) {
Node node = new Node(currentNode, new Vector2(
rowNum, colNum));
if (rowNum != startPX && colNum != startPY) {
node.setMovementCost(14);
} else
node.setMovementCost(10);
openList.add(node);
System.out.print(node.getFValue() + "|");
} else
System.out.print("B");
}
System.out.println("");
}
openList.remove(currentNode);
closedList.add(currentNode);
int n = openList.get(0).getFValue();
int index = 0;
for (Node temp : openList) {
if (temp.getFValue() < n) {
n = temp.getFValue();
index = openList.lastIndexOf(temp);
Gdx.app.log("n", "n = " + n);
}
}
currentNode = openList.get(index);
arena.colorSquare(currentNode.getVectorPos());
// need to calc move cost;
//
Gdx.app.log("", "");
openList.clear();
closedList.clear();
}
This is my Node class
public static class Node {
int hVal;
int gVal;
int fVal;
Node parentNode;
Vector2 parentV;
private Node(Node node, Vector2 p) {
setParent(node);
this.parentV = p;
calcHValue();
}
public void setMovementCost(int c) {
this.gVal = c;
calcFVal();
}
private void calcFVal() {
fVal = gVal + hVal;
// Gdx.app.log("Node", "HVal = " + hVal);
// Gdx.app.log("Node", "GVal = " + gVal);
// Gdx.app.log("Node", "FVal = " + fVal);
}
private void calcHValue() {
int x = (int) (parentV.x - end.x);
if (x < 0)
x *= -1;
int y = (int) (parentV.y - end.y);
if (y < 0)
y *= -1;
hVal = (int) (x + y) / 32;
// Gdx.app.log(PArena.LOG, "Heuristic Value" + hVal);
}
private void setParent(Node node) {
this.parentNode = node;
}
public int getFValue() {
return fVal;
}
public Vector2 getVectorPos() {
return parentV;
}
}
My problem is that my debugging outputs like this
15|11|15|
11|11|11|
15|11|15|
So basically it isnt actually calculating the total value. It is just adding the movement cost, not heuristic.
What is th problem? Am i missing a step?
You are missing the Successor list i think. An A* does have a Successorlist and while the openlist isnt empty you do the following stuff:
while (openList.size() != 0) {
successor.clear();
q = openList.remove(); //first element of the prio queue
// generate your neighbornodes of q and add them to the successorlist
//after this you iterate over the successor and check if its your goalnode.
//If so you do return it else you add it to the openlist. (still inside of the while!)
//Dont forget to check if the neighbor is inside of the close list!
//if so you do not need to add it to the successorlist
//Here is how it does look at mine A*. It also contains a check if there is a betterone
// calc
for (Node suc : successor) {
if (suc.x == (int) this.screen.character.mapPos.x
&& suc.y == (int) this.screen.character.mapPos.y)
return suc; //return the goalnode
boolean add = true;
if (betterIn(suc, openList))
add = false;
if (betterIn(suc, closeList))
add = false;
if (add)
openList.add(suc);
}
Last but not least you do delete the q note from the openlist and add it to the close ist.
}
closeList.add(q);
}//end of while
Some more minor improvmements would be that you do add a compareable to the Node..
#Override
public int compareTo(Node o) {
if ((this.g + this.h) < (o.g + o.h))
return -1;
else if ((this.g + this.h) >= (o.g + o.h))
return 1;
else
return 0;
}
also override the equals and the hashCode method for it for example like this:
#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() {
return x + y;
}
After that your openList can be a PriorityQueue<Node> and the first object you are getting from the is always the one with the smallest h.
Dont forget to return our final Node to iterate over the getparent method to get the path.
private boolean betterIn(Node n, Collection<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;
}
Related
I am trying to build a max heap java class for item objects, so I can solve the knapsack problem and implement greedy algorithms to do so. Item class includes weight, value, Id(to distinguish items), and most importantly a priority factor:
public class Items {
double weight;
double value;
double priorityFactor;
int ID;
//constructor for items class
public Items(int weight, int value, int id, int priorityFactor)
{
this.weight=weight;
this.value=value;
this.ID=id;
this.priorityFactor = priorityFactor;
} //end constructor
Now the issue that I'm facing is in the max heap class, which is supposed to build me a max heap tree based on the priority factor. Means that I should have an array of item objects: private Items[] array
What I'm finding difficult to implement is how can I insert those items in the array based on the priority factor. If I do this, I think I will be able to implement the greedy algorithms. How to handle this?
This is the basic code for a min/max heap (depending on the T:compareTo() method).
This only handles insertion, but I think it's what you're after.
package jc.lib.container.collection.set;
import jc.lib.lang.string.JcStringBuilder;
public class JcHeap<T extends Comparable<T>> {
private T[] mItems;
private int mItemCount = 0;
#SuppressWarnings("unchecked") public JcHeap(final int pStartCapacity) {
mItems = (T[]) new Comparable[pStartCapacity];
}
private void checkResize() {
if (mItems.length <= mItemCount) {
final int newSize = (mItems.length) * 2;
#SuppressWarnings("unchecked") final T[] tmp = (T[]) new Comparable[newSize];
if (mItems != null) System.arraycopy(mItems, 0, tmp, 0, mItemCount);
mItems = tmp;
}
}
static private int getParentIndex(final int pCurrentIndex) {
return (pCurrentIndex - 1) / 2;
}
#SuppressWarnings("unused") static private int getLeftChildIndex(final int pCurrentIndex) {
return 2 * pCurrentIndex + 1;
}
#SuppressWarnings("unused") static private int getRightChildIndex(final int pCurrentIndex) {
return 2 * pCurrentIndex + 2;
}
public void addItem(final T pItem) {
checkResize();
// insert
System.out.println("\nInserting " + pItem);
T current = pItem;
int currentIndex = mItemCount;
mItems[currentIndex] = current;
++mItemCount;
// sort
while (true) { // swap up
if (currentIndex <= 0) break;
final int parentIndex = getParentIndex(currentIndex);
final T parent = mItems[parentIndex];
System.out.print("Checking cur:" + current + " vs par:" + parent + " => " + current.compareTo(parent) + "/");
if (current.compareTo(parent) >= 0) {
System.out.println("break");
break;
}
System.out.println("swap");
System.out.println("Swapping with parent: " + parent);
final T tmp = mItems[parentIndex];
mItems[parentIndex] = mItems[currentIndex];
mItems[currentIndex] = tmp;
currentIndex = parentIndex;
current = mItems[currentIndex];
}
}
// public boolean contains(final T pItem) {
// final int index = findIndex(pItem);
// return 0 <= index && index < mItemCount;
// }
//
// public int findIndex(final T pItem) {
// int index = 0;
// int width = mItemCount;
//
// while (true) {
// System.out.println("Comparing with index " + index);
// final int cmp = pItem.compareTo(mItems[index]);
// if (cmp == 0) return index;
// else if (cmp > 0) return -1;
//
// index += mItemCount;
// width /= 2;
// if (width == 0) return -1;
// }
// }
#Override public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("\nTree View:\n");
int height = (int) (Math.log(mItemCount) / Math.log(2));
sb.append("count=" + mItemCount + " height=" + height);
int next = 1;
sb.append("\n[");
sb.append(JcStringBuilder.buildFromArray(", ", (Object[]) mItems));
// for (int c = 0; c < mItemCount; c++) {
// sb.append("\n" + mItems);
// }
sb.append("]");
for (int c = 0; c < mItemCount; c++) {
if (c + 2 > next) {
sb.append("\n");
for (int d = 0; d < height; d++) {
sb.append("\t");
}
height -= 1;
next *= 2;
// System.out.println("Next is " + next);
}
sb.append("<" + mItems[c] + ">\t");
}
return sb.toString() + "\n";
}
}
In a number maze, a player always starts from the square at the upper left and makes a certain number of moves which will take him/her to the square marked Goal if a solution exist. The value in each cell in the maze indicates how far a player must move horizontally or vertically from its current position.
My task is to find out if the shortest path to the cell labeled “Goal” and print it.
Input
the maze is in the form of square 2D array. The goal square is indicated by the number -1 in the maze description.
Output
For the maze, output the solution of the maze or the phrase “No Solution Possible.” Solutions should be output as a list of square coordinates in the format “(Row, Column)”, in the order in which they are visited from the start to the goal, including the starting cell. You will need to report the shortest solution from start to the goal. The shortest solution will be unique.
I have tried some solution, but I think there is problem that is the solution is always the first path I found not the shortest..
public class findShoretstPath
{
private static Stack<Node> stack = new Stack<>();
private static class Node
{
private int[] coordinate = new int[2];
private int data;
private Node Right, Left, Top, Bottom;
public Node(){}
}
public static boolean isValid(int[][] a, int x, int y)
{
if(x >= 0 && x < a.length && y >= 0 && y < a.length)
return true;
return false;
}
public static Node[][] nodeArray(int[][] a)
{
Node[][] nodeA = new Node[a.length][a.length];
for(int i = 0; i<nodeA.length; i++)
for(int j = 0; j<nodeA[i].length; j++)
{
nodeA[i][j] = new Node();
nodeA[i][j].coordinate[0] = i;
nodeA[i][j].coordinate[1] = j;
nodeA[i][j].data = a[i][j];
}
for(int i = 0; i<nodeA.length; i++)
for(int j = 0; j<nodeA[i].length; j++)
{
if(isValid(a, i, j+nodeA[i][j].data))
nodeA[i][j].Right = nodeA[i][j+nodeA[i][j].data];
if(isValid(a, i, j-nodeA[i][j].data))
nodeA[i][j].Left = nodeA[i][j-nodeA[i][j].data];
if(isValid(a, i+nodeA[i][j].data, j))
nodeA[i][j].Bottom = nodeA[i+nodeA[i][j].data][j];
if(isValid(a, i-nodeA[i][j].data, j))
nodeA[i][j].Top = nodeA[i-nodeA[i][j].data][j];
}
return nodeA;
}
public static boolean findPath(Node[][] s, int[][] t, int x, int y)
{
boolean b = false;
if(t[x][y] == 0)
{
t[x][y] = 1;
if(s[x][y].data == -1) b = true;
else
{
if(s[x][y].Right != null) b = findPath(s, t, x, y+s[x][y].data);
if(!b && s[x][y].Bottom != null) b = findPath(s, t, x+s[x][y].data, y);
if(!b && s[x][y].Left != null) b = findPath(s, t, x, y-s[x][y].data);
if(!b && s[x][y].Top != null) b = findPath(s, t, x-s[x][y].data, y);
}
if(b) stack.add(s[x][y]);
}
return b;
}
public static void main(String[] args)
{
int[][] maze = {{1,1,1,1,1},
{1,1,1,1,1},
{1,1,1,1,1},
{1,1,1,1,3},
{4,1,1,3,-1}};
Node[][] net = nodeArray(maze);
int[][] path = new int[maze.length][maze[0].lenght];
if(findPath(net, path, 0, 0))
{
Node temp;
while(!stack.isEmpty())
{
temp = stack.pop();
System.out.print("("+temp.coordinate[0]+" "+temp.coordinate[1]+") ");
}
}
else System.out.println("No Solution Possible.");
}
}
for this example the output should be:
(0 0) (1 0) (2 0) (3 0) (4 0) (4 4)
but I have this output:
(0 0) (0 1) (0 2) (0 3) (0 4) (1 4) (2 4) (3 4) (3 1) (3 2) (3 3) (4 3) (4 0) (4 4)
Please, any help how to fix the code so the solution will be the shortest path?!
After searching about BFS, now I know the difference between DFS and BFS.
DFS algorithm travels a path from the source to the last node, if the goal is found stop, else try another path again from the source to the last node, and so until the goal is reached. While BFS algorithm travels from the source to the level below, if the goal is found stop, else go to the next level and so on..
For my problem, BFS is a suitable algorithm to find the shortest path.
The code after some modifications:
public class findShoretstPath
{
private static class Node
{
private int[] coordinate = new int[2];
private int data;
private Node Right, Left, Top, Bottom;
public Node(){}
}
public static boolean isLinked(Node s, Node d) //method to determine if the node d is linked to the node s
{
if(d.Right == s) return true;
if(d.Bottom == s) return true;
if(d.Left == s) return true;
if(d.Top == s) return true;
return false;
}
public static boolean isValid(int[][] a, int x, int y)
{
if(x >= 0 && x < a.length && y >= 0 && y < a.length)
return true;
return false;
}
public static Node[][] nodeArray(int[][] a)
{
Node[][] nodeA = new Node[a.length][a.length];
for(int i = 0; i<nodeA.length; i++)
for(int j = 0; j<nodeA[i].length; j++)
{
nodeA[i][j] = new Node();
nodeA[i][j].coordinate[0] = i;
nodeA[i][j].coordinate[1] = j;
nodeA[i][j].data = a[i][j];
}
for(int i = 0; i<nodeA.length; i++)
for(int j = 0; j<nodeA[i].length; j++)
{
if(isValid(a, i, j+nodeA[i][j].data))
nodeA[i][j].Right = nodeA[i][j+nodeA[i][j].data];
if(isValid(a, i, j-nodeA[i][j].data))
nodeA[i][j].Left = nodeA[i][j-nodeA[i][j].data];
if(isValid(a, i+nodeA[i][j].data, j))
nodeA[i][j].Bottom = nodeA[i+nodeA[i][j].data][j];
if(isValid(a, i-nodeA[i][j].data, j))
nodeA[i][j].Top = nodeA[i-nodeA[i][j].data][j];
}
return nodeA;
}
public static void shortestPath(Node[][] nodes, int x, int y)
{
Stack<Node> stack = new Stack<>();
Queue<Node> queue = new LinkedList<>();
int[][] path = new int[nodes.length][nodes[0].length];
boolean b = false;
int level = 1;//to keep tracking each level viseted
queue.add(nodes[x][y]);
path[x][y] = level;
while(!queue.isEmpty())
{
Node temp;
level++;
int size = queue.size();
for(int i = 0; i<size; i++)
{
temp = queue.remove();
if(temp.data == -1) {b = true; break;}
if(temp.Right != null && path[temp.Right.coordinate[0]][temp.Right.coordinate[1]] == 0)
{
queue.add(temp.Right);
path[temp.Right.coordinate[0]][temp.Right.coordinate[1]] = level;
}
if(temp.Bottom != null && path[temp.Bottom.coordinate[0]][temp.Bottom.coordinate[1]] == 0)
{
queue.add(temp.Bottom);
path[temp.Bottom.coordinate[0]][temp.Bottom.coordinate[1]] = level;
}
if(temp.Left != null && path[temp.Left.coordinate[0]][temp.Left.coordinate[1]] == 0)
{
queue.add(temp.Left);
path[temp.Left.coordinate[0]][temp.Left.coordinate[1]] = level;
}
if(temp.Top != null && path[temp.Top.coordinate[0]][temp.Top.coordinate[1]] == 0)
{
queue.add(temp.Top);
path[temp.Top.coordinate[0]][temp.Top.coordinate[1]] = level;
}
}
if(b) break;
}
if(b)
{
int x1 = 0, y1 = 0;
for(int i = 0; i<nodes.length; i++)// to locate the position of the goal
for(int j = 0; j<nodes.length; j++)
if(nodes[i][j].data == -1)
{
x1 = i; y1 = j;
}
stack.add(nodes[x1][y1]);
int d = path[x1][y1];
while(d > 0)//go back from the goal to the source
{
for(int i = 0; i<path.length; i++)
{
if(path[x1][i] == d-1 && isLinked(nodes[x1][y1], nodes[x1][i]))
{
stack.add(nodes[x1][i]);
y1 = i;
break;
}
else if(path[i][y1] == d-1 && isLinked(nodes[x1][y1], nodes[i][y1]))
{
stack.add(nodes[i][y1]);
x1 = i;
break;
}
}
d--;
}
Node temp;
int stackSize = stack.size();
for(int i = 0; i<stackSize; i++)// print the final result
{
temp = stack.pop();
System.out.print("("+temp.coordinate[0]+" "+temp.coordinate[1]+") ");
}
}
else System.out.print("No Solution Possible.");
}
public static void main(String[] args)
{
int[][] maze = {{1,1,1,1,1},
{1,1,1,1,1},
{1,1,1,1,1},
{1,1,1,1,3},
{4,1,1,3,-1}};
Node[][] net = nodeArray(maze);
shortestPath(net, 0, 0));
System.out.println("");
}
}
and the output now is:
(0 0) (1 0) (2 0) (3 0) (4 0) (4 4)
I'm currently working on a project where I have to create a max heap. I'm currently using my textbooks version of the heap which somewhat looks like:
public MaxHeap(int initialCapacity) {
if (initialCapacity < DEFAULT_CAPACITY)
initialCapacity = DEFAULT_CAPACITY;
else
checkCapacity(initialCapacity);
#SuppressWarnings("unchecked")
T[] tempHeap = (T[]) new Comparable[initialCapacity + 1];
heap = tempHeap;
lastIndex = 0;
initialized = true;
}
public T getMax() {
checkInitialization();
T root = null;
if (!isEmpty())
root = heap[1];
return root;
}
public boolean isEmpty() {
return lastIndex < 1;
}
public int getSize() {
return lastIndex;
}
public void clear() {
checkInitialization();
while (lastIndex > -1) {
heap[lastIndex] = null;
lastIndex--;
}
lastIndex = 0;
}
public void add(T newEntry) {
checkInitialization();
int newIndex = lastIndex + 1;
int parentIndex = newIndex / 2;
while ((parentIndex > 0) && newEntry.compareTo(heap[parentIndex]) > 0) {
heap[newIndex] = heap[parentIndex];
newIndex = parentIndex;
parentIndex = newIndex / 2;
}
heap[newIndex] = newEntry;
lastIndex++;
ensureCapacity();
}
public int getSwaps()
{
return swaps;
}
public T removeMax() {
checkInitialization();
T root = null;
if (!isEmpty()) {
root = heap[1];
heap[1] = heap[lastIndex];
lastIndex--;
reheap(1);
}
return root;
}
private void reheap(int rootIndex) {
boolean done = false;
T orphan = heap[rootIndex];
int leftChildIndex = 2 * rootIndex;
while (!done && (leftChildIndex <= lastIndex)) {
int largerChildIndex = leftChildIndex;
int rightChildIndex = leftChildIndex + 1;
if ((rightChildIndex <= lastIndex) && heap[rightChildIndex].compareTo(heap[largerChildIndex]) > 0) {
largerChildIndex = rightChildIndex;
}
if (orphan.compareTo(heap[largerChildIndex]) < 0) {
heap[rootIndex] = heap[largerChildIndex];
rootIndex = largerChildIndex;
leftChildIndex = 2 * rootIndex;
} else
done = true;
}
heap[rootIndex] = orphan;
}
Am I supposed to count the swaps in multiple places and print the total amount and if so where would i count them? I had previously tried to just enumerate swaps++ in the add method but i don't think that is the proper way of doing it.
You have to count the swap in both the add(T newEntry) method and reHeap method which is called from removeMax mathod.
In reHeap you start from the top and as you call it from removeMax where after removing the max(in Max Heap case) you replace the root with the last element and then you need to balance the heap. So the heap recursively goes down till the last level to balance which may require swap.
EDIT:
Add the swap inside following code block of reHeap:
if (orphan.compareTo(heap[largerChildIndex]) < 0) {
heap[rootIndex] = heap[largerChildIndex];
rootIndex = largerChildIndex;
leftChildIndex = 2 * rootIndex;
// increment the swap here as inside this block of reHeap only swap takes place.
swap++
}
Would these be the correct way of implementing it?
So the add method would be:
public void add(T newEntry) {
checkInitialization();
int newIndex = lastIndex + 1;
int parentIndex = newIndex / 2;
while ((parentIndex > 0) && newEntry.compareTo(heap[parentIndex]) > 0) {
heap[newIndex] = heap[parentIndex];
newIndex = parentIndex;
parentIndex = newIndex / 2;
swap++;
}
heap[newIndex] = newEntry;
lastIndex++;
ensureCapacity();
}
and the reheap would be:
private void reheap(int rootIndex) {
boolean done = false;
T orphan = heap[rootIndex];
int leftChildIndex = 2 * rootIndex;
while (!done && (leftChildIndex <= lastIndex)) {
int largerChildIndex = leftChildIndex;
int rightChildIndex = leftChildIndex + 1;
if ((rightChildIndex <= lastIndex) && heap[rightChildIndex].compareTo(heap[largerChildIndex]) > 0) {
largerChildIndex = rightChildIndex;
}
if (orphan.compareTo(heap[largerChildIndex]) < 0) {
heap[rootIndex] = heap[largerChildIndex];
rootIndex = largerChildIndex;
leftChildIndex = 2 * rootIndex;
swap++;
} else
done = true;
}
heap[rootIndex] = orphan;
}
Whats up guys, I have a question regarding the Dijkstra algorithm. I have made it so that a user enter a graph file, and then the user enters the source node and destination node. And my code so far calculates the shortest distance between them, like it's supposed to. However I do not know to print the path of nodes it goes through in order to get to the destination node. Please help this is a homework assignment due today. Here is my code:
package minheap;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class MinHeap {
private int veNum;
private int x;
private int y;
private Vertex[] vertices;
private int size;
public static void main(String[] args) throws FileNotFoundException{
Scanner input = new Scanner(System.in);
System.out.println("%%%%%%Enter the name of the file that contains the graph");
String file = input.nextLine();
MinHeap minHeap = new MinHeap(file);
System.out.println("What city would you like to start from?(Please enter a number "
+ "from 0 to 87574)");
int start = Integer.parseInt(input.nextLine());
System.out.println("What city would you like to get to?(Please enter a number "
+ "from 0 to 87574)");
int end = Integer.parseInt(input.nextLine());
minHeap.findShortestPaths(start, end);
}
public MinHeap(String file) throws FileNotFoundException {
Scanner input = new Scanner(new File(file));
String sizeString = input.next(); //get the size as a string
size = Integer.parseInt(sizeString);
System.out.println("======The size is: " + size);
vertices = new Vertex[size];
// addNodes();
input.next();
/*Now read the vertices*/
for(int i = 0; i < vertices.length; i++){
veNum = Integer.parseInt(input.next());
x = Integer.parseInt(input.next());
y = Integer.parseInt(input.next());
vertices[i] = new Vertex(veNum, x, y);
}
/*Now read the edges */
while(input.hasNext()){
int vertex1 = indexForName(input.next());
int vertex2 = indexForName(input.next());
//System.out.println("====" + vertex1 + "====" + vertex2);
/*Formula to calculate the distance(weight)*/
int distance = (int) Math.sqrt(Math.pow(vertices[vertex1].xCord - vertices[vertex2].xCord, 2)
+ Math.pow(vertices[vertex1].yCord - vertices[vertex2].yCord, 2));
/*Pass the 2 vertexes that make an edge, and their distance to addEdge method*/
addEdge(vertex1, vertex2, distance);
/*System.out.println("X cord: " + vertices[vertex1].xCord + "| Y cord: " + vertices[vertex1].yCord +
"| X cord2: " + vertices[vertex2].xCord + "| Y cord2: " + vertices[vertex2].yCord);
*/
}
}
//======================================================================================================
int indexForName(String name){
for(int i = 0; i < vertices.length; i++){
/*Look for the vertex name in the array to see if they match with the one the one from
the file */
if(vertices[i].name == Integer.parseInt(name)){
return i;
}
}
return -1;
}
//===============================================================================================================
public void addEdge(int sourceName, int destinationName, int weight) {
int srcIndex = sourceName;
int destiIndex = destinationName;
vertices[srcIndex].adj = new Neighbour(destiIndex, weight, vertices[srcIndex].adj);
vertices[destiIndex].indegree++;
}
public void findShortestPaths(int sourceName, int end){
for (int i = 0; i < size; i++) {
if (vertices[i].name == sourceName) {
applyDikjstraAlgorith(vertices[i], vertices[end]);
break;// in this case we need not traverse the nodes which are
// not reachable from the source Node
}
}
//applyDikjstraAlgorith(vertices[sourceName], vertices[end]);
// for(int i = 0; i < size; i++){
// System.out.println("Distance of "+vertices[i].name+" from Source: "+ vertices[i].cost);
//}
}
public class Vertex {
int cost;
int name;
Neighbour adj;
int indegree;
State state;
int xCord;
int yCord;
public Vertex(int name, int xCord, int yCord) {
this.name = name;
cost = Integer.MAX_VALUE;
state = State.NEW;
this.xCord = xCord;
this.yCord = yCord;
}
public int compareTo(Vertex v) {
if (this.cost == v.cost) {
return 0;
}
if (this.cost < v.cost) {
return -1;
}
return 1;
}
}
public enum State {
NEW, IN_Q, VISITED
}
public class Neighbour {
int index;
Neighbour next;
int weight;
Neighbour(int index, int weight, Neighbour next) {
this.index = index;
this.next = next;
this.weight = weight;
}
}
public void applyDikjstraAlgorith(Vertex src, Vertex end) {
Heap heap = new Heap(size);
heap.add(src);
src.state = State.IN_Q;
src.cost = 0;
while (!heap.isEmpty()) {
Vertex u = heap.remove();
u.state = State.VISITED;
Neighbour temp = u.adj; //the neighbor of the vertex being removed. it accesses it adj neighbor list
System.out.println("=======Edge weights");
while (temp != null) { //while it has a neighbor
if (vertices[temp.index].state == State.NEW) { //if that neighbor is unvisited
heap.add(vertices[temp.index]); //add the unvisited vertices to the heap
vertices[temp.index].state = State.IN_Q; //make the state indicating its in the heap
}
System.out.println("Weight from "+ vertices[u.name].name + " to " + vertices[temp.index].name +" is "+ temp.weight);
if (vertices[temp.index].cost > u.cost + temp.weight) { //if the neighbors weight is less than
vertices[temp.index].cost = u.cost + temp.weight;
heap.heapifyUP(vertices[temp.index]);
}
temp = temp.next;
}
}
System.out.println();
System.out.println("The shortest distance from "+src.name +" to "+end.name+" is "
+ end.cost);
}
public static class Heap {
private Vertex[] heap;
private int maxSize;
private int size; //starts off as 0
public Heap(int maxSize) {
this.maxSize = maxSize;
heap = new Vertex[maxSize]; //make the max size for the heap array made of vertices
}
public void add(Vertex u) {
heap[size++] = u; //fill the heap array with the vertices, starting at position 0
//
heapifyUP(size - 1); //pass each vertext ino heapifyUP (vertex type)
}
public void heapifyUP(Vertex u) {
for (int i = 0; i < maxSize; i++) { //look for vertex in the heap array
if (u == heap[i]) {
heapifyUP(i); //if its found, go to heapifyUp method (int type) and pass in the vertex num
break;
}
}
}
public void heapifyUP(int position) {
int currentIndex = position;
Vertex currentItem = heap[currentIndex];
int parentIndex = (currentIndex - 1) / 2;
Vertex parentItem = heap[parentIndex];
while (currentItem.compareTo(parentItem) == -1) {
swap(currentIndex, parentIndex);
currentIndex = parentIndex;
if (currentIndex == 0) {
break;
}
currentItem = heap[currentIndex];
parentIndex = (currentIndex - 1) / 2;
parentItem = heap[parentIndex];
}
}
public Vertex remove() {
Vertex v = heap[0];
swap(0, size - 1);
heap[size - 1] = null;
size--;
heapifyDown(0);
return v;
}
public void heapifyDown(int postion) {
if (size == 1) {
return;
}
int currentIndex = postion;
Vertex currentItem = heap[currentIndex];
int leftChildIndex = 2 * currentIndex + 1;
int rightChildIndex = 2 * currentIndex + 2;
int childIndex;
if (heap[leftChildIndex] == null) {
return;
}
if (heap[rightChildIndex] == null) {
childIndex = leftChildIndex;
} else if (heap[rightChildIndex].compareTo(heap[leftChildIndex]) == -1) {
childIndex = rightChildIndex;
} else {
childIndex = leftChildIndex;
}
Vertex childItem = heap[childIndex];
while (currentItem.compareTo(childItem) == 1) {
swap(currentIndex, childIndex);
currentIndex = childIndex;
currentItem = heap[currentIndex];
leftChildIndex = 2 * currentIndex + 1;
rightChildIndex = 2 * currentIndex + 2;
if (heap[leftChildIndex] == null) {
return;
}
if (heap[rightChildIndex] == null) {
childIndex = leftChildIndex;
} else if (heap[rightChildIndex].compareTo(heap[leftChildIndex]) == -1) {
childIndex = rightChildIndex;
} else {
childIndex = leftChildIndex;
}
}
}
public void swap(int index1, int index2) {
Vertex temp = heap[index1];
heap[index1] = heap[index2];
heap[index2] = temp;
}
public boolean isEmpty() {
return size == 0;
}
}
}
The sample.txt file is as follows:
6 9
0 1000 2400
1 2800 3000
2 2400 2500
3 4000 0
4 4500 3800
5 6000 1500
0 1
0 3
1 2
1 4
2 4
2 3
2 5
3 5
Again, the actual algorithm works, I just need help printing the path. Thanks in advance
I'm writing a sliding block solver that has a list of block objects (which contains block size and location of upper left corner), and a 2D array that represents the tray. Wherever there is a block, that location in the array points to the block object, otherwise it is null.
In my solver I'm generating possible moves that haven't been seen, hashing them, then choosing one to do (which changes the tray layout) and calling the solver recursively on the new tray layout. When there are no more possible move layouts that haven't been seen before I return the call, reverse the last move and continue checking the previous call, and so on until either it is solved or I run out of moves (no solution).
The problem is, I'm getting a Null Pointer Exception when I make a move. The weird thing is that it only happens after quite a few recursive calls. The program runs through several calls/moves fine, and then it seems to mess up.
generateMoves() tests if a move has been seen before by calling move(), and then reversing the move once it has checked. I think the Null Pointer is happening after it calls move(), and move() is setting toMove = layout[][]. Evidently it is looking up a position in the array that is null instead of one with the block. It seems there is a discrepancy between the list of blocks and the Tray array... Because when move() then calls setTrayAfterMove() it throws the exception. What I can't figure out is why it works for several recursive calls to solveHelper() but then breaks.
import java.io.*;
import java.util.*;
public class Solver {
Tray initial;
Tray goal;
HashSet<Integer> visited;
LinkedList<Integer> movesToSolution; // list of moves leading to solution
int recursionCounter;
boolean isSolved;
public Solver(String initial, String goal) {
this.initial = new Tray(initial);
this.goal = new Tray(this.initial, goal);
visited = new HashSet<Integer>();
movesToSolution = new LinkedList<Integer>();
recursionCounter = 0;
isSolved = false;
}
public void solve() {
if (goal.equals(initial)) {
System.out.println("Solver finished no moves");
return;
}
solveHelper(initial);
if (movesToSolution.isEmpty()) {
System.out.println("No solution");
System.exit(1);
}
printMoves();
System.out.println("Solver finished");
}
private void solveHelper(Tray t) {
Stack<Integer> possibleMoves = new Stack<Integer>();
int lastMoveMade = 0;
if (recursionCounter > 5000 || isSolved) {
return;
}
if (goal.equals(t)) {
isSolved = true;
// movesToSolution.addFirst(lastMoveMade);
return;
}
recursionCounter++;
LinkedList<Integer> movesToAdd = t.generateMoves();
Iterator<Integer> movesIter = movesToAdd.iterator();
while (movesIter.hasNext()) {
possibleMoves.push(movesIter.next());
}
while (!possibleMoves.isEmpty()) {
lastMoveMade = possibleMoves.pop();
boolean isMoved = t.move(lastMoveMade, false);
if (isMoved) {
int moveHash = t.hashCode();
visited.add(moveHash);
solveHelper(t);
}
if (isSolved) {
movesToSolution.addFirst(lastMoveMade);
return;
}
}
t.move(lastMoveMade, true);
return;
}
public void printMoves() {
for (Integer move : movesToSolution) {
System.out.println(move);
}
}
public class Tray {
private int length; // number of rows
private int width; // number of columns
private LinkedList<Block> blocks;
private Block[][] layout;
public Tray(String file) {
blocks = new LinkedList<Block>();
try {
Scanner s = new Scanner(new FileReader(file));
length = s.nextInt();
width = s.nextInt();
layout = new Block[width][length];
while (s.hasNextLine()) {
int l = s.nextInt();
int w = s.nextInt();
int r = s.nextInt();
int c = s.nextInt();
Block b = new Block(l, w, r, c);
blocks.add(b);
for (int blockX = b.col; blockX < b.col + b.width; blockX++) {
for (int blockY = b.row; blockY < b.row + b.length; blockY++) {
layout[blockX][blockY] = b;
}
}
s.nextLine();
// isOK();
}
} catch (FileNotFoundException e) {
System.out.println("File not found");
}
}
public Tray(Tray t, String file) {
blocks = new LinkedList<Block>();
try {
this.length = t.length;
this.width = t.width;
Scanner s = new Scanner(new FileReader(file));
layout = new Block[this.width][this.length];
while (s.hasNextLine()) {
int l = s.nextInt();
int w = s.nextInt();
int r = s.nextInt();
int c = s.nextInt();
Block b = new Block(l, w, r, c);
blocks.add(b);
for (int blockX = b.col; blockX < b.col + b.width; blockX++) {
for (int blockY = b.row; blockY < b.row + b.length; blockY++) {
layout[blockX][blockY] = b;
}
}
s.nextLine();
// isOK();
}
} catch (FileNotFoundException e) {
System.out.println("File not found");
}
}
public void print() {
for (Block b : blocks) {
System.out.println(b.length + " " + b.width + " " + b.col + " "
+ b.row);
}
}
public boolean equals(Object o) {
for (int x = 0; x < this.width; x++) {
for (int y = 0; y < this.length; y++) {
if (this.layout[x][y] != null
&& (((Tray) o).layout[x][y] == null || !((Tray) o).layout[x][y]
.equals(this.layout[x][y]))) {
return false;
}
}
}
return true;
}
public int hashCode() {
// TODO come up with hashcode unique to layout taking in
// consideration block at each coordinate, size of block
int hashCode = 0;
for (Block b : blocks) {
hashCode += (17 * (b.width * b.col)) + (7 * (b.length * b.row));
}
return hashCode;
}
public boolean isOK() {
Block[][] trayChecker = new Block[width][length];
Iterator<Block> blockIter = blocks.iterator();
while (blockIter.hasNext()) {
Block b = blockIter.next();
for (int x = b.col; x < x + b.width; x++) {
for (int y = b.row; y < y + b.length; y++) {
if (trayChecker[x][y] != null) {
throw new IllegalStateException(
"Two blocks cannot be in the same location");
}
if (x < 0 || x > width || y < 0 || y > length) {
throw new IllegalStateException(
"Block must be completely on the board");
}
trayChecker[x][y] = b;
}
}
}
return true;
}
// only returns possible valid moves that haven't been seen before
public LinkedList<Integer> generateMoves() {
LinkedList<Integer> movesToTry = new LinkedList<Integer>();
// TODO: generate moves that haven't been seen
int[] moveDir = { -10, 10, -1, 1 };
for (Block b : blocks) {
for (int m : moveDir) {
if (canMove(b, m)) {
int trayMove = createMove(b, m);
move(trayMove, false);
if (!visited.contains(hashCode())) {
movesToTry.add(trayMove);
}
move(trayMove, true); // reverse the move
}
}
}
return movesToTry;
}
public boolean canMove(Block b, int dir) {
int tmp = Math.abs(dir);
int y = tmp % 10;
int x = tmp / 10;
if (dir < 0) {
x = -x;
y = -y;
}
if ((b.col + x < 0 || b.col + b.width + x > this.width)
|| (b.row + y < 0 || b.row + b.length + y > this.length)) {
return false;
}
if (x == 0) {
for (int xBlock = b.col; xBlock < b.col + b.width; xBlock++) {
if (layout[xBlock][b.row + y] != null) {
return false;
}
// } else if(x > 0 && layout[xBlock][b.row + y + b.length -
// 1] != null) {
// return false;
// }
}
}
if (y == 0) {
for (int yBlock = b.row; yBlock < b.row + b.length; yBlock++) {
if (layout[b.col + x][yBlock] != null) {
return false;
}
// } else if(x > 0 && layout[b.col + x + b.width -
// 1][yBlock] != null) {
// return false;
// }
}
}
return true;
}
// only takes valid input
public boolean move(int moveDirections, boolean reverse) {
Block toMove = null;
if (moveDirections == 0) {
return false;
}
// System.out.println(moveDirections + " " + recursionCounter);
int tmp = Math.abs(moveDirections);
int moveY = tmp % 10;
tmp /= 10;
int moveX = tmp % 10;
tmp /= 10;
int blockY = tmp % 1000;
tmp /= 1000;
int blockX = tmp;
System.out.println(blockX + " + " + blockY);
if (reverse) {
if (moveDirections > 0) {
toMove = layout[blockX + moveX][blockY + moveY];
} else {
toMove = layout[blockX - moveX][blockY - moveY];
}
setTrayAfterMove(toMove, true);
if (moveDirections < 0) {
toMove.col += moveX;
toMove.row += moveY;
} else {
toMove.col -= moveX;
toMove.row -= moveY;
}
setTrayAfterMove(toMove, false);
} else {
toMove = layout[blockX][blockY];
setTrayAfterMove(toMove, true);
if (moveDirections < 0) {
toMove.col -= moveX;
toMove.row -= moveY;
} else {
toMove.col += moveX;
toMove.row += moveY;
}
setTrayAfterMove(toMove, false);
}
return true;
// 256x256
// 1x256 23x256
// 100x01 100x001 100x100
// 1x01 1x001 1x100
// 10x01 10x001 10x100
}
private int createMove(Block b, int dir) {
// multiply b.x to get 8 digits
// multiply bh .y to get 5 digits
int move = b.col * 100000;
move += (b.row * 100);
move += Math.abs(dir);
if (dir < 0) {
move *= -1;
}
return move;
}
private void setTrayAfterMove(Block b, boolean isBeforeMove) {
for (int blockX = b.col; blockX < b.col + b.width; blockX++) {
for (int blockY = b.row; blockY < b.row + b.length; blockY++) {
if(isBeforeMove) {
layout[blockX][blockY] = null;
} else {
layout[blockX][blockY] = b;
}
}
}
}
}
public class Block {
private int length;
private int width;
private int row;
private int col;
public Block(int l, int w, int r, int c) {
length = l;
width = w;
row = r;
col = c;
}
public boolean equals(Block b) {
return this.length == b.length && this.width == b.width
&& this.row == b.row && this.col == b.col;
}
}
public static void main(String[] args) {
if (args.length < 2 || args.length > 3) {
throw new IllegalArgumentException(
"Must have at least 2 and no more than 3 arguments");
}
String initialLayout = args[0];
String goalLayout = args[1];
String debug = "";
if (args.length == 3) {
if (args[0].substring(0, 2).equals("-o")) {
debug = args[0].substring(2, args[0].length());
switch (debug) {
// cases for debugging arguments go here
}
} else {
throw new IllegalArgumentException(
"First argument must start with -o");
}
initialLayout = args[1];
goalLayout = args[2];
}
Solver s = new Solver(initialLayout, goalLayout);
s.solve();
}
}
Could someone please take a look at my code? Suggestions on how to improve efficiency are also welcome. Thanks!
Instead of solving your problem, let me give you some advice on how you can root cause this yourself.
Are you developing in and IDE? If you aren't, start now.
Have you ever used a debugger? If not, start now.
Have you ever set a conditional breakpoint? If not, start now.
Set a conditional breakpoint on the variable that is null, with the condition being that the variable is null. Run your program in debug mode and see whats going on.
If the community solves this problem for you, you haven't learned anything about becoming a better programmer. Make it a point to solve this problem yourself - otherwise you are just postponing the inevitable : becoming a mediocre programmer.