Can't figure out why recursion never resolves - java

My friend is making a minesweeper clone and he asked me to help with the part where when you click on a non-mine/non-number 'blank' square it reveals all adjacent blanks. The following is the code I wrote. I can't figure out why it never resolves.
My base case should be when the for loops completely execute and the if statement never returns true.
Is there something I'm missing?
This is in java, by the way. Also, I told him the whole slew of button state changing should be assigned to a method :p
public void revealAdjacentNulls(int r, int c)
{
int ir, ic;
//literal edge cases :P
int rmax = (r == 15) ? r : r + 1;
int cmax = (c == 15) ? c : c + 1;
//check all spaces around button at r,c
for(ir = (r==0) ? 0 : r-1; ir <= rmax; ir++){
for (ic = (c==0) ? 0 : c-1; ic <= cmax; ic++){
//if any are blank and uncovered, reveal them, then check again around the blanks
if (buttons[ir][ic].value == 0 && buttons[ir][ic].isCovered == false)
{
buttons[ir][ic].setEnabled(false); //number uncovered
buttons[ir][ic].setBackground(Color.blue);
buttons[ir][ic].setText(Character.toString(buttons[ir][ic].value));
buttons[ir][ic].isCovered = false;
revealAdjacentNulls(ir, ic);
}
}
}
}

Let's consider the case when r==0 and c==0, and let's assume that buttons[0][0].value == 0 and that buttons[0][0].isCovered == false.
The very first iteration of the loop will cause the function to call itself with the same arguments, 0, 0, and with unchanged state of value and isCovered. This will instantly lead to infinite recursion.
P.S. Check out the Wikipedia article for other flood fill algorithms.

Well for one thing, it will always keep recursing for revealAdjacentNulls(r, c). Your condition is that isCovered must be false - but then you're setting isCovered to false as well. Did you mean to write:
buttons[ir][ic].isCovered = true;
? Or possibly your check should be:
if (buttons[ir][ic].value == 0 && buttons[ir][ic].isCovered)
(It depends on what you mean by "is covered".)

Another case: if r == 15 then the loop will be from 14 (r - 1) to 15 (rmax). If your if statement is true, then there will be infinite recursion. The same applies to c.

Related

Code only outputting the same thing, wont use the .equals to output differently

