Java recursion Issue with the flood fill algorithm - java

I am trying to write a program to locate and count all connected regions in a grid. A connected region consists of a set of marked cells (value 1) such that each cell in the region can be reached by moving up, down, left or right from another marked cell in the region, cells on a diagonal line are not considered connected.
So, it would take an input of:
10 20
0 1 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0
0 1 1 1 0 1 1 0 0 1 0 0 1 1 1 0 0 0 1 1
0 0 1 0 0 0 1 1 0 1 0 0 0 1 0 0 0 1 1 1
1 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 1 1 0
1 1 0 1 0 0 0 1 1 1 0 0 0 1 1 0 1 1 0 0
1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 0 1 1 0 1 0 0 0
0 1 1 1 1 1 0 0 1 1 1 0 0 0 1 1 1 1 1 0
0 0 0 1 1 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0
1 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 0 1 0 0
And outputs:
0 1 1 0 0 0 2 0 3 3 0 0 0 0 4 0 0 0 5 0
0 1 1 1 0 2 2 0 0 3 0 0 4 4 4 0 0 0 5 5
0 0 1 0 0 0 2 2 0 3 0 0 0 4 0 0 0 5 5 5
6 0 0 0 0 0 0 0 3 3 0 0 7 0 0 0 5 5 5 0
6 6 0 6 0 0 0 3 3 3 0 0 0 8 8 0 5 5 0 0
6 6 6 6 0 0 0 0 0 0 9 0 8 8 8 0 0 0 0 0
0 6 6 6 0 0 0 9 9 9 9 0 0 8 8 0 8 0 0 0
0 6 6 6 6 6 0 0 9 9 9 0 0 0 8 8 8 8 8 0
0 0 0 6 6 0 0 0 0 9 0 0 0 8 8 0 0 8 8 0
10 0 6 6 6 6 6 0 0 0 0 0 0 0 8 8 0 8 0 0
Right now, when I run the code, I get:
0 2 2 0 0 0 2 0 2 2 0 0 0 0 2 0 0 0 2 0
0 3 3 3 0 3 3 0 0 3 0 0 3 3 3 0 0 0 3 3
0 0 4 0 0 0 4 4 0 4 0 0 0 4 0 0 0 4 4 4
5 0 0 0 0 0 0 0 5 5 0 0 5 0 0 0 5 5 5 0
6 6 0 6 0 0 0 6 6 6 0 0 0 6 6 0 6 6 0 0
7 7 7 7 0 0 0 0 0 0 7 0 7 7 7 0 0 0 0 0
0 8 8 8 0 0 0 8 8 8 8 0 0 8 8 0 8 0 0 0
0 9 9 9 9 9 0 0 9 9 9 0 0 0 9 9 9 9 9 0
0 0 0 10 10 0 0 0 0 10 0 0 0 10 10 0 0 10 10 0
11 0 11 11 11 11 11 0 0 0 0 0 0 0 11 11 0 11 0 0
Here is my code:
package project2;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;
public class Project2 {
private static int height;
private static int length;
public static void main(String[] args) {
String inputFile;
Scanner input = new Scanner(System.in);
System.out.print("Enter input file name: ");
inputFile = "test_case_proj2.txt";
try {
Integer grid[][] = loadGrid(inputFile);
System.out.println("Before flood fill");
printGrid(grid);
findGroups(grid, 0, 0, 2, height, length);
System.out.println("After flood fill");
printGrid(grid);
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
public static void findGroups(Integer[][] array, int column, int row,
int counter, int height, int length) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < length; j++) {
if (row < 0 || row >= length || column < 0 || column >= height) {
} else {
if (array[column][j] == 1) {
array[column][j] = counter;
findGroups(array, column, row + 1, counter, height, length);
findGroups(array, column, row - 1, counter, height, length);
findGroups(array, column - row, j, counter, height, length);
findGroups(array, column + row, j, counter, height, length);
}
}
}
counter++;
column++;
row++;
}
}
public static Integer[][] loadGrid(String fileName) throws IOException {
FileInputStream fin;
fin = new FileInputStream(fileName);
Scanner input = new Scanner(fin);
height = input.nextInt();
length = input.nextInt();
Integer grid[][] = new Integer[height][length];
for (int r = 0; r < height; r++) {
for (int c = 0; c < length; c++) {
grid[r][c] = input.nextInt();
}
}
fin.close();
return (grid);
}
public static void printGrid(Integer[][] grid) {
for (Integer[] grid1 : grid) {
for (int c = 0; c < grid[0].length; c++) {
System.out.printf("%3d", grid1[c]);
}
System.out.println();
}
}
}
Does someone see what I am doing wrong?

