StackOverflow on Recursive Function - java

I have the following function which is supposed to yield all coordinates in a cartesian plane I can reach from an origin in n steps:
The origin is 'location' and the number of steps is 'strength' which is an int 1-10. However, I keep getting a stackoverflow error. Every time I call it I then call clear on the ArrayList positions. Thoughts?
Updated code:
// Returns all positions reachable in 'strength' steps
public ArrayList<Int2D> findEscapeSpace(Int2D location, Field f) {
// Are we still within the given radius?
if((Math.abs(location.getX() - this.location.getX()) + Math.abs(location.getY() - this.location.getY())) < strength) {
System.out.println("Starting on " + location);
// If this position is not contained already, and if it doesn't contain a wall
if(!positions.contains(location) && f.wallField.getObjectsAtLocation(location) == null) {
positions.add(location);
System.out.println("added " + location);
}
// Getting neighboring positions
ArrayList<Int2D> neigh = findNeighPos(location, f);
for(Int2D pos : neigh) {
System.out.println("looking into " + pos + " at depth " + (Math.abs(location.getX() - this.location.getX()) + Math.abs(location.getY() - this.location.getY())) + " and strength " + strength);
if(!positions.contains(pos))
findEscapeSpace(pos, f);
}
}
System.out.println(positions.size());
return positions;
}
Old code
public ArrayList<Int2D> positions = new ArrayList<Int2D>();
// Returns all positions reachable in 'strength' steps
public ArrayList<Int2D> findEscapeSpace(Int2D location, Field f) {
// Are we still within the given radius?
if((Math.abs(location.getX() - this.location.getX()) + Math.abs(location.getY() - this.location.getY())) < strength) {
// If this position is not contained already, and if it doesn't contain a wall
if(!positions.contains(location) && f.wallField.getObjectsAtLocation(location) == null)
positions.add(location);
// Getting neighboring positions
ArrayList<Int2D> neigh = findNeighPos(location, f);
for(Int2D pos : neigh) {
findEscapeSpace(pos, f);
}
}
return positions;
}
public ArrayList<Int2D> findNeighPos(Int2D currentP, Field f) {
ArrayList neighPositions = new ArrayList<Int2D>();
int cx = currentP.getX();
int cy = currentP.getY();
int maxY = f.HEIGHT-1;
int maxX = f.WIDTH-1;
// A few checks to make sure we're not going off tack (literally)
if(cx > 0 && cy < maxY)
neighPositions.add(new Int2D(cx-1, cy+1));
if(cy < maxY)
neighPositions.add(new Int2D(cx, cy+1));
if(cx < maxX && cy < maxY)
neighPositions.add(new Int2D(cx+1, cy+1));
if(cx > 0)
neighPositions.add(new Int2D(cx-1, cy));
if(cx < maxX)
neighPositions.add(new Int2D(cx+1, cy));
if(cx > 0 && cy > 0)
neighPositions.add(new Int2D(cx-1, cy-1));
if(cy > 0)
neighPositions.add(new Int2D(cx, cy-1));
if(cx < maxX && cy > 0)
neighPositions.add(new Int2D(cx+1, cy-1));
return neighPositions;
}

Your recursion does not appear to have a termination condition. It looks like you may want to pass strength as an argument to findEscapeSpace(), and when that method recurses for it to pass a value one less than the one passed to it.
Other than that, your algorithm looks fairly inefficient, as it is likely to generate and test many of the reachable cells many times each, and, moreover, it will be comparatively expensive to check whether each one has already been found. But that's the next problem to overcome.

Related

What is a good way to output why an object won't go through all of the "if" statements?