I'm doing a project for a class I'm in and the assignment is to make a program in Netbeans that will take 3 inputs,
the person height,
back problems
heart problems.
The teacher said to use boolean for the two problems. he wants us to use inputBack.equals("N") to see if it equals N for the input which I get, anyways I'll put my code below if someone could help me out that would be great!
Basically the program only outputs different when I change the height but I need it to show something else when b or h is Y.
double H;
String b, h;
b = back.getText();
h = heart.getText();
H = Double.parseDouble(height.getText());
if (h.equals("Y") || b.equals("Y")) {
output.setText("Sorry, its not safe for you to ride the coaster");
}
if ((H >= 122 && H <= 188) && (h.equals("N") || b.equals("N"))) {
output.setText("You are cleared to ride, have fun!");
} else if (b.equals("Y") || h.equals("Y")) {
output.setText("Sorry, its not safe for you to ride the coaster");
} else {
output.setText("Sorry, its not safe for you to ride the coaster");
}
You're making it too complex actually. Your real issue is in the line:
if ((H >= 122 && H <= 188) && (h.equals("N") || b.equals("N")))
The OR operator should be an AND operator there. If the person has no heart issues, your test will always succeed no matter the value of b. This is why your output won't change even if you change the value.
I think a simple solution like the one below would already be sufficient to achieve what you want:
// Please use sensible names for your variables, and no uppercase single letters
double height = Double.parseDouble(heightField.getText()); // This could throw a NumberFormatException, you probably want to catch it
String backIssues = backField.getText();
String heartIssues = heartField.getText();
// Drop your first if test, it is completely unnecessary there.
// If the person is between 122 and 188 cm, and has no heart issues and has no back issues: Hooray!
if (height >= 122 && height <= 188 && heartIssues.equalsIgnoreCase("N") && backIssues.equalsIgnoreCase("N")) {
output.setText("You are cleared to ride, have fun!");
} else { // In all other cases, not allowed to ride the coaster
output.setText("Sorry, its not safe for you to ride the coaster");
}
You have too many redundant if/else statements. You can simplify your code like this:
//Heart or back problem, so no riding
if (h.equals("Y") || b.equals("Y")) {
output.setText("Sorry, its not safe for you to ride the coaster");
}
else { //health ok, check height
if (H >= 122 && H <= 188)
output.setText("You are cleared to ride, have fun!");
else
output.setText("You are outside the height requirements, you can't ride")
}
Also keep in mind if the user puts in a value for height that is not numeric you will get an exception thrown.
your error is on this line :
if ((H >= 122 && H <= 188) && (h.equals("N") || b.equals("N"))) {
Indeed if your height is fine, you can go to the coaster even if you have one of the two others problem.
If you put h="N" and b="Y" the condition h.equals("N") || b.equals("N") will be true because h="N".
The good thing to do is to replace this line by :
if ((H >= 122 && H <= 188) && (h.equals("N") && b.equals("N"))) {
You can also simplify your code, you put too many if...

Beginner Boolean compiling error

I am very new to Java (doing a beginners university module) so sorry for the probably silly question. I am trying to verify whether a ragged array is a 'tridiagonal matrix'.
It is valid if it is of length 3 at the first level and of length n − 1, n, and n − 1 at the second level. I intended to come up with a code to firstly verify the length is 3, then find the longest length array within it for n, then finally verify each length.
For whatever reason my code won't compile but I'm not seeing an error message, just a red exclamation mark on the class. I assume this means there are multiple errors. If anyone could point them out it would be a massive help.
static boolean isValidTridiagonal ( double [][] m)
{
if (double [][]=new double [3][])
{
int n = 0;
for(int i = 0; i < m.length; i++)
{
if(m[i].length > n)
{
n = m[i].length;
if( (m[0].length = n-1) && (m[1].length = n) &&(m[2].length=n-1))
{
return true
}
else
{
return false
}
}
else
{
return false
}
}
Thanks very much!
I agree with Foolish in the comments that it's helpful to use an IDE that can highlight syntax errors and other problems with the code, it really makes a huge difference. Apart from that, another general strategy is to always code in "baby steps": do only the minimal thing to test if the code works, compile and test often. And if you still have troubles, you can always comment out chunks of your code when searching for the offending bits.
Having said that, the errors that I see in your code are:
if (double [][]=new double[3][])
If you want to test the length of the input, you can do if (m.length == 3)
In
if( (m[0].length = n-1) && (m[1].length = n) &&(m[2].length=n-1))
you're not testing for equality, but rather trying to put the values n-1 etc into m[0].length, which is not going to work. What you probably meant was
if( (m[0].length == n-1) && (m[1].length == n) &&(m[2].length==n-1))
In
return true
you're missing a semicolon. The compiler is whiny about things like that and unless you use an IDE or learn to interpret the compiler error messages, it can be really painful to find such errors.
Finally, of course, the answer by vasste provides a much simpler solution to your actual task, so it's worth looking into that :).
Why do you need all that loops? If all arrays cannot be null, than
static boolean isValidTridiagonal(double[][] m) {
return m.length == 3 && m[0].length == m[1].length - 1 && m[2].length == m[0].length;
}
You're missing a few braces at the end but, judging from your indentation, you just forgot to copy them.
You're missing semicolons from the end of the return lines.
The condition within this if statement if (double [][] = new double [3][]) is not a valid expression. You simply want to evaluate the length, which you can do like if (m.length == 3). You did the same thing later on.
The line including (m[0].length = n-1) && (m[1].length = n) && (m[2].length=n-1) is not valid because you are performing assignment (=) in all three cases. An equality check is the double equals operator ==.
You do not return a value in every case. You can fix this by adding return false; after the closing brace of your first if statement, i.e. the last line of the function.
This is enough to get your code to compile. As mentioned in another answer though, your logic is confusing and without actually tracing it through I would speculate that it will not work as you would expect.
If I have understood your requirements correctly, you can rewrite the entire function as:
static boolean isValidTridiagonal ( double [][] m)
{
return m.length == 3 &&
m[0].length + 1 == m[1].length &&
m[2].length + 1 == m[1].length;
}
A proper IDE - Netbeans, Eclipse, etc. - will give you fairly descriptive error messages to show you where you've gone wrong.
This is basically completely stylistic but I wish someone had pointed this out to me earlier. If you ever find yourself writing code in this form:
if( (m[0].length == n-1) && (m[1].length == n) && (m[2].length == n-1))
{
return true;
}
else
{
return false;
}
know that you can save yourself so many lines without losing any readability by instead writing:
return (m[0].length == n-1) && (m[1].length == n) && (m[2].length == n-1);

Wrap Around Grid - errors on east/west only

I have four methods that check whether or not a given grid location is next to an occupied location (value of 1). The grid is assumed to wrap around, ie, if in a 50x50 grid[0][1] is the given location and grid[49][1] is occupied, the method should return true/ My checkNorth and checkEast method are working fine, but I get an ArrayIndexOutofBoundsException: -1 error for either the south or west methods every time I run the program. I checked my math and I think it should work - am I using the modulo incorrectly, or am I missing something else?
EDIT: Clarified the wrapping criterion, word use correction.
boolean checkWest(int indexA, int indexB)
{
if (indexA-1 > 0)
{
if (grid[indexA-1][indexB] == 1)
{
return true;
}
}
if (indexA-1 < 0)
{
if (grid[(indexA-1)%width][indexB] == 1)
{return true;}
else return false;
}
return false;
}
I see a couple problems. First, Java arrays are zero-indexed, which means that the first element is at index 0. So it's okay to check grid[indexA-1][indexB] when indexA-1 is equal to 0. Second, you're not properly handling when indexA equals 0. Here is my implementation. I also simplified the logic a bit.
boolean checkWest(int indexA, int indexB)
{
if (indexA > 0)
return grid[indexA - 1][indexB] == 1;
else
return grid[width + indexA - 2][indexB] == 1;
}
EDIT: I'm pretty sure I butchered the math with the second return statement. It should be right now...

ArrayIndexOutOfBoundsException when .length is zero

I got a java.lang.ArrayIndexOutOfBoundsException and I think it is because when nums.length gives me a zero (because there is nothing inserted in the parameter) the attribute I gave to the variable (-----.length -1------) will make it -1 when it gives me zero.
How should I make it not do this knowing that if I leave it .length without a -1 there will be an out of bounds exception on the other side of the array?
public boolean sameFirstLast(int[] nums) {
int lengthOfArray = nums.length - 1;
int thisIsHowLong = nums.length;
if (nums[0] == nums[lengthOfArray ] && thisIsHowLong > 0){
return true;
}
return false;
}
//always remember to return false in the end becuse if the top dosnt run then
//there will be no boolean returned and the method is not void so it has to return a //boolean
//ALWAYS REMEMBER TO SET nums.length - 1
//the .length method always starts from 1 and threfore will give you an extra space //that it will check for but we wont have anything in that space and then the compiler //will go to that space and will fond nothing to test with and gove an ERROR out of //bounds exeption because it is looking out of the array.
Your condition should look like
if(thisIsHowLong > 0 && nums[0] == nums[lengthOfArray ] )
Now if your first condition is false, second will never be checked.
And you want same.
You need to interchange the conditions.
if (thisIsHowLong > 0 && nums[0] == nums[lengthOfArray ]){ // This will prevent the exception.

Solving maze using stacks

I been working on this code for a while and can't seem to get it to work. I have started over multiple times. I am not sure if my logic is off or if I could be doing something better. Any suggestion in the right direction or new ideas to try would be helpful. I understand that a maze could be solved recursively but for this part of the assignment I need to use a stack.
I created two stacks. One for the path the other for spots I already searched. Ideally I would check to see if the searched path contains the next spot in a direction. If it does it checks another direction.
Sample maze
0 1 0 1 0
0 0 0 1 0
0 1 0 0 0
0 1 0 1 1
0 1 0 0 0
My algorithm seems to get stuck between 2,3 and 2,4. Never explores 1,4 or 0,4. I see it keep bouncing between 2,3 and 2,4 in an infinite loop. So it seems my searched.contains() is not functioning properly. Any suggestion to fix my searched stack? Ideally, when I run my code. I want it to check East, South, west then North has already been searched or not. If all points have been checked it will pop the last position from my path stack using current= path.pop inside the while loop and repeat.
Position is a custom class. I have considered adding a previous position variable to the constructor in the position class but seems to not to be needed if I can get my path stack to work. If I am wrong on this please let me know.
public static Position [] stackSearch(char [] [] maze){
//todo: your path finding algorithm here using the stack to manage search list
//your algorithm should modify maze to mark positions on the path, and also
//return array of Position objects coressponding to path, or null if no path found
ArrayDeque <Position> path = new ArrayDeque<Position>();
ArrayDeque <Position> searched = new ArrayDeque<Position>();
//creates position object
Position start = new Position(0,0,'0');
Position current;
Position north,south, east, west;
int i = 0; int j = 0;
//push (0,0) onto stack
path.push(start);
searched.push(start);
while(!path.isEmpty()){
current=path.pop();
i=current.i;
j=current.j;
if(i==maze.length-1 && j==maze.length-1 && maze[i][j]=='0'){
Position[] trail= new Position [path.size()];
while(!path.isEmpty()){
for(int k=0; k<path.size();k++){
trail[k]=path.pop();
}
return trail;
}
}
System.out.println(i +"," +j);
//check east.
east= new Position(i,j+1,'0');
south= new Position(i+1,j,'0');
west= new Position(i,j-1,'0');
north= new Position(i-1,j,'0');
if (j+1 >= 0 && j+1 < maze.length && maze[i][j+1] == '0' && searched.contains(east)==false)
{
searched.push(east);
path.push(current);
path.push(east);
}
//check south, add its position to the list.
else if (i+1 >= 0 && i+1 < maze.length && maze[i+1][j] == '0' && searched.contains(south)==false)
{
searched.push(south);
path.push(current);
path.push(south);
}
//check west.
else if (j-1 >= 0 && j-1 < maze.length && maze[i][j-1] == '0' && searched.contains(west)==false)
{
searched.push(west);
path.push(current);
path.push(west);
}
//check north
else if (i-1 >= 0 && i-1 < maze.length && maze[i-1][j] == '0' && searched.contains(north)==false)
{
searched.push(north);
path.push(current);
path.push(north);
}
}
return null;
}
I would guess that the problem lies, not in the code you posted, but rather in the Position class. If you have not overridden hashcode() and equals() in the Position class, the contains() comparison here will be looking for object equality.
So when you ask if searched.contains(east), having just created east as a new object, it will return false, even though east's coordinates perfectly match what is already in your search.
See this answer for more.
A common solution to solving a maze is BFS, which is both optimal and complete [it always find a solution if there is one, and also it finds the shortest one].
Using a stack, is actually simulating a DFS, which is not optimal.
About the specific problem, where contains() doesn't do its job, it will be hard to know what the problem is without the source for the class Position, but a possible reason is you did not override equals(), so the default equals() is still checking for identity, and not equality - which is obviously not true.

Categories