You put too much responsibilities into one method. You combine the floodfill algorithm with your island numbering algorithm.
I've created this jdoodle.
First of all you better create a single fill method, that does nothing more than filling islands with the value of a counter (I've made it static so you don't need to pass it through the algorithm, although this is arbitrary):
public static void fill(Integer[][] array, int column, int row, int height, int length) {
if (row >= 0 && row < length && column >= 0 && column < height && array[column][row] == 1) {
array[column][row] = counter;
fill(array, column, row + 1, height, length);
fill(array, column, row - 1, height, length);
fill(array, column - 1, row, height, length);
fill(array, column + 1, row, height, length);
}
}
As you can see, it's a simple algorithm that uses recursion.
Secondly, you simply create a method that calls the fill algorithm on all the possible tiles. If you reach a point with a value of 1, you know that this island has not been claimed by another king yet :D. Thus you fill it and claim it to the king with the counter id. Normally one uses a special array of boolean to prevent the fill algorithm to go into an infinite loop. You solved this smartly by starting to assign number from index counter = 2, of course once all island are claimed, you need to decrement the value.
public static void findGroups(Integer[][] array, int column, int row, int height, int length) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < length; j++) {
if (array[i][j] == 1) {
fill(array, i,j, height, length);
counter++;
}
}
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < length; j++) {
if (array[i][j] > 1) {
array[i][j]--;
}
}
}
}
The rest of the algorithm remains the same (the algorithm now reads from stdin, but this is simply to make sure the jdoodle keeps working).
About your algorithm, it's quite hard to understand. For instance you use a fill and part of the calls use column and row, other parts use j. Next your counter is only updated for each row. This causes problems if two idlands start at the same row (as you can see with your output).

Related

Java 10x10 array with nested loop

I have an 10x10 array and I am trying to fill it with nested loop
int A[][] = new int [10][10];
So far I have created this -
C = 1;
for (i=0; i<=9; i++)
for (j=9-i; j>=7-i; j--)
if (j>=0) {
A[i][j] = C; C=C+1;
}
And here is the result so far.
But I am trying to create this with two for loops and cannot manage it.
Thank you for any help!
This should do the job:
iterate rows as usual from 0 to 10, set column index to 9 and decrease it
in the inner loop, set the range from i to the Math.max(i - beltWidth + 1, 0) inclusive (beltWidth is the maximal count of non-zero values in a column, in this case it's 3).
final int size = 10;
final int beltWidth = 3;
int A[][] = new int [size][size];
int c = 1;
for (int i = 0, j = size - 1; i < size; i++, j--) {
for (int k = i; k >= Math.max(i - beltWidth + 1, 0); k--) {
A[k][j] = c++;
}
}
for (int[] r : A) {
for (int x : r) {
System.out.printf("%2d ", x);
}
System.out.println();
}
Output
0 0 0 0 0 0 0 6 3 1
0 0 0 0 0 0 9 5 2 0
0 0 0 0 0 12 8 4 0 0
0 0 0 0 15 11 7 0 0 0
0 0 0 18 14 10 0 0 0 0
0 0 21 17 13 0 0 0 0 0
0 24 20 16 0 0 0 0 0 0
27 23 19 0 0 0 0 0 0 0
26 22 0 0 0 0 0 0 0 0
25 0 0 0 0 0 0 0 0 0
Here is my version. I borrowed the nice printf formatting from Alex's answer :)
I just wanted to mention 2 things:
I think it's a bit easier to read if i and j are called y and x
I seem to remember that if you need performance, you need to traverse the array along the x axis, as that is how CPU cache is fetched (at least in theory). That would make the algorithm a bit more complicated, but I guess in this case we are not really concerned with performance so having y in the inner loop is fine :)
int dimension = 10;
int[][] result = new int[dimension][dimension];
int C = 27;
int yOffset = 9;
for (int x = 0; x < dimension; x++) {
for (int y = Math.min(2, yOffset); y >= 0 && yOffset - y >= 0; y--) {
result[yOffset - y][x] = C--;
}
yOffset--;
}
for (int[] y : result) {
for (int x : y) {
System.out.printf("%2d ", x);
}
System.out.println();
}
Output
0 0 0 0 0 0 0 6 3 1
0 0 0 0 0 0 9 5 2 0
0 0 0 0 0 12 8 4 0 0
0 0 0 0 15 11 7 0 0 0
0 0 0 18 14 10 0 0 0 0
0 0 21 17 13 0 0 0 0 0
0 24 20 16 0 0 0 0 0 0
27 23 19 0 0 0 0 0 0 0
26 22 0 0 0 0 0 0 0 0
25 0 0 0 0 0 0 0 0 0

