What is wrong with my Java recursive function? - java

I'm trying to write a relatively straightforward recursive program in Java to compute all the possible ways to traverse a 4x4 matrix (not necessarily traveling through every spot), starting at the top left and ending in the bottom right spaces. I use a 2-D array to do this, marking off visited spaces with "1"s as I go.
It's been a while since I've worked recursively and I can't seem to get the output I expect. The output from the code below is "2" - obviously, the result should be much higher. I know there's something tiny I'm overlooking. Can someone tell me what it is?
public static void main(String[] args) {
int[][] matrix = new int[4][4];
int result = moveRobot(matrix, 0, 0);
System.out.print(result + "");
}
public static int moveRobot(int[][] matrix, int x, int y) {
if (x == 3 && y == 3) {
return 1;
} else if (x < 0 || y < 0 || x > 3 || y > 3) {
return 0;
} else if (matrix[x][y] == 1) {
return 0;
} else {
matrix[x][y] = 1;
return moveRobot(matrix, x, y+1) + moveRobot(matrix, x+1, y) + moveRobot(matrix, x, y-1) +
moveRobot(matrix, x-1, y);
}
}

The problem is that the matrix is not copied but passed by value of the reference to it. Every time you modify it such in matrix[x][y] = 1 other successive code paths will see the modification instead that working on an unmodified state.
For example here:
moveRobot(matrix, x, y+1) + moveRobot(matrix, x+1, y)
Entering the first call will modify matrix, so in second moveRobot call you'd end up with 1 in matrix[x][y+1] while that's not what you want.

Related

Difficulty in writing a recursive solution to "Rat in a maze" problem