I am making a program that checks to see if an elements positive and negative charges are able to combine to make 0. A thing i want to do is output the reasons why the two elements are not able to combine. But it is more difficult than i expected. for example if sodium were trying to combine with copernicium, it would output this:
Sodium doesn't combine with Copernicium:
Both valence charges have same polarity.
One or more elements is man-made.
but i can not think of a way to implement this into my code.
here is my code:
public void combine(Element element){
if ((element.getValence() > 0 && valence < 0) || (element.getValence() < 0 && valence > 0)) { //one element needs a positive valence, and one needs a negative valence
if (valence != 0 && element.getValence() != 0) { //checks to see if valence is not equal to 0
if (natural == true && element.isNatural() == true) { //checks to see if both elements are natural
for (int x = 1; x <= 4; x++) {//bruteforce the atoms to see if they both add up to 0.
for (int y = 1; y <= 4; y++) {
if ((valence * x) + (element.getValence() * y) == 0) {
System.out.println(name + " combines with " + element.getName() + " to form " + symbol + "" + x + "" + element.getSymbol() + "" + y);
}
}
}
}
}
}
}
Thanks for any help!
The way to do this is to add else clauses for each if that return an appropriate message.
if ((element.getValence() > 0 && valence < 0) || (element.getValence() < 0 && valence > 0)) { //one element needs a positive valence, and one needs a negative valence
{
// the inner tests
}
else
{
System.out.println("The elements are both positive or both negative");
}
}
This should get you started in the right direction.

Why are the generations in my Game of Life (using Processing) out of order?