Get last made move from game boards

I have two 2D int arrays that represent game boards. (The initial board and the new board)
Content of the initial board:
013 | 6 0 0 0 4 4 4 4 4 0 0 0 6
012 | 0 0 0 0 0 0 4 0 0 0 0 0 0
011 | 0 0 0 0 0 0 0 0 0 0 0 0 0
010 | 0 0 0 0 0 0 2 0 0 0 0 0 0
009 | 4 0 0 0 0 0 2 0 0 0 0 0 4
008 | 4 0 0 0 0 0 2 0 0 0 0 0 4
007 | 4 4 0 2 2 2 5 2 2 2 0 4 4
006 | 4 0 0 0 0 0 2 0 0 0 0 0 4
005 | 4 0 0 0 0 0 2 0 0 0 0 0 4
004 | 0 0 0 0 0 0 2 0 0 0 0 0 0
003 | 0 0 0 0 0 0 0 0 0 0 0 0 0
002 | 0 0 0 0 0 0 4 0 0 0 0 0 0
001 | 6 0 0 0 4 4 4 4 4 0 0 0 6
A B C D E F G H I J K L M
Content of the new board (after applying a move):
013 | 6 0 0 0 4 4 4 4 4 0 0 0 6
012 | 0 0 0 0 0 0 4 0 0 0 0 0 0
011 | 0 0 0 0 0 0 0 0 0 0 0 0 0
010 | 0 0 0 0 0 0 2 0 0 0 0 0 0
009 | 4 0 0 0 0 0 2 0 0 0 0 0 4
008 | 4 0 0 0 0 0 2 0 0 0 0 0 4
007 | 4 4 0 2 2 2 5 2 2 2 0 4 4
006 | 4 0 0 0 0 0 2 0 0 0 0 0 4
005 | 4 0 0 0 0 0 2 0 0 0 0 0 4
004 | 0 0 0 0 0 0 2 0 0 0 0 0 0
003 | 0 0 0 0 0 0 0 0 0 0 0 0 0
002 | 0 0 0 0 4 0 4 0 0 0 0 0 0
001 | 6 0 0 0 0 4 4 4 4 0 0 0 6
A B C D E F G H I J K L M
I wanna compare the two game boards to get the last fetched move. How can I determine the last made move on this board?
As you can see the last made move is: "E1 - E2" -> The pawn "E1" was put in "E2"
Is there a fast way to compare the two to determine this last made move "E1 - E2"
What I have:
for (int y = 0; y < Board.DIMENSION; y++) {
for (int x = 0; x < Board.DIMENSION; x++) {
// Check where not equal
if (initialBoard.grid[x][y] != newBoard.grid[x][y]) {
// What to add??
}
}
}
Assuming that the user can only make a move over the empty places(0).
You can do something like this:
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
// Check where not equal
if (initialBoard.grid[x][y] != newBoard.grid[x][y] && newBoard.grid[x][y] == 0) {
// From move
String from = x +""+ (char)y+65;
}
if(initialBoard.grid[x][y] != newBoard.grid[x][y] && newBoard.grid[x][y] != 0) {
// To move
}
}
}
You will need to find two spots where the boards differ. You already seem to have the logic down to find a spot where the game board has changed. Now you need to decide what direction the move occurs in.
To me, it looks like the board going from 0 to 4 means a piece has moved there. So, if the new int is > the old int... we know this is the end location.
Since you've gotten this far, I think you can figure it out with the follow logic: (maybe there are cases in this game I am not aware of - so you will have to check for those cases)
String startPos, endPos;
for (int y = 0; y < Board.DIMENSION; y++) {
for (int x = 0; x < Board.DIMENSION; x++) {
// Check where not equal
if (initialBoard.grid[x][y] != newBoard.grid[x][y]) {
// if we go from a 0 to a 4, this is the starting position
if (initialBoard.grid[x][y] < newBoard.grid[x][y]) {
// translate the location into a position and store it as startPos
} else {
// translate the location into a position and store it as endPos
}
}
}
}
System.out.println(startPos + " -> " + endPos); // something like that

Creating matrices Java