My question is essentially a doubt about recursion. I was solving the classic "Rat in a Maze" DFS traversal problem. My input was an n*n int array a[][] where for indices i and j, a[i][j] could either be 0 or 1. 0 meant the hypothetical rat couldn't visit the element and 1 meant it could. The rat could only go downwards("D") or rightwards("R"). The task was to output all movement Strings like RDRDRD that represented the rat's movement through the maze. The rat starts from a[0][0] and must reach a[n-1][n-1]. The input was the maze itself.
I wrote the following code
public boolean isSafe(int x, int y, int[][] a, int n)
{
if(x >= 0 && x < n && y >= 0 && y < n && a[x][y] == 1)
return true;
else
return false;
}
public ArrayList<String> printPath(int[][] a, int n)
{
ArrayList<String> res = new ArrayList<String>();
solve(0,0,new String(), res,a,n);
return res;
}
public void solve(int x, int y, String sol, ArrayList<String> res ,
int[][]a, int n)
{
if(x == n-1 && y == n-1)
{
res.add(sol);
return;
}
y++;
if(isSafe(x,y,a,n))
{
solve(x,y,sol + "R",res,a,n);
}
else
y--;
x++;
if(isSafe(x,y,a,n))
{
solve(x,y,sol+"D",res,a,n);
}
else
x--;
}`
where isSafe check whether a movement is permitted, printPath is a helper function for printing the output and solve is the recursive function used to traverse the maze.a represents the maze array as a 2-D array.
For the input
{1 0 0 0
1 1 0 1
0 1 0 0
0 1 1 1}
I get the following output
DRDDRR DDDRR
Obviously the second string represents an incorrect result.
However, when I changed the solve function like so
public void solve(int x, int y, String sol, ArrayList<String> res,
int[][]a, int n)
{
if(x == n-1 && y == n-1)
{
res.add(sol);
return;
}
if(!isSafe(x,y,a,n))
return;
solve(x+1,y,sol + "D",res,a,n);
solve(x,y+1,sol + "R",res,a,n);
return;
}
I get the correct output. What I am failing to understand is what resulted in the incorrect output in my previous solution, as to me the two solutions are logically similar.
I know it's a long read, but any insight would be greatly appreciated.
In the first solution the variable increment y++ is only undone if the call to isSafe with the incremented value comes back negative and is carried over to the check of x if it was true. This means that the down check on a field that has a valid neighbor to the right, in particular the field [1][0], will be performed with the incremented value of y instead of the correct one.
If you modify the first solution like this
y++;
if(isSafe(x,y,a,n)){
solve(x,y,sol + "R",res,a,n);
}
y--;
the first solution will work correctly as does the second one. In the second solution the increment is only done on the function argument, not a local variable.
A general advice is to not modify your input. And it is the case that your problem comes from just that. Here I modified your code so it doesn't do that. It's much more readable in my opinion and now you're sure of what x or y value you're using.:
if (isSafe(x, y + 1, a, n)) {
solve(x, y + 1, sol + "R", res, a, n);
}
if (isSafe(x + 1, y, a, n)) {
solve(x + 1, y, sol + "D", res, a, n);
}

Multiplication using increments

My assignment is to write a recursive function to multiply two numbers together, using only an addition function, ++, and --. My addition function is:
public static int peanoplus(int x, int y) {
if(y==0) return x;
else return peanoplus(++x,--y);
}
What I have so far for my multiplication function is:
public static int peanotimes(int x, int y)
{
if(y==0) return x;
else return peanotimes(peanoplus(x,x),--y);
}
I am not exactly sure what to put in the first parameter for the peanotimes function. Right now the issue is that I'm doubling the number, rather than adding it to the original number. I know that I need to maintain the x variable so that the recursive calls can continue adding the original number (instead of doubling every time), but then where would I actually add the numbers?
I found this which is very similar to my question, but even with those tips I am unable to find a solution.
if( y == 0 || x == 0 ) { return 0; }
else { return peanoplus(x, peanotimes(x,--y)); }
This version closest matches the formal Peano axiom of x * S(y) = x + (x * y)
public static int peanotimes(int x, int y)
{
if (y == 0) {
return 0; // terminate recursion, NB: not "x"
} else {
return peanoplus(x, peanotimes(x, --y));
}
}

Mathematical induction of this Code?

I don't really understand how I use proof by induction on this Code.
I just wanna know how to prove the correctness of this code and algorithm.
Prove that we will never count items which already counted .
Algorithm for countCells(x,y)
if the cell at(x,y) is outside
the grid the result is 0;
else if
the color of the cell at (x, y) is not the abnormal color the result is 0;
else
set the color of the cell at (x, y) to a temporary
color; the result is 1 plus the number of cells in each piece of the
blob that includes a nearest neighbor;
public int countCells(int x, int y)
{
int result;
if(x<0 || x>=N || y<0 || y>=N) // N is the maximum value of the matrix
return 0;
else if(!getColor(x,y).equals(ABNORMAL)) //
return 0;
else
{
recolor(x, y, TEMPORARY);
return 1 + countCells(x-1, y+1) + countCells(x, y+1)
+ countCells(x+1, y+1) + countCells(x-1, y)
+ countCells(x+1, y) + countCells(x-1, y-1)
+ countCells(x, y-1) + countCells(x+1, y-1)
}
}
the following link show how this works
http://kin.naver.com/qna/detail.nhn?d1id=1&dirId=104&docId=186514818
Proof by induction
Prove for base case condition (n = 1)
Prove for all assumption step ( n = k )
Prove for inductive step + 1 (n = k + 1)
So call your function with a base for step 1, let k equal some other generic input, then do the input + 1.
Basically you want to test the edge cases of your functions to ensure that they work properly. Your teacher probably wants you to just write test conditions for the function above.

Recursive method - Java

Addition information:
Chip doesn't support multiplication, only addition. I should work around this problem by creating a recursive method, mult(), that performs multiplication
of x and y by adding x to itself y times. Its arguments are x and y and its return
value is the product of x and y. I should then write the method and a main() to
call it.
It's pure logical thinking, but I get lost every time I try to think what to do.
I am stuck at the math part..
What I have, that doesn't work and I know the math is wrong, but I am not good at this:
public static void mult(int x, int y) {
x = 0;
y = 0;
if (y > 0) {
for (int i = 0; i < y; i++) {
x = x * (x * y);
return mult(x, y);
}
}
}
When I hear "recursion", I expect to see two things:
A function calling itself with modified arguments each time.
A stopping condition right at the top that tells the function when to stop, avoiding an infinite stack.
So where are yours? Start with writing those down in words before you write code.
One possibility is to use an accumulator which will store the current value of the multiplication. I replace missing statements by ??? :
public static void main(String []args){
System.out.println(mult(2,5));
}
public static int mult(int x, int y) {
if(???) return ???;
else return multAcc(???,???,???);
}
private static int multAcc(int x, int y, int acc){
if(???) return ???;
else return multAcc(???, ???, ???);
}
... by adding x to itself y times.
You could actually do that, instead of multiplying. Oh, and maybe if you don't set both x and y to zero, you would have something to add ;-)
One last thing: If you want a recursive solution, you don't need the for-loop.
Java has no TCO by design, so using recursion for linear (not tree-like) processes is very bad idea. Especially for such task, which will most likely become a bottleneck in your program. Use loop instead.
Oh, it must be recursive anyway? Looks like a homework task. Do it yourself then.
All you need to remember is that a multiplication is a repeated addition (assuming that both operands are >= 0), so we have:
The base case is when y is zero
If y is not zero, then add x one more time, and subtract 1 from y
Notice that as long as y is positive, it'll eventually have a value of zero. So basically we keep adding x a total number of y times; this is what I mean:
public static int mult(int x, int y) {
if (y == 0)
return 0;
return x + mult(x, y-1);
}
The same code can be written in a tail-recursive style, too - meaning: there's nothing to do after the recursive call returns, and this is important for certain languages that support a so-called tail-call optimization:
public static int mult(int x, int y, int accumulator) {
if (y == 0)
return accumulator;
return mult(x, y-1, x + accumulator);
}
The above will get called as follows, noticing that the last parameter is always initialized in zero:
mult(10, 5, 0)
=> 50
public static int mult(int x, int y) {
if (y == 0) {
return 0;
}
if (y > 0) {
return x + mult(x, y - 1);
} else {
return -x + mult(x, y + 1);
}
}
this was the solution by the way

Calculating direction based on point offsets

For my tile-based game, I need to calculate direction based on a given point offset (difference between two points). For example, let's say I'm standing at point (10, 4) and I want to move to point (8, 6). The direction I move at is north-west. What would be the best way to calculate this?
Here's me basic implementation in Java.
public int direction(int x, int y) {
if (x > 0) {
if (y > 0) {
return 0; // NE
} else if (y < 0) {
return 1; // SE
} else {
return 2; // E
}
} else if (x < 0) {
if (y > 0) {
return 3; // NW
} else if (y < 0) {
return 4; // SW
} else {
return 5; // W
}
} else {
if (y > 0) {
return 6; // N
} else if (y < 0) {
return 7; // S
} else {
return -1;
}
}
}
Surely it can be optimised or shortened. Any help? Thanks.
I think the easiest to understand way would be making a static array that contains the values for all cases.
// Won't say anything about how much these values make sense
static final int[][] directions = {
{3, 6, 0},
{5, -1, 2}, // -1 for "no direction", feel free to replace
{4, 7, 1}
};
public int direction(int x, int y) {
x = (x < 0) ? 0 : ((x > 0) ? 2 : 1);
y = (y < 0) ? 0 : ((y > 0) ? 2 : 1);
return directions[y][x];
}
Edit: Now it's correct (why are so many languages missing a proper sgn function?)
My answers with if conditions :).
public int direction(int x, int y) {
//0 NE, 1 SE, 2 E, 3 NW, 4 SW, 5 W, 6 N, 7 S, 8 (Same place / Not a direction)
int direction = 0;
if(x < 0){
direction = 3;
}else if(x == 0){
direction = 6;
}
if(y < 0){
direction = direction + 1;
}else if(y == 0){
direction = direction + 2;
}
return direction;
}
define a 2D array to hold all states.
convert x and y to 0, 1 or 2 based on their value (x>0 or x<0 or x ==0)
return the specific index of array.
This is about as short and clean as you can get, if you represent the eight cardinal directions this way, as separate enumerated values. You're choosing between eight distinct return values, so a decision tree with eight leaves is the best you can do.
You might get something a little tidier if you split direction into two components (N-S and E-W), but without knowing more about what you do with direction, we can't know whether that's worth the trouble.
You can receive and return your direction as a Point or something similar (anyway, an (x,y) tuple). So if you're standing in p0 = (10, 4) and want to move to p1 = (8, 6), the result would be (in pseudocode):
norm(p1 - p0) = norm((-2,2)) = (-1,1)
You can calculate the norm of an integer if you divide it by its absolute value. So for a point you calculate the norm of both members. Just bear in mind that (-1,1) is more expressive than 3 and you can operate in an easier fashion with it.
If you need specific operations, you can create your own Java Point class or extend the existing ones in the library.

Categories