import processing.core.PApplet;
import static java.lang.System.out;
public class GoL2 extends PApplet {
int rectSideLength = 25; // rectSideLength = length of each side of the rectangles drawn that represent cells
int generation = 0;
int windowWidth = 1920;
int windowHeight = 950;
int[][] currentGeneration = new int[windowWidth][windowHeight]; // currentGeneration = 2D array to gold cell values of current generation
int[][] nextGeneration = new int[windowWidth][windowHeight]; // nextGeneration = 2D array to hold cell values of next generation
int sumOfNeighbors;
int temporarySumOfNeighbors;
int counter;
public static void main(String[] args) {
PApplet.main("GoL2");
}
public void settings() {
size(windowWidth, windowHeight);
}
int numRectWidth = width / rectSideLength; // numRectWidth = the number of rectangles wide that will fit in the x axis of window
int numRectHeight = height / rectSideLength; // numRectHeight = the number of rectangles that will fit in the y axis of window
// The previous statements are here because they need the size of the frame to
// be set in order to accurately set the variables, lest they end up equal to 100
/* public void setup() {
* background(255);
* frameRate(1);
* for (int y = 0; y < windowHeight; y++) { // For each row,
* for (int x = 0; x < windowWidth; x++) { // For each element in the current row,
* currentGeneration[x][y] = (int) random(0, 2); // Set element (cell) equal to either 0 or 1 (on or off)
* }
* }
* } */
public void setup() {
background(255);
frameRate(1);
for (int y = 0; y < windowHeight; y++) { // For each row,
for (int x = 0; x < windowWidth; x++) { // For each element in the current row,
currentGeneration[x][y] = 0; // Set element (cell) equal to either 0 or 1 (on or off)
}
}
currentGeneration[25][25] = 1;
currentGeneration[25][26] = 1;
currentGeneration[25][27] = 1;
currentGeneration[26][27] = 1;
currentGeneration[27][26] = 1;
}
public void draw() {
numRectWidth = width / rectSideLength;
numRectHeight = height / rectSideLength;
displayCurrentGeneration();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
fill(255, 20, 147);
textSize(30);
text(generation, 20, 30);
textSize(10);
text("25,25", 625, 645);
text("24,27", 600, 695);
text(generation, 580, 695);
generation++;
generateNextGeneration();
}
public void displayCurrentGeneration() {
background(255);
for (int y = 0; y < 950; y++) { // For each row,
for (int x = 0; x < 1920; x++) { // For each element in the current row,
if (currentGeneration[x][y] == 0) { // If element equals zero, make rectangle white
fill(255);
stroke(0);
} else if (currentGeneration[x][y] == 1) { // If element equals one, make rectangle black
fill(0);
stroke(255);
} else {
out.println("Inappropriate value for currentGeneration[" + x + "][" + y + "]. Value: "
+ currentGeneration[x][y] + ", generation: " + generation);
}
rect(x * rectSideLength, y * rectSideLength, rectSideLength, rectSideLength); // Display rectangle (cell)
}
}
// out.println("Generation " + generation);
}
public void generateNextGeneration() {
out.println("Generating gen " + generation);
for (int y = 1; y < numRectHeight - 1; y++) { // For each row,
for (int x = 1; x < numRectWidth - 1; x++) { // For each element in the current row,
sumOfNeighbors = 0;
sumOfNeighbors = getSumOfNeighbors(x, y);
if (sumOfNeighbors != 2 && sumOfNeighbors != 3) { // Death
nextGeneration[x][y] = 0;
} else if (sumOfNeighbors == 3 && currentGeneration[x][y] == 0) { // Birth
nextGeneration[x][y] = 1;
} else if ((sumOfNeighbors == 2 || sumOfNeighbors == 3) && currentGeneration[x][y] == 1) { // Stasis
nextGeneration[x][y] = 1;
}
}
}
currentGeneration = nextGeneration.clone();
}
public int getSumOfNeighbors(int xAxis, int yAxis) {
temporarySumOfNeighbors = 0;
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (xAxis == 24 && yAxis == 27 && j != 0 && i != 0) {
out.println("X" + j + ", Y" + i + ":: " + currentGeneration[xAxis + j][yAxis + i]);
} else if (xAxis == 24 && yAxis == 27 && j == 0 && i != 0) {
out.println("X" + ", Y" + i + ":: " + currentGeneration[xAxis + j][yAxis + i]);
} else if (xAxis == 24 && yAxis == 27 && j != 0 && i == 0) {
out.println("X" + j + ", Y" + ":: " + currentGeneration[xAxis + j][yAxis + i]);
} else if (xAxis == 24 && yAxis == 27 && j == 0 && i == 0) {
out.println("X" + ", Y" + ":: " + currentGeneration[xAxis + j][yAxis + i]);
}
temporarySumOfNeighbors += currentGeneration[xAxis + j][yAxis + i];
}
}
temporarySumOfNeighbors -= currentGeneration[xAxis][yAxis];
if (temporarySumOfNeighbors > 8) {
out.println("temporarySumOfNeighbors > 8: " + temporarySumOfNeighbors);
}
if (xAxis == 24 && yAxis == 27) {
out.println("Generation: " + generation + "- " + xAxis + ", " + yAxis + ": " + temporarySumOfNeighbors);
}
return temporarySumOfNeighbors;
}
}
http://pastebin.com/GH51hXzJ
I am a beginner attempting to code the Game of Life, and I am unsure how to find the source of my issues. I set the game to just start with a simple glider in setup, and believe I may have found the effects of the issue.
I put markers on the cells to help track them. If you watch cell (24,27) you will see at least an example of the issue. In the console, I print out the neighborhood of that cell throughout the run of the program. It appears to somehow detect the neighborhood that (24,27) will have in generation 2 in generation 1, and vice versa (assuming that the first generation is generation 0). I am unsure how to explain it, but if you examine the console output and look at the neighborhoods, you see that it detects generation 2's neighborhood in generation 1 and vice versa. That's why when (24,27) has 3 neighbors in generation 1, it only comes to life in generation 3 while in generation 2, it only has 2 neighbors.
Please let me know if you have any questions, I find it difficult to explain my problem.
The issue is explained more here: http://imgur.com/gallery/iRc07/new
Thank you
This is the main source of your problem:
currentGeneration = nextGeneration.clone();
You might think that line will copy everything from nextGeneration into currentGeneration, and it does... but not in the way you're thinking it does.
The nextGeneration variable is a 2D array. In other words, it's an array of arrays. In other other words, the values contained by nextGeneration are arrays.
When you call the clone() function of an array, it copies the values of the old array into a new array. There's your problem: your values are arrays. So it's copying the arrays, not the values inside those second arrays.
Because of that, both nextGeneration and currentGeneration are pointing to the same arrays. So now when you calculate the next generation, you're changing the arrays of the current generation. This doesn't work, since the Game of Life calculation requires two separate arrays.
In other words, you're making a shallow copy of the arrays.
This might be easier to explain with a simpler program:
public class Test {
public static void main(String... args){
//create an array
int[][] array = {{1, 2, 3}, {4, 5, 6}};
//clone the array
int[][] arrayTwo = array.clone();
//change the original array
array[0][0] = 99;
//second array has also changed!
System.out.println(arrayTwo[0][0]);
}
}
Long story short: You should almost never use the clone() function.
You could fix your problem by making a deep copy of the array. There are libraries that handle this for you, or you could use serialization, or just write your own nested for loop.
But an even simpler (and I would argue more correct) solution would be: stop using class-level variables when you don't need them.
The clone() problem wouldn't be a problem, except you're using nextGeneration as a class-level variable. This means that it retains its value between calls to generateNextGeneration(). And since that value is pointing to the arrays inside currentGeneration, that's causing all of the problems.
You already handle this issue with your other variables: notice how you're resetting the sumOfNeighbors and temporarySumOfNeighbors before you use them. You could do the same thing with the nextGeneration variable.
But I would go a step further and get rid of all three of those class-level variables. Move their declarations to inside the functions that use them, that way you don't have to worry about them maintaining their values between function calls.
Two more notes while I'm at it:
You shouldn't really call Thread.sleep() from the draw() function (or any event function). Just set the frame rate and let Processing handle the timing for you.
You're using a ton of cells that you aren't drawing. Your array is 1920x950, but you're only drawing a small percentage of those cells. That's wasting a ton of CPU time on cells you never show. Like I said in your other question, you need to be more careful about distinguishing between pixel coordinates and array coordinates.
Anyway, this was a good question. I think you're getting closer. You just need to get rid of those extra cells and you'll be in pretty good shape. Good luck.
PS: I'm going to add a processing tag to your question. If you have any questions in the future, it's probably a good idea to make sure to include this tag. Otherwise I won't see it. :p

