Related
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 am solving the problem https://leetcode.com/problems/path-sum-iii/
I'll also briefly mention it here:
Find the number of paths in a Binary tree whose sum = sum. The path does not necessarily have to begin (end) at the root (leaf). As long as the path goes downward it should be considered as a valid path.
Here is my solution:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int pathSum(TreeNode root, int sum) {
int path = 0;
if(root.val == sum)
return 1;
else if(root.left == null && root.right == null)
return 0;
if(root.left != null){
path += pathSum(root.left, sum - root.val);
path += pathSum(root.left, sum);
}
if(root.right != null){
path += pathSum(root.right, sum - root.val);
path += pathSum(root.right, sum);
}
return path;
}
}
The answer as per their system is 3, but I am getting the answer as 4 for the following input:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
Return 3. The paths that sum to 8 are:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
I have spent hours trying to reason why my code wold not work, but I cannot figure out the problem.
Sorry for a naive question :( But this is killing me!
I'm not sure what's wrong in your solution, but I don't think it's correct. For one thing, if your root was 8 you would immediately return and count only the root as solution. This is how I would do it:
import java.util.ArrayList;
public class Solution {
public static int pathSum(TreeNode root, int sum) {
return pathSum(root, sum, 0, new ArrayList<Integer>());
}
public static int pathSum(TreeNode root, int sum, int count, ArrayList<Integer> arr) {
arr.add(root.val);
int acc = 0;
for (int i=arr.size()-1; i>=0; i--) {
acc += arr.get(i);
if (acc == sum)
count++;
}
if(root.left != null)
count = pathSum(root.left, sum, count, arr);
if(root.right != null)
count = pathSum(root.right, sum, count, arr);
arr.remove(arr.size()-1);
return count;
}
static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int v) {
this.val = v;
}
}
public static void main(String[] args) {
TreeNode root = new TreeNode(10);
root.left = new TreeNode(5);
root.right = new TreeNode(-3);
root.left.left = new TreeNode(3);
root.left.right = new TreeNode(2);
root.right.right = new TreeNode(11);
root.left.left.left = new TreeNode(3);
root.left.left.right = new TreeNode(-2);
root.left.right.right = new TreeNode(1);
System.out.println(pathSum(root, 8));
}
}
The idea is to populate an aarray with the value along the path as you traverse the tree recursively, making sure you remove elements as you return. When you visit a node, you have to consider all the sums from that node to any node on the path to the root. Any of them can add up to your reference value. This implementation is O(nlogn), as you traverse n nodes, and for each you traverse an array of len up to log(n).
your code cant satisfy this constraint:
these nodes should be continuous.
e.g the root(value 10) of this tree and the leaf(value -2) of this tree, the sum of them is equals 8. but it dont satisfy continous, so It cant count.
Unfortunately, your code cant filter this case.
an alternative Solution:
public class Solution {
public int pathSum(TreeNode root, int sum) {
int path = traverse(root,sum);
return path;
}
public int traverse(TreeNode root, int sum){
int path = 0;
if(root==null){
return 0;
}
else{
path += calcu(root,sum);
path += traverse(root.left,sum);
path += traverse(root.right,sum);
return path;
}
}
private int calcu(TreeNode root, int sum) {
if(root==null){
return 0;
}
else if(root.val==sum){
return 1 + calcu(root.left,sum-root.val)+calcu(root.right,sum-root.val);
}
else{
return calcu(root.left,sum-root.val)+calcu(root.right,sum-root.val);
}
}
}
explanation: traverse this tree and make every treeNode as root node, find target path under the premise continous.
the problem with your solution is that you do not start from an initial sum, if you are in a new inner path.
so you should keep track of both the accomulated sum and the original sum as well when you move inner path.
find below a modified copy of your algorithm.
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
boolean visitedAsRoot = false;
TreeNode(int x) {
val = x;
}
}
public static int pathSum(TreeNode root, int accomulate, int sum) {
int path = 0;
if (root.val == accomulate)
return 1;
else if (root.left == null && root.right == null)
return 0;
if (root.left != null) {
path += pathSum(root.left, accomulate - root.val, sum);
if (!root.left.visitedAsRoot) {
root.left.visitedAsRoot = true;
path += pathSum(root.left, sum, sum);
}
}
if (root.right != null) {
path += pathSum(root.right, accomulate - root.val, sum);
if (!root.right.visitedAsRoot) {
root.right.visitedAsRoot = true;
path += pathSum(root.right, sum, sum);
}
}
return path;
}
public static void main(String args[]) {
TreeNode t1 = new TreeNode(3);
TreeNode t2 = new TreeNode(-2);
TreeNode t3 = new TreeNode(1);
TreeNode t4 = new TreeNode(3);
TreeNode t5 = new TreeNode(2);
TreeNode t6 = new TreeNode(11);
TreeNode t7 = new TreeNode(5);
TreeNode t8 = new TreeNode(-3);
TreeNode t9 = new TreeNode(10);
t4.left = t1;
t4.right = t2;
t5.right = t3;
t7.left = t4;
t7.right = t5;
t8.right = t6;
t9.left = t7;
t9.right = t8;
System.out.println(pathSum(t9, 8, 8));
}
The problem with your solution is that it is also counting 10 - 2 = 8. where 10 is the topmost root node and -2 is a bottom leaf. It ignores all the path in between.
I managed to solve it with a tamperedSum boolean.
public static int pathSum(TreeNode root, int sum, boolean tamperedSum)
{
int path = 0;
if(root.val == sum)
path = 1;
if(root.left == null && root.right == null)
return path;
if(root.left != null){
path += pathSum(root.left, sum - root.val, true);
if (!tamperedSum)
path += pathSum(root.left, sum, false);
}
if(root.right != null){
path += pathSum(root.right, sum - root.val, true);
if (!tamperedSum)
path += pathSum(root.right, sum, false);
}
return path;
}
The tamperedSum boolean is set to true when we have deducted values (of nodes) from the original sum which in this case is 8.
We would invoke it as:
pathSum(root, sum, false)
The idea is that if the sum has been tampered i.e a node value on the path has already been deducted, we are no longer allowed to pass it as-is to the branch below the node.
So, we set tamperedSum to true whenever we deduct the node value from the sum as: sum - root.value. After that, all nodes below it are not allowed to pass through the sum without deducting their node value from it.
I tried to build a minHeap using java, this is my code:
public class MyMinHeap {
private ArrayList<Node> heap;
public MyMinHeap() {
heap = new ArrayList<Node>();
}
public MyMinHeap(ArrayList<Node> nodeList) {
heap = nodeList;
buildHeap();
}
public void buildHeap() {
int i = heap.size() / 2;
while (i >= 0) {
minHeapify(i);
i--;
}
}
public Node extractMin() {
if (heap.size() <= 0) return null;
Node minValue = heap.get(0);
heap.set(0, heap.get(heap.size() - 1));
heap.remove(heap.size() - 1);
minHeapify(0);
return minValue;
}
public String toString() {
String s = "";
for (Node n : heap) {
s += n + ",";
}
return s;
}
public void minHeapify(int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int smallest = i;
if (left < heap.size() - 1 && lessThan(left, smallest))
smallest = left;
if (right < heap.size() - 1 && lessThan(right, smallest))
smallest = right;
if (smallest != i) {
swap(smallest, i);
minHeapify(smallest);
}
}
private void swap(int i, int j) {
Node t = heap.get(i);
heap.set(i, heap.get(j));
heap.set(j, t);
}
public boolean lessThan(int i, int j) {
return heap.get(i)
.compareTo(heap.get(j)) < 0;
}
public static void main(String[] args) {
char[] chars = {'a', 'b', 'c', 'd', 'e', 'f'};
int[] freqs = {45, 13, 12, 16, 9, 5};
ArrayList<Node> data = new ArrayList<Node>();
for (int i = 0; i < chars.length; i++) {
data.add(new Node(chars[i], freqs[i]));
}
MyMinHeap heap = new MyMinHeap(data);
System.out.println("print the heap : " + heap);
for (int i = 0; i < chars.length; i++) {
System.out.println("Smallest is :" + heap.extractMin());
}
}
}
The output should be:5,9,12,13,16,45,
but what I got is : 9,13,12,16,45
I have debugged this but still can't figure out, anybody help? thanks a lot.
Insert :
When we insert into a min-heap, we always start by inserting the element at the bottom. We insert at the
rightmost spot so as to maintain the complete tree property.
Then, we "fix" the tree by swapping the new element with its parent, until we find an appropriate spot for
the element. We essentially bubble up the minimum element.
This takes 0 (log n) time, where n is the number of nodes in the heap.
Extract Minimum Element :
Finding the minimum element of a min-heap is easy: it's always at the top. The trickier part is how to remove
it. (I n fact, this isn't that tricky.)
First, we remove the minimum element and swap it with the last element in the heap (the bottommost,
rightmost element). Then, we bubble down this element, swapping it with one of its children until the minheap
property is restored.
Do we swap it with the left child or the right child? That depends on their values. There's no inherent
ordering between the left and right element, but you'll need to take the smaller one in order to maintain
the min-heap ordering.
public class MinHeap {
private int[] heap;
private int size;
private static final int FRONT = 1;
public MinHeap(int maxSize) {
heap = new int[maxSize + 1];
size = 0;
}
private int getParent(int position) {
return position / 2;
}
private int getLeftChild(int position) {
return position * 2;
}
private int getRightChild(int position) {
return position * 2 + 1;
}
private void swap(int position1, int position2) {
int temp = heap[position1];
heap[position1] = heap[position2];
heap[position2] = temp;
}
private boolean isLeaf(int position) {
if (position > size / 2) {
return true;
}
return false;
}
public void insert(int data) {
heap[++size] = data;
int currentItemIndex = size;
while (heap[currentItemIndex] < heap[getParent(currentItemIndex)]) {
swap(currentItemIndex, getParent(currentItemIndex));
currentItemIndex = getParent(currentItemIndex);
}
}
public int delete() {
int item = heap[FRONT];
swap(FRONT, size--); // heap[FRONT] = heap[size--];
heapify(FRONT);
return item;
}
private void heapify(int position) {
if (isLeaf(position)) {
return;
}
if (heap[position] > heap[getLeftChild(position)]
|| heap[position] > heap[getRightChild(position)]) {
// if left is smaller than right
if (heap[getLeftChild(position)] < heap[getRightChild(position)]) {
// swap with left
swap(heap[position], heap[getLeftChild(position)]);
heapify(getLeftChild(position));
} else {
// swap with right
swap(heap[position], heap[getRightChild(position)]);
heapify(getRightChild(position));
}
}
}
#Override
public String toString() {
StringBuilder output = new StringBuilder();
for (int i = 1; i <= size / 2; i++) {
output.append("Parent :" + heap[i]);
output
.append("LeftChild : " + heap[getLeftChild(i)] + " RightChild :" + heap[getRightChild(i)])
.append("\n");
}
return output.toString();
}
public static void main(String... arg) {
System.out.println("The Min Heap is ");
MinHeap minHeap = new MinHeap(15);
minHeap.insert(5);
minHeap.insert(3);
minHeap.insert(17);
minHeap.insert(10);
minHeap.insert(84);
minHeap.insert(19);
minHeap.insert(6);
minHeap.insert(22);
minHeap.insert(9);
System.out.println(minHeap.toString());
System.out.println("The Min val is " + minHeap.delete());
}
}
The problem is in your minHeapify function. You have:
public void minHeapify(int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int smallest = i;
if (left < heap.size() - 1 && lessThan(left, smallest))
smallest = left;
if (right < heap.size() - 1 && lessThan(right, smallest))
smallest = right;
Now, let's say that your initial array list is {3,2}, and you call minHeapify(0).
left = 2 * i + 1; // = 1
right = 2 * i + 2; // = 2
smallest = i; // 0
Your next statement:
if (left < heap.size() - 1 && lessThan(left, smallest))
At this point, left = 1, and heap.size() returns 2. So left isn't smaller than heap.size() - 1. So your function exits without swapping the two items.
Remove the - 1 from your conditionals, giving:
if (left < heap.size() && lessThan(left, smallest))
smallest = left;
if (right < heap.size() && lessThan(right, smallest))
smallest = right;
the problem is: calculate the total sum of all root-to-leaf numbers. for example: if the tree is (1,2,3), 1 is root, 2 is left child, 3 is right child, two paths: 1->2 1->3, sum=12+13=25
this is my correct recursive solution. in the helper method, return the sum:
public int sumNumbers(TreeNode root) {
if (root == null) {
return 0;
}
return getSum(root, 0);
}
private int getSum(TreeNode root, int value) {
if (root.left == null && root.right == null) {
return root.val + value * 10;
}
int sum = 0;
if (root.left != null) {
sum += getSum(root.left, value * 10 + root.val);
}
if (root.right != null) {
sum += getSum(root.right, value * 10 + root.val);
}
return sum;
}
but when I add the sum as a parameter in the helper method, I always got 0.
public int getSum(TreeNode root) {
int sum = 0, path = 0;
helper(root, path, sum);
return sum;
}
private void helper(TreeNode root, int path, int sum) {
if (root == null) {
return;
}
int path = 10 * path + root.val;
if (root.left == null && root.right == null) {
sum += path;
return;
}
helper(root.left, path, sum);
helper(root.right, path, sum);
}
I believe there must be some points I misunderstand about the recursion. thank you in advance to give me some explanation why the value of sum is not 'transferred' back to the sum in getSum method.
Also you need to think about overflow. My solution has passed in LeetCode, hopefully it gives you some tips.
public class Solution {
private long sum = 0;
public int sumNumbers(TreeNode root) {
if(root == null) return 0;
sum(root, new Stack<Integer>());
if(this.sum >= Integer.MAX_VALUE){
return Integer.MAX_VALUE;
}
return (int)this.sum;
}
private void sum(TreeNode node, Stack<Integer> stack){
if(node == null) return;
stack.push(node.val);
if(node.left == null && node.right == null){
long tempSum = 0;
int index = 0;
for(int i=stack.size()-1;i>=0;i--){
int k = stack.get(i);
int times = (int)Math.pow(10, index++);
k *= times;
tempSum += k;
}
this.sum += tempSum;
}
sum(node.left, stack);
sum(node.right, stack);
if(stack.size() > 0)
stack.pop();
}
}
ZouZou is right about the pass by value, although this only applies to primitives. Changing your sum to an Integer instead of int should do the trick, other solution would be to us a global variable (i.e. field)
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;
}