I have trouble creating a matrice for a game map design.
void prepareMatrix(int width, int height)
{
room = new int[height][width];
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
if(i < height/4)
{
room[i][j] = 2;
}
else if(j == 0 || j == --width)
{
room[i][j] = 1;
}
else if(i == --height)
{
room[i][j] = 1;
}
else
{
room[i][j] = 0;
}
}
}
}
I want to create something like this: (1- Wall1, 2- wall2, 0-floor)
2 2 2 2 2 2
2 2 2 2 2 2
1 0 0 0 0 1
1 0 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
And I get this:
2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2
1 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
The matrice would be a blueprint for the map.
You are using --width and --height. It appears from the expected result that you want the 1's to go in the first and last columns and in the last row. As a commenter implied, --width does not just return the width minus one, it also reduces width by 1. You may want width - 1 and height - 1 instead.
Like M. Aroosi said, try to change the --width to width-1 and --height to height-1. You don't want to modify the value of a parameter. I think what is happening is that every time it goes through the loop, the values change for width and height.

how to restricts the number of character and lines reads from a file before insertinting into 2dimentional array in java

i have go through the previous answers but nothing like what i am looking for, specifically in java. here is my code, the block of my code can read a singe character integer only which is not exactly what i intend to do, i intends to reads more than one char integer, it doesn't work. and i want reads only 16 lines and 16 integers in a line from the file even if the file contains more than 16 lines and more than 16 integers per line. can some one share an idea with me please?
Here is sample input data:
13 20 0 0 0 0 0 0 0 0 0 0 11 2
0 0 0 0 0 0 0 0 0 4 5 0 0 11 2
0 0 0 0 0 0 0 0 0 333 4 0 0 0 0
0 0 0 0 0 0 0 0 0 9 10 41 3 5 8
0 0 0 0 0 0 0 0 0 0 11 2 333 4
13 20 0 0 0 0 0 0 0 0 0 0 11 2
0 0 0 0 0 0 0 0 0 4 5 0 0 11 2
0 0 0 0 0 0 0 0 0 333 4 0 0 0 0
0 0 0 0 0 0 0 0 0 9 10 41 3 5 8
0 0 0 0 0 0 0 0 0 0 11 2 333 4
13 20 0 0 0 0 0 0 0 0 0 0 11 2
0 0 0 0 0 0 0 0 0 4 5 0 0 11 2
0 0 0 0 0 0 0 0 0 333 4 0 0 0 0
0 0 0 0 0 0 0 0 0 9 10 41 3 5 8
0 0 0 0 0 0 0 0 0 0 11 2 333 4
13 20 0 0 0 0 0 0 0 0 0 0 11 2
0 0 0 0 0 0 0 0 0 4 5 0 0 11 2
0 0 0 0 0 0 0 0 0 333 4 0 0 0 0
0 0 0 0 0 0 0 0 0 9 10 41 3 5 8
0 0 0 0 0 0 0 0 0 0 11 2 333 4
i just want insert this into the 2dimentional array as you can see in my code, but my array is 16X16 but the file may be more than 16x16 in size, but i just want reads just 16x16 even if the file contains more than that, and ignore the empty line even if it exist.
BufferedReader bufferedReader = new BufferedReader(new FileReader("text.txt"));
String line = null;
int[][] board = new int[16][16];
int k = 0;
while((line = bufferedReader.readLine())!=null) {
String[] newmatrix = line.split(" ");
for(int i=0; i<9; i++) {
board[k][i] = Integer.parseInt(newmatrix[i]);
}
k++;
}
This appears to be "a learning exercise". So, hints / advice only1:
To stop reading after 16 lines, use a counter.
Skip an empty line by testing for an empty line.
Use a Scanner (hasNextInt() and nextInt() to process each line.
It is a good idea to avoid hard-wiring literal constants into your code ... like 9 which you seem to have pulled out of the air.
Use board.length - 1 or board[i].length - 1 for your array bounds when "looping". (See previous)
Also ... your input file seems to only have 14 integers per line, not 16 as the question states.
1 ... because you will learn more by coding this yourself.
The code below should work.
BufferedReader bufferedReader = new BufferedReader(new FileReader("text.txt"));
String line = null;
int[][] board = new int[16][16];
int k = 0;
while((line = bufferedReader.readLine())!=null) {
String[] newmatrix = line.split(" ");
for(int i = 0; i < 16; i++) {
board[k][i] = Integer.parseInt(newmatrix[i]);
}
k++;
if (k == 16)
break;
}
bufferedReader.close();

Java counting connected regions in a grid

I am trying to locate all four-connected regions in the grid. A four-connected region consists of a set of marked cells (value 1) such that each cell in the region can be reached by moving up, down, left or right from another marked cell in the region. The assignment states that we should use recursion.
An example input would be:
10 20
0 1 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0
0 1 1 1 0 1 1 0 0 1 0 0 1 1 1 0 0 0 1 1
0 0 1 0 0 0 1 1 0 1 0 0 0 1 0 0 0 1 1 1
1 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 1 1 0
1 1 0 1 0 0 0 1 1 1 0 0 0 1 1 0 1 1 0 0
1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 0 1 1 0 1 0 0 0
0 1 1 1 1 1 0 0 1 1 1 0 0 0 1 1 1 1 1 0
0 0 0 1 1 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0
1 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 0 1 0 0
And the output should be:
0 1 1 0 0 0 2 0 3 3 0 0 0 0 4 0 0 0 5 0
0 1 1 1 0 2 2 0 0 3 0 0 4 4 4 0 0 0 5 5
0 0 1 0 0 0 2 2 0 3 0 0 0 4 0 0 0 5 5 5
6 0 0 0 0 0 0 0 3 3 0 0 7 0 0 0 5 5 5 0
6 6 0 6 0 0 0 3 3 3 0 0 0 8 8 0 5 5 0 0
6 6 6 6 0 0 0 0 0 0 9 0 8 8 8 0 0 0 0 0
0 6 6 6 0 0 0 9 9 9 9 0 0 8 8 0 8 0 0 0
0 6 6 6 6 6 0 0 9 9 9 0 0 0 8 8 8 8 8 0
0 0 0 6 6 0 0 0 0 9 0 0 0 8 8 0 0 8 8 0
10 0 6 6 6 6 6 0 0 0 0 0 0 0 8 8 0 8 0 0
Right now when I run the code I have, I get this output:
0 2 2 0 0 0 2 0 2 2 0 0 0 0 2 0 0 0 2 0
0 2 2 2 0 2 2 0 0 2 0 0 2 2 2 0 0 0 2 2
0 0 2 0 0 0 2 2 0 2 0 0 0 2 0 0 0 2 2 2
2 0 0 0 0 0 0 0 2 2 0 0 2 0 0 0 2 2 2 0
2 2 0 2 0 0 0 2 2 2 0 0 0 2 2 0 2 2 0 0
2 2 2 2 0 0 0 0 0 0 2 0 2 2 2 0 0 0 0 0
0 2 2 2 0 0 0 2 2 2 2 0 0 2 2 0 2 0 0 0
0 2 2 2 2 2 0 0 2 2 2 0 0 0 2 2 2 2 2 0
0 0 0 2 2 0 0 0 0 2 0 0 0 2 2 0 0 2 2 0
2 0 2 2 2 2 2 0 0 0 0 0 0 0 2 2 0 2 0 0
My code looks like:
package project2;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;
public class project2 {
private static int height;
private static int length;
public static void main(String[] args) {
String inputFile;
Scanner input = new Scanner(System.in);
System.out.print("Enter input file name: ");
inputFile = input.nextLine();
try {
Integer grid[][] = loadGrid(inputFile);
System.out.println("Before flood fill");
printGrid(grid);
findGroups(grid, 0, 0, 2, height, length);
System.out.println("After flood fill");
printGrid(grid);
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
public static void findGroups(Integer[][] array, int column, int row,
int counter, int height, int length) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < length; j++) {
if (row < 0 || row >= length || column < 0 || column >= height) {
} else {
if (array[i][j] == 1) {
array[i][j] = counter;
findGroups(array, column, row + 1, counter, height, length);
findGroups(array, column, row - 1, counter, height, length);
findGroups(array, column - 1, row, counter, height, length);
findGroups(array, column + 1, row, counter, height, length);
counter++;
}
}
}
}
}
public static Integer[][] loadGrid(String fileName) throws IOException {
FileInputStream fin;
fin = new FileInputStream(fileName);
Scanner input = new Scanner(fin);
height = input.nextInt();
length = input.nextInt();
Integer grid[][] = new Integer[height][length];
for (int r = 0; r < height; r++) {
for (int c = 0; c < length; c++) {
grid[r][c] = input.nextInt();
}
}
fin.close();
return (grid);
}
public static void printGrid(Integer[][] grid) {
for (Integer[] grid1 : grid) {
for (int c = 0; c < grid[0].length; c++) {
System.out.printf("%3d", grid1[c]);
}
System.out.println();
}
}
}
I'm not sure what I am doing wrong, I believe I am moving the counter up after each time. Does anyone have a recommendation of what the issue might be?
Thanks in advance.

Categories

Resources