I understand what tail recursion is but I am having trouble converting this method to tail recursion. I am trying to count how many adjacent elements there are in a matrix. Therefore, my question is how would you turn this into a tail recursion?
public static int ExploreAndLabelColony(char[][] grid, int i, int j, char c,int count) {
grid[i][j] = c;
count = 1;
if ((i>0 && i<grid.length && j<grid[0].length) && (grid[i-1][j] == '1')) { //vertical bottom
count +=ExploreAndLabelColony(grid, i-1,j,c,count);
}
if (i+1<grid.length && j<grid[0].length && grid[i+1][j] == '1') { //vertical top
count+=ExploreAndLabelColony(grid, i+1,j ,c,count);
}
if (j>0 && i<grid.length && j<grid[0].length && grid[i][j-1] == '1') { //horizontal left
count +=ExploreAndLabelColony(grid, i,j-1 ,c,count);
}
if (i<grid.length && j+1<grid[0].length && grid[i][j+1] == '1') { //horizontal right
count+=ExploreAndLabelColony(grid, i,j+1 ,c,count);
}
if (i+1<grid.length && j+1<grid[0].length && grid[i+1][j+1] == '1') { //diagonal bottom right
count+=ExploreAndLabelColony(grid, i+1,j+1 ,c,count);
}
if (j>0 && i+1<grid.length && j<grid[0].length && grid[i+1][j-1] == '1') { //diagonal bottom right
count+=ExploreAndLabelColony(grid, i+1,j-1 ,c,count);
}
if (i>0 && i<grid.length && j+1<grid[0].length && grid[i-1][j+1] == '1') { //diagonal top right
count+=ExploreAndLabelColony(grid, i-1,j+1 ,c,count);
}
if (i>0 && j>0 && i<grid.length && j<grid[0].length && grid[i-1][j-1] == '1') { //diagonal top left
count+=ExploreAndLabelColony(grid, i-1,j-1 ,c,count);
}
return count;
}
This might qualify as tail recursion:
static class Queue {
int i;
int j;
Queue next;
Queue(int i, int j, Queue next) {
this.i = i;
this.j = j;
this.next = next;
}
}
int exploreAndLabel(char[][] grid, int i, int j, char c) {
return exploreAndLabel(new Queue(i, j, null), grid, c, 0);
}
int exploreAndLabel(Queue queue, char[][] grid, char c, int count) {
if (queue == null) {
return count; // no more work
}
int i = queue.i;
int j = queue.j;
queue = queue.next;
if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length) {
// outside grid
} else if (grid[i][j] != '1') {
// outside colony
} else {
grid[i][j] = c; // label
count++;
queue = new Queue(i - 1, j - 1, queue);
queue = new Queue(i - 1, j, queue);
queue = new Queue(i - 1, j + 1, queue);
queue = new Queue(i, j - 1, queue);
queue = new Queue(i, j + 1, queue);
queue = new Queue(i + 1, j - 1, queue);
queue = new Queue(i + 1, j, queue);
queue = new Queue(i + 1, j + 1, queue);
}
return exploreAndLabel(queue, grid, c, count);
}
and here is a test:
#Test
public void testTailRecursion() {
char[][] grid = Stream.of(
"00000101",
"00001101",
"00111010")
.map(String::toCharArray)
.toArray(char[][]::new);
int count = exploreAndLabel(grid, 2, 3, '2');
Assert.assertEquals(9, count);
}
I am trying to find all adjacent elements in the matrix. Adjacent refers to elements being right beside each other either horizontal, vertical and diagonal elements. However it is giving me java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5. I am not sure why, any help would be much appreciated! Also the program needs to be recursive !
class matrixAdjacent
{
public static void main(String[] args)
{
char grid[][] = {{'0','0','0','1','1','0','1','1','0','0','0','1','1','1','0','1','1','1','0','1'},
{'1','0','0','0','0','1','0','0','0','1','0','0','0','0','0','1','1','1','1','1'},
{'0','1','0','0','1','0','0','0','1','0','1','0','0','0','0','0','0','1','1','1'},
{'1','1','1','0','0','1','0','1','0','0','0','0','1','0','1','1','0','1','1','0'},
{'0','1','1','1','0','1','1','1','0','1','0','0','1','0','1','0','1','1','0','1'}};
ExploreAndLabelColony(grid, 0, 0);
}
private static void ExploreAndLabelColony(char[][] grid, int i, int j)
{
// TODO Auto-generated method stub
if(grid==null)
{
return;
}
if(i==grid.length || j==grid[0].length)
{
return;
}
if (grid[i][j] == '1') //checks if theres a 1 which refers to a colony
{
if (i>0 && i + 1 < grid.length && j>0 && j + 1 < grid[0].length)
{
if (grid[i+1]==grid[j] || grid[i] == grid[j+1] || grid[i-1]==grid[j] || grid[i]==grid[j-1]) //checks if adjacent
{
grid[i][j] = 'A'; //creates a colony
}
}
}
else if(grid[i][j] == '0') //replaces 0 with '-'
{
grid[i][j] = '-';
}
System.out.print(grid[i][j]); //print grid
if(j==grid[0].length-1)
{
System.out.println(); //prints next row
ExploreAndLabelColony(grid,i+1,0); //recurse to increment row
}
ExploreAndLabelColony(grid,i,j+1); //recurse to increment column
}
}
Issues
if (i>0 && i + 1 < grid.length && j>0 && j + 1 < grid[0].length)
{
if (grid[i+1]==grid[j] || grid[i] == grid[j+1] || grid[i-1]==grid[j] || grid[i]==grid[j-1]) //checks if adjacent
{
grid[i][j] = 'A'; //creates a colony
}
}
In the above section of code, j>0 && j + 1 < grid[0].length can not guarantee the access to grid[j].
The check on inner array index can not correctly validate the access to outer array index.
Check adjacent elements
To check adjacent elements, all 4 valid adjacent indices have to be checked
grid[i][j - 1]
grid[i][j + 1]
grid[i - 1][j]
grid[i + 1][j]
In the above 4 checks, please validate the index before making any of the i - 1, i + 1, j - 1, j + 1 access.
For the given cell with coordinates i, j the adjacent elements are in the square:
[i - 1][j - 1], [i - 1][j], [i - 1][j + 1]
[i ][j - 1], CURR_CELL, [i ][j + 1]
[i + 1][j - 1], [i + 1][j], [i + 1][j + 1]
Additional limitations may be applied using Math.min, Math.max functions and adjacent cells can be detected as follows:
if (grid[i][j] == '1') { //checks if theres a 1 which refers to a colony
out: // label to break
for (int ii = Math.max(i - 1, 0), in = Math.min(grid.length, i + 2); ii < in; ii++) {
for (int jj = Math.max(j - 1, 0), jn = Math.min(grid[0].length, j + 2); jj < jn; jj++) {
if (ii == i && jj == j) {
continue; // skip reference cell
}
if (grid[ii][jj] == '1') {
grid[i][j] = 'A';
break out; // as soon as the first neighbor is found
}
}
}
}
With this change, the output for the given input:
public static void main(String[] args) {
char grid[][] = {
{'0','0','0','1','1','0','1','1','0','0','0','1','1','1','0','1','1','1','0','1'},
{'1','0','0','0','0','1','0','0','0','1','0','0','0','0','0','1','1','1','1','1'},
{'0','1','0','0','1','0','0','0','1','0','1','0','0','0','0','0','0','1','1','1'},
{'1','1','1','0','0','1','0','1','0','0','0','0','1','0','1','1','0','1','1','0'},
{'0','1','1','1','0','1','1','1','0','1','0','0','1','0','1','0','1','1','0','1'}
};
ExploreAndLabelColony(grid, 0, 0);
}
is as follows:
---AA-A1---AA1-AAA-A
A----A---A-----AAAAA
-A--A---A-1------AAA
AAA--A-A----A-AA-AA-
-AA1-AA1-1--1-1-A1-1
Possibly, condition should be fixed to check if adjacent cell is already containing A, or if there are too many neighbors but setting/applying these or any other rules is up to the author.
Given a NxN matrix (which contains Boolean values - true / false).
We will define:
true region in an array as a maximum collection of adjacent cells that all have a true value.
Cells located diagonally to each other are not considered adjacent.
In this example, there are 3 true areas:
True Regions
My Solution attemp in Java:
public static int (boolean[][] mat) {
return GetTrueRegions(mat, 0, 0);
}
public static int GetTrueRegions(boolean[][] m, int i , int j) {
final boolean VISITED = false;
if (i == m.length - 1 && j == m[0].length - 1)
return 0;
// avoid repeat a cell
boolean temp = m[i][j];
m[i][j] = VISITED;
// recursion for all neighbors
int up = -1, down = -1, left = -1, right = -1;
if (i - 1 >= 0 && m[i-1][j] )
up = GetTrueRegions(m, i - 1, j);
if (i + 1 < m.length && m[i+1][j])
down = GetTrueRegions(m, i + 1, j);
if (j - 1 >= 0 && m[i][j-1])
left = GetTrueRegions(m, i, j - 1);
if (j + 1 < m[0].length && m[i][j+1] )
right = GetTrueRegions(m, i, j + 1);
// couldn't find a path
if (temp) {
return 1 + GetTrueRegions(m, i, j + 1);
}
if (up == -1 && down == -1 && left == -1 && right == -1 )
return GetTrueRegions(m, i, j +1);
return up + down + left + right;
}
this obviously not working.
I was thinking about going through each cell, and if the cell has true value, adding 1 to the total regions(somehow), and put the value false to him and to each adjacent cell(mark the region as "visited").
though I find it hard for me to get the base cases, and how to get every region value.
try to look at something like that:
public static int GetTrueRegions(boolean[][] mat)
{
return GetTrueRegions(mat, 0, 0);
}
private static int GetTrueRegions(boolean[][] m, int i, int j)
{
if (j == m[0].length)
return 0;
if (i == m.length)
return GetTrueRegions(m, 0, j + 1);
// found a region
if (m[i][j])
{
// mark the entire region, to avoid duplications
markRegionAsFalse(m, i, j);
// count 1 region and proceed
return 1 + GetTrueRegions(m, i + 1, j);
}
// proceed...
return GetTrueRegions(m, i + 1, j);
}
private static void markRegionAsFalse(boolean[][] matrix, int row, int col)
{
// just visited...
matrix[row][col] = false;
if(row - 1 >= 0 && matrix[row - 1][col]) // move up and mark cell if true
markRegionAsFalse(matrix, row - 1, col);
if (row < matrix.length - 1 && matrix[row + 1][col]) // move down and mark cell if true
markRegionAsFalse(matrix, row + 1, col);
if (col < matrix.length - 1 && matrix[row][col + 1]) // move right and mark cell if true
markRegionAsFalse(matrix, row, col + 1);
if(col - 1 >= 0 && matrix[row][col - 1]) // move left and mark cell if true
markRegionAsFalse(matrix, row, col - 1);
}
My checkWin method returns false until there's a winner in the Connect 4 game by putting 4 "checkers" in a row horizontally, vertically, or diagonally in my board array. Once there's a winner, the checkWin method returns true, the nearest if statement iterates, printing the winner, then terminating the entire loop (if I coded it all correctly). However, when I run the program, the while loop iterates only once, accepts one input for red, states red won, then does the same thing for yellow, then terminates.
What am I missing here?
Below is the relevant code.
Thank you.
public static void main(String[] args) {
char[][] board = new char[6][7];
boolean loop = true;
// loop to alternate players until there's a winner
while (loop) {
printData(board);
red(board);
if (checkWin(board) == true) {
printData(board);
System.out.print("Red wins!");
loop = false;
}
printData(board);
yellow(board);
if (checkWin(board) == true) {
printData(board);
System.out.print("Yellow wins!");
loop = false;
}
}
}
public static void printData(char[][] tbl) {
for (int r = 0; r < tbl.length; r++) {
for (int c = 0; c < tbl[r].length; c++) {
if (tbl[r][c] == 0) {
System.out.print("| ");
} else {
System.out.print("|" + tbl[r][c]);
}
} // end for col loop
System.out.println("|");
} // end for row loop
System.out.println("---------------");
} // end printData method
public static void red(char[][] f) {
System.out.println("Place a red checker at column (0-6)");
Scanner in = new Scanner(System.in);
int c = in.nextInt();
for (int i = 5; i >= 0; i--) {
if (f[i][c] == 0) {
f[i][c] = 'R';
break;
}
}
}
public static void yellow(char[][] f) {
System.out.println("Place a yellow checker at column (0-6)");
Scanner in = new Scanner(System.in);
int c = in.nextInt();
for (int i = 5; i >= 0; i--) {
if (f[i][c] == 0) {
f[i][c] = 'Y';
break;
}
}
}
// Method to check for a winner. Receives 2-D array as parameter. Returns
// boolean value.
public static boolean checkWin(char[][] b) {
// Create four boolean variables, one for each set of rows. Initialize
// all of them to false.
boolean foundRow = false;
boolean foundCol = false;
boolean foundMjrD = false;
boolean foundMinD = false;
// Check to see if four consecutive cells in a row match.
// check rows
for (int r = 0; r <= 5; r++) {
for (int c = 0; c <= 3; c++) {
if (b[r][c] == b[r][c + 1] && b[r][c] == b[r][c + 2] && b[r][c] == b[r][c + 3] && b[r][c] != ' ') {
foundRow = true;
break;
}
}
}
// Check to see if four columns in the same row match
// check columns
for (int r = 0; r <= 2; r++) {
for (int c = 0; c <= 6; c++) {
if (b[r][c] == b[r + 1][c] && b[r][c] == b[r + 2][c] && b[r][c] == b[r + 3][c] && b[r][c] != ' ') {
foundCol = true;
break;
}
}
}
// Check to see if four diagonals match (top left to bottom right)
// check major diagonal
for (int r = 0; r <= 2; r++) {
for (int c = 0; c <= 3; c++) {
if (b[r][c] == b[r + 1][c + 1] && b[r][c] == b[r + 2][c + 2] && b[r][c] == b[r + 3][c + 3]
&& b[r][c] != ' ') {
foundMjrD = true;
break;
}
}
}
// Check to see if four diagonals in the other direction match (top
// right to bottom left)
// check minor diagonal
for (int r = 0; r <= 2; r++) {
for (int c = 3; c <= 6; c++) {
if (b[r][c] == b[r + 1][c - 1] && b[r][c] == b[r + 2][c - 2] && b[r][c] == b[r + 3][c - 3]
&& b[r][c] != ' ') {
foundMinD = true;
break;
}
}
}
// If ONE of the booleans is true, we have a winner.
// checks boolean for a true
if (foundRow || foundCol || foundMjrD || foundMinD)
return true;
else
return false;
} // end checkWin method
By what I've analyzed by debugging your code , you have not set boolean variable to "true" after toggling it to false. After you are coming out of condition make that boolean variable "true" again.
May this help you. Happy Coding
You should take a closer look at this line:
if (b[r][c] == b[r][c + 1] && b[r][c] == b[r][c + 2] && b[r][c] == b[r][c + 3] && b[r][c] != ' ') {
You check for b[r][c] != ' ', but you never put a space in char[][] board, therefore the default value in board[?][?] is 0.
In our assignment we are only allowed to use one method. I didn't know about that and I wrote two. So I wanted to ask, if its somehow possible to integrate the function of my neighbourconditions method into the life method. I tried, but I don't know how to initialize my int neighbors. Look at the following code:
public static String[] life(String[] dish) {
String[] newGen = new String[dish.length];
//TODO: implement this function
for (int line = 0; line < dish.length; line++) { // for loop going through each line
newGen[line] = "";
for (int i = 0; i < dish[line].length(); i++) { // loops through every character in the line
String top = ""; // neighbours on the top
String middle = ""; // neighbors on the same line
String down = ""; // neighbors down
if (i == 0){
if(line == 0){
top = null;
} else {
top = dish[line-1].substring(i, i+2);
}
middle = dish[line].substring(i + 1, i +2);
if(line == dish.length -1){
down = null;
} else {
down = dish[line + 1].substring(i, i + 2);
}
} else if (i == dish[line].length() - 1){
if(line == 0){
top = null;
} else {
top = dish[line - 1].substring(i - 1, i + 1);
}
middle = dish[line].substring(i - 1, i);
if(line == dish.length - 1){
down = null;
} else {
down = dish [line + 1].substring(i - 1, i + 1);
}
} else {
if (line == 0){
top = null;
} else {
top = dish[line - 1].substring(i - 1, i + 2);
}
middle = dish[line].substring(i - 1, i) + dish[line].substring(i+1, i+2);
if (line == dish.length - 1){
down = null;
} else {
down = dish[line + 1].substring(i - 1, i + 2);
}
}
int neighbors = neighbourconditions(top, middle, down);
if (neighbors < 2 || neighbors > 3){ // neighbours < 2 or >3 neighbors -> they die
newGen[line] += "o";
} else if (neighbors == 3){
newGen[line] += "x"; // neighbours exactly 3 -> they spawn/live
} else {
newGen[line] += dish[line].charAt(i); // 2 neighbours -> stay
}
}
}
return newGen;
}
// helpmethod with three arguments and the conditions
public static int neighbourconditions(String top, String middle, String down) {
int counter = 0;
if (top != null) { // if no one's on top
for (int x = 0; x < top.length(); ++x) {
if (top.charAt(x) == 'x') {
counter++; // count if an organism's here
}
}
}
for (int x = 0; x < middle.length(); ++x) {
if (middle.charAt(x) == 'x') { // two organisms, one on each side
counter++; // count if an organism's here
}
}
if (down != null) { // if no one's down
for (int x = 0; x < down.length(); ++x) {
if (down.charAt(x) == 'x') { // each neighbour down
counter++; // count if an organism's here
}
}
}
return counter;
}
Everything you do inside the second function will have to be done in the first function. So just copy the code from function 2 into function 1:
public static String[] life(String[] dish){
String[] newGen= new String[dish.length];
//TODO: implement this functions
for(int row = 0; row < dish.length; row++){ // each row
newGen[row]= "";
for(int i = 0; i < dish[row].length(); i++){ // each char in the row
String above = ""; // neighbors above
String same = ""; // neighbors in the same row
String below = ""; // neighbors below
if(i == 0){ // all the way on the left
// no one above if on the top row
// otherwise grab the neighbors from above
above = (row == 0) ? null : dish[row - 1].substring(i, i + 2);
same = dish[row].substring(i + 1, i + 2);
// no one below if on the bottom row
// otherwise grab the neighbors from below
below = (row == dish.length - 1) ? null : dish[row + 1].substring(i, i + 2);
}else if(i == dish[row].length() - 1){//right
// no one above if on the top row
// otherwise grab the neighbors from above
above = (row == 0) ? null : dish[row - 1].substring(i - 1, i + 1);
same = dish[row].substring(i - 1, i);
// no one below if on the bottom row
// otherwise grab the neighbors from below
below = (row == dish.length - 1) ? null : dish[row + 1].substring(i - 1, i + 1);
}else{ // anywhere else
// no one above if on the top row
//otherwise grab the neighbors from above
above = (row == 0) ? null : dish[row - 1].substring(i - 1, i + 2);
same = dish[row].substring(i - 1, i) + dish[row].substring(i + 1, i + 2);
//no one below if on the bottom row
//otherwise grab the neighbors from below
below = (row == dish.length - 1) ? null : dish[row + 1].substring(i - 1, i + 2);
}
// here is the interesting part for you:
int neighbors = 0;
if(above != null){//no one above
for(char x: above.toCharArray()){ //each neighbor from above
if(x == 'x') neighbors++; //count it if someone is here
}
}
for(char x: same.toCharArray()){ //two on either side
if(x == 'x') neighbors++;//count it if someone is here
}
if(below != null){ //no one below
for(char x: below.toCharArray()){//each neighbor below
if(x == 'x') neighbors++;//count it if someone is here
}
};
//here ends the interesting part for you
if(neighbors < 2 || neighbors > 3){
newGen[row]+= "o"; // If the amount of neighbors is < 2 or >3 neighbors -> they die
}else if(neighbors == 3){
newGen[row]+= "x"; // If the amount of neighbors is exactly 3 neighbors -> they spawn/live
}else{
newGen[row]+= dish[row].charAt(i); // 2 neighbors -> stay
}
}
}
return newGen;
}
The trivial answer to this question is to copy and paste the code from the method into the body of the other method. If you're using an IDE, you can use the in-built refactoring tools to inline the method (e.g. ctrl-alt-n, in intellij).
But this is the sort of behavior that makes future generations curse your name. It makes for nasty, unreadable, unmaintainable code. Don't do it. As GhostCat pointed out in comments, you should be looking to make methods smaller, not bigger.
Take a step back, and consider whether you're approaching the problem in the right way. Look for repeating patterns in the existing code, to see if you can simplify it. Or, sometimes, consider that you've just taken the wrong approach in the first place, and so you need to find an alternative approach.
As far as I can work out, all you're trying to do is to count the number of xs in the 8 cells immediately surrounding the current position.
You don't need all of this code to do that. You could simply do:
for(int row = 0; row < dish.length; row++){ // each row
for(int col = 0; col < dish[row].length(); col++){ // each char in the row
int neighbors = 0;
for (int r = Math.max(row - 1, 0); r < Math.min(row + 2, dish.length); ++r) {
for (int c = Math.max(col - 1, 0); c < Math.min(col + 2, dish[row].length()); ++c) {
// Don't count (row, col).
if (r == row && c == col) continue;
if (dish[r].charAt(c) == 'x') ++neighbors;
}
}
//here ends the interesting part for you
if(neighbors < 2 || neighbors > 3){
// etc.
Way less code, no need for an auxiliary method. Also a lot more efficient, because it avoids unnecessarily creating strings.