Players appear to be colliding with air?

(Will be putting a bounty on this - Also, I'm not 100% sure what tags are relevant for this)
I'm incredibly confused here. I am attempting to use this (simplified) model for my archers to collide with:
However, as you can see, my archers appear to be colliding in mid-air! I would understand if they fell through (e.g. I had not put enough "points" in my collision model), but to actually appear to be colliding with NOTHING is absolutely baffling me.
I'm loading the model on the server with the same code that I'm displaying it there in the client, so that can't be the issue. I've pastebinned it here anyway.
Then, I'm adding it to three int[] arrays, like this:
coordsx = new int[80 * 10];
coordsy = new int[80 * 10];
coordsz = new int[80 * 10];
for (javax.vecmath.Vector3f vec : m.getVertices()){ //Quick note: M is a model. As you can see, I'm just going through all the vertex positions.
coordsx[DELTA+(int) vec.x] = 1;
coordsy[DELTA+(int) vec.y] = 1;
coordsz[DELTA+(int) vec.z] = 1;
}
Quick note: DELTA is the value of ((80 * 10) / 2) or to save you the math, 400. Also, I used three int[]'s and not an int[][][] because an int[][][] caused an OutOfMemory which I couldn't fix.
Now that I have got these arrays of coordinates, I'm using this code to check it:
for (int x = (int) (location.x + 1); x > location.x - 1; x--){
for (int y = (int) (location.y + 1); y > location.y - 1; y--){
for (int z = (int) (location.z + 1); z > location.z - 1; z--){
distancex = x;
distancez = z;
distancey = y;
try{
int i = 0;
if (owner.type == 0){
if (GameServer.DELTA + distancex > 0 && GameServer.DELTA + distancex < 800 && GameServer.coordsx[(int) (GameServer.DELTA + distancex)] == 1){
if (GameServer.DELTA + distancey > 0 && GameServer.DELTA + distancey < 800 && GameServer.coordsy[(int) (GameServer.DELTA + distancey)] == 1){
if (GameServer.DELTA + distancez > 0 && GameServer.DELTA + distancez < 800 && GameServer.coordsz[(int) (GameServer.DELTA + distancez)] == 1){
i = 1;
}
}
}
}
if (i == 1){
collision = true;
YDown = 0;
}
}catch (ArrayIndexOutOfBoundsException e1){
e1.printStackTrace();
}
}
}
}
if (collision){
System.out.println("Collision!");
}else{
System.out.println("No Collision!");
location.y = location.y-=YDown;
}
location is a Vector3f of the archers' X, Y, and Z relative to the ship's location - I've checked this using de-bug messages, and the location is indeed returning correctly.
As you can see, the variable i is only being set to 1 if there is a coordinate at both the X, Y, and Z location of the point that is being checked. Obviously, I am iterating through all the nearby coordinates as well, since my player is not just a single point.
Since the player appears to be colliding with air, then there is obviously something wrong. But I cannot find what.
Am I on the right track here, or am I doing everything entirely wrong? And if I am on the right track, then what is going wrong here and how can I fix it?
There is a problem with your model. Using three arrays may save memory, but it also changes the model, creating "shadows" that your archers can collide with.
Let's say that you have vertices in (1,1,1) and (2,2,2).
Using your model, there will also a vertex at (1,2,2) and any other combination where all coordinates is either 1 or 2.
So, back to the drawing board.
Maybe you can save memory by using a single bit instead of a 32 bit int for each coordinate?
Or you could change the way you store the model. What if you use a 2-dimensional array of int and store the z-coordinate(s) of the floor. This would limit your world to one (or just a few) floors at each x,y-coordinate but would save a huge amount of memory.

Find the shortest path with maximum gain

Problem link How can i modify my code so it give me shortest path with maximum weight.
Problem overview: I am giving a matrix and i have to go from one index to other with minimum index each index is having some gain , so i have to find the shortest path(if more than one shortest path are possible so path with maximum gain)
My code:
public static int min(int x , int y ,int endx,int endy,int n ,int m,int[][] p){
int[] dirx ={1,-1,0,0 };
int[] diry={0,0,1,-1};
LinkedList<Point> som = new LinkedList<Point>();
som.add(new Point(x,y));
//dp[x][y]=p[x][y];
while(!som.isEmpty()){
Point xx = som.pop();
for(int i=0;i<4;i++){
int x1 = xx.x + dirx[i];
int y1 = xx.y + diry[i];
if(x1>=0 && x1<n && y1>=0 && y1<m && p[x1][y1]!=-1 && dp[x1][y1]==-1){
dp[x1][y1] = dp[xx.x][xx.y]+ 1;
som.add(new Point(x1,y1));
}
}
}
return dp[endx][endy];
}
from your code add
((dp[x1][y1]==-1) || ((dp[x1][y1] == dp[xx.x][xx.y] + 1) && (w[xx.x][xx.y]+p[x1][y1] > w[x1][y1])))
instead of
(dp[x1][y1]==-1)
and inside the condition
w[x1][y1] = w[xx.x][xx.y] + p[x1][y1];
which means you will update the path result if you found better way of the same length
also you may optimize not to add same point several times, but i think this is not necessary in this particular problem
This problem can be solved using Dijkstra's algorithm. But we need to compare both distance and gain amount instead of just distance in the original algorithm.
These are some code hints from me, so you only need to change some part of your code.
class Entry implements Comparable<Entry>{
int x,y, dist, gain;
//Constructor is omitted.
public int compareTo(Entry o){
if(dist != o.dist)//Compare distance first
return dist - o.dist;
return o.gain - gain;//Compare gain value
}
}
//Method signature is omitted
PriorityQueue<Entry> q = new PriorityQueue();
q.add(new Entry(0,0,0,gain[0][0]);
int[][][]dist = new int[n][m][2];//Assume size of matrix is n x m
//Init dist array omitted
dist[0][0][0] = 0;//Init distance
dist[0][0][1] = gain[0][0];//Init gain amount, assume we have a gain matrix
while(!q.isEmpty()){
Entry e = q.poll();
if(dist[e.x][e.y][0] == e.dist && dist[e.x][e.y][1] == e.gain){
for(all valid next positions (a,b))
if(dist[a][b][0] > e.dist + 1 || (dist[a][b][0] == e.dist + 1 && dist[a][b][1] < e.gain + gain[a][b]){
//Notice the condition to update the dist array
dist[a][b][0] = e.dist + 1;
dist[a][b][1] = e.gain + gain[a][b];
q.add(new Entry(a,b,e.dist + 1, e.gain + gain[a][b]);
}
}
}
return dist[n-1][m-1][1];

How to end my recursion

I need to program a method to solve a maze (2-dimensional array). I need to stay directly left of the wall at all times and my method should end when either I've reached the exit point (which is always at the same position) or when there is no solution possible (and, after running through the maze I'm back at the entry point).
I was able to do all that, no problems, I can visually ensure that it's doing what I want it to do (we've got some other methods from our instructor which output the visuals) and my console debug output is right as well.
This is the relevant code:
public static void main(String[] args) {
maze = generateMaze(10,10);
walk(1,0,0);
}
public static void walk(int x, int y, int direction) {
System.out.println("x = " + x + " y = " + y); //debug output
draw(x,y,maze); //draws current position
if (x == maze.length-1 && y == maze[1].length-2) { //terminate when reached exit
System.out.println("Geschafft!");
return;
}
if (x == 1 && y == 0 && direction == 3) { //terminate when at starting point again (no solution)
System.out.println("Keine Lösung möglich.");
return;
}
if (direction == 0) { //go down
if (maze [x][y+1]) {
walk(x,y,1);
}
walk(x,y+1,2);
}
if (direction == 1) { //go right
if(maze [x+1][y]) {
walk(x,y,3);
}
walk(x+1,y,0);
}
if (direction == 2) { //go left
if(maze [x-1][y]) {
walk(x,y,0);
}
walk(x-1,y,3);
}
if (direction == 3) { //go up
if(maze[x][y-1]) {
walk(x,y,2);
}
walk(x,y-1,1);
}
}
There's just one problem: how do I end my recursion correctly? This is what I get form the console:
x = 1 y = 0
x = 1 y = 1
x = 1 y = 1
x = 1 y = 2
and so on...
x = 8 y = 8
x = 9 y = 8
Geschafft!
x = 8 y = 9
x = 8 y = 9
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10
at maze.MazeSolution.walk(MazeSolution.java:26)
at maze.MazeSolution.walk(MazeSolution.java:39)
and some more of that
I do understand the error, the recursion obviously doesn't end where I want it to and x or y are increased and try to use an index in the array that isn't there.
Why doesn't the recursion end with the return statement, when either of these situations come true:
if (x == maze.length-1 && y == maze[1].length-2) { //terminate when reached exit
System.out.println("Geschafft!");
return;
}
if (x == 1 && y == 0 && direction == 3) { //terminate when at starting point again (no solution)
System.out.println("Keine Lösung möglich.");
return;
}
What do I need to do to end it correctly?
I greatly appreciate your help, show some love for a beginner and tell me what to do.
Add to the beginning
public static void walk(int x, int y, int direction) {
System.out.println("x = " + x + " y = " + y); //debug output
if (x >= 10 || x < 0 || y >= 10 || y < 0) return;
Look at your returns and where you may return to. You can return in the middle of your enclosing function which has other calls to walk, without the guards to ensure they're not called.
I recommend re-implementing your logic; think about having if/else pairs to ensure mutual exclusion.
Why don't you simply return true or false and react on it?
So basically you add to your two end cases return true; for code ended.
if(walk(...)) return true;

Categories