Finding adjacent matrix: Java.lang.ArrayIndexOutOfBoundsException - java

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.

Related

Java: How do I get these two methods into one?

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.

Neighbors in a 2D 4x4 Array

Alright... So I've been stuck with an exercise for school for a little while now and I really can't figure out how to solve it. I think I've come really compared to where I started and I hope you guys could help me out.
The final meaning of the exercise would be that the code will output all the neighbors possible of every single digit in the array. I've done the middle four ones, they work perfectly. The outer digits are a pain for me, I can't find a way to make sure to make the code 'notice' that there are no more digits, for example, above the digit in the upper left corner.
I feel like I know how to do it: with an if statement that doesn't let something happen if the value of the index of the array is higher than 3 or lower than 0. Because it's a 4x4 2D Array that means there are 0, 1, 2, 3 indexes for the X Axis and Y Axis.
I hope someone here is willing to help me out. It will be greatly appreciated! Here's my code for so far!
Thanks in advance
public class P620 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
int[][] counts =
{
{ 1, 0, 3, 4},
{ 3, 5, 6, 4 },
{ 9, 7, 1, 4},
{ 1, 1, 1, 1}
};
for(int i = 0; i <= 3; i++) {
for(int j = 0; j <= 3; j++) {
System.out.println("Neighbours van de array: " + i + j + " met waarde: " + counts[i][j]);
if ((i < 4 && i > -1) && (j < 4 && j > -1)) {
System.out.println(counts[i - 1][j]);
}
else if ((i < 4 && i > -1) && (j < 4 && j > -1)) {
System.out.println(counts[i - 1][j - 1]);
}
else if ((i < 4 && i > -1) && (j < 4 && j > -1)) {
System.out.println(counts[i - 1][j + 1]);
}
else if ((i < 4 && i > -1) && (j < 4 && j > -1)) {
System.out.println(counts[i][j - 1]);
}
else if ((i < 4 && i > -1) && (j < 4 && j > -1)) {
System.out.println(counts[i + 1][j - 1]);
}
else if ((i < 4 && i > -1) && (j < 4 && j > -1)) {
System.out.println(counts[i + 1][j]);
}
else if ((i < 4 && i > -1) && (j < 4 && j > -1)) {
System.out.println(counts[i + 1][j + 1]);
}
else if ((i < 4 && i > -1) && (j < 4 && j > -1)) {
System.out.println(counts[i][j + 1]);
}
else {
}
}
}
}
}
Here's a little hint:
for (int i=0; i < 4; ++i) {
for (int j=0; j<4; ++j) {
System.out.println("Neighbours van de array: " + i + j + " met waarde: " + counts[i][j]);
// print upper-left (northwest) neighbor, if there is one
if (i >= 1 && j >= 1)
System.out.println(counts[i-1][j-1]);
// print upper (north) neighbor, if there is one
if (i >= 1)
System.out.println(counts[i-1][j]);
.
.
.
// print lower (south) neighbor, if there is one
if (i < 3)
System.out.println(counts[i+1][j]);
// print lower-right (southeast) neighbor, if there is one
if (i < 3 && j < 3)
System.out.println(counts[i+1][j+1]);
}
}

GameOfLife IndexOutOfBounds Error-handling

So, I'm working on an assignment to make a class to receive text files set up for Conway's Game Of Life. I have written everything, but its hard to test since I suck as error-handling. I have read the java tutorial pages on try, catch, throw, etc. I don't understand it, and it would save me a lot of time if I could get something working for IndexOutOfBounds errors.
public void computeNextGeneration(int generation) {
int aliveCount;
tempBoard = new char[Column][Row];
int generationCount = 1;
System.out.print("Generation" + generationCount);
print();
do {
for (int i = 0; i < Row; i++) {
for (int j = 0; j < Column; j++) {
aliveCount = 0;
try {
if (board[Row - 1][Column - 1] == 'X') {
aliveCount++;
}
if (board[Row - 1][Column] == 'X') {
aliveCount++;
}
if (board[Row - 1][Column + 1] == 'X') {
aliveCount++;
}
if (board[Row][Column - 1] == 'X') {
aliveCount++;
}
if (board[Row][Column + 1] == 'X') {
aliveCount++;
}
if (board[Row + 1][Column - 1] == 'X') {
aliveCount++;
}
if (board[Row + 1][Column + 1] == 'X') {
aliveCount++;
}
if (board[Row + 1][Column + 1] == 'X') {
aliveCount++;
}
if (board[i][j] == 'X') {
if (aliveCount < 2) {
setCell(j, i, 0);
}
if (aliveCount > 2) {
setCell(j, i, 0);
} else {
setCell(j, i, 1);
}
}
if (board[i][j] == '0') {
if (aliveCount == 3) {
setCell(j, i, 1);
}
}
} catch (IndexOutOfBoundsException e) {
}
throw new IndexOutOfBoundsException();
}
board = tempBoard;
generationCount++;
System.out.print("Generation" + generationCount);
print();
System.out.println();
generation--;
}
} while (generation > 1);
}
The very first case, being on the edge of the 2d array will give the first error. I thought if I put the code that checks neighboring array indices... to be honest I was just throwing code together like shots in the dark. If I could get an example similar to my problem, anything that exemplifies handling an IndexOutOfBounds error, I would really appreciate it.
Take the 8 if statements out of the try-catch scenario and instead focus on checking whether or not the indices for board are correct. In other words, before accessing board[Row - 1][Column - 1], check that 0 <= Row-1 <= NumOfRows and 0 <= Column-1 <= NumOfColumns.
EDIT
More explicit view.
for (int i = 0; i < NumOfRows; i++) {
for (int j = 0; j < NumOfColumns; j++) {
aliveCount = 0;
if (i-1 >= 0 && i-1 <= NumOfRows) {//This case checks the cell to the left
aliveCount++;
}
//Other cases
You are trying to accessing board[Row + 1][Column + 1] which throws ArrayIndexOutOfBound exception.
Similary board[Row][Column + 1] and board[Row + 1][Column] throws an exception. Because elements at position Row + 1 and Column + 1 are not initialized.
A few thoughts about this one...
First, you are accessing the wrong array elements with
for (int i = 0; i < Row; i++) {
for (int j = 0; j < Column; j++) {
...
// Wrong Indices, possible Exception
// vvvvvvv vvvvvvvvvvv
if (board[Row - 1][Column - 1] == 'X') {
aliveCount++;
}
...
}
}
Like this, you are always checking the same element (last row, last column). But you want to check the element next to the current element. So something like
// [i][j] -> Current Element
// [i-1][j-1] -> Element on the top left
if (board[i - 1][j - 1] == 'X') {
aliveCount++;
}
should be used. However, this can and will throw an IndexOutOfBoundsException. So you have to check if the values of i and j are in the correct Range. So add checks to ensure valid values:
if (0 <= (i - 1) && (i - 1) <= Row && 0 <= (j - 1) && (j - 1) <= Column) {
if (board[i - 1][j - 1] == 'X') {
aliveCount++;
}
} else {
// TODO: What to do with the Edges? Assume 0/1? Wrap around?
}
However, this code is repeated 8 times in your loop, which will be hard to read, hard to debug and error prone. So it is better to move this into a seperate function. Something like
public boolean cellIsAlive(char[][] board, int row, int col)
{
if (0 <= (row - 1) && (row - 1) <= Row && 0 <= (col- 1) && (col- 1) <= Column) {
if (board[row - 1][col- 1] == 'X') {
return true;
}
} else {
// TODO: What to do with the Edges? Assume 0/1? Wrap around?
return false;
}
return false;
}
...
if (cellIsAlive(board, i, j)) {
aliveCount++;
}
Another note: Actually you don't need any of the checks if the cells exist. You know the size of the grid and you now the different cases: Middle of the board, first row, last row, first column, second column, corner elements. So instead of looping through the whole board, you can treat these cases seperately. But that might be overkill for your example.

Minesweeper implementation output seems ok but fails UVa Judge tests

The Input
The input will consist of an arbitrary number of fields. The first line of each field contains two integers n and m (0 < n,m <= 100) which stands for the number of lines and columns of the field respectively. The next n lines contains exactly m characters and represent the field. Each safe square is represented by an "." character (without the quotes) and each mine square is represented by an "*" character (also without the quotes). The first field line where n = m = 0 represents the end of input and should not be processed.
The Output
For each field, you must print the following message in a line alone:
Field #x:
Where x stands for the number of the field (starting from 1). The next n lines should contain the field with the "." characters replaced by the number of adjacent mines to that square. There must be an empty line between field outputs.
Sample Input
4 4
*...
....
.*..
....
3 5
**...
.....
.*...
0 0
Sample Output
Field #1:
*100
2210
1*10
1110
Field #2:
**100
33200
1*100
I get the correct output for the given inputs.
import java.util.*;
public class Main{
public static void main(String[] args) {
//field size
int n, m;
//string to hold a row of a minesweeper board
String line;
//array to hold all the minesweeper boards entered
ArrayList<char[][]> allBoards = new ArrayList<char[][]>();
Scanner scan = new Scanner(System.in);
//get the field size
n = scan.nextInt();
m = scan.nextInt();
//keep going until n=0 and m=0
while ((n+m)!=0) {
//create the minesweeper board
//the field sizes are 2 spaces bigger to prevent error checking
//at the edges of the minesweeper board
char[][] board = new char[n + 2][m + 2];
//fill the appropriate spaces with the mines '*' and blank spaces '.'
for (int row = 1; row < board.length - 1; row++) {
line = scan.next();
for (int col = 1; col < board[0].length - 1; col++) {
board[row][col] = line.charAt(col - 1);
}
}
//add the current minesweeper board to the array
allBoards.add(board);
//get new field size
n = scan.nextInt();
m = scan.nextInt();
}
printResults(allBoards);
}
//function to find out how many mines are around a certain position
//check all positions surrounding the current one.
public static int getMines(char[][] board, int row, int col) {
int nMines = 0;
if (board[row - 1][col - 1] == '*') {
nMines++;
}
if (board[row - 1][col] == '*') {
nMines++;
}
if (board[row - 1][col + 1] == '*') {
nMines++;
}
if (board[row][col - 1] == '*') {
nMines++;
}
if (board[row][col + 1] == '*') {
nMines++;
}
if (board[row + 1][col - 1] == '*') {
nMines++;
}
if (board[row + 1][col] == '*') {
nMines++;
}
if (board[row + 1][col + 1] == '*') {
nMines++;
}
return nMines;
}
//print the results
private static void printResults(ArrayList<char[][]> allBoards) {
for (int i = 1; i <= allBoards.size(); i++) {
System.out.println("Field #" + i + ":");
for (int row = 1; row < allBoards.get(i - 1).length - 1; row++) {
for (int col = 1; col < allBoards.get(i - 1)[0].length - 1; col++) {
if (allBoards.get(i - 1)[row][col] != '*') {
System.out.print(getMines(allBoards.get(i - 1), row, col));
} else {
System.out.print("*");
}
}
System.out.println();
}
System.out.println();
}
}
}

Place a word in a 2d array

is there a way to place a word in a 2d array in a specific position? For example,i want to give the word, choose vertical or horizontal and the position ((3,3) or (3,4) or (5,6) etc) and the word will be placed in that position.This is my code for the array...
char [][] Board = new char [16][16];
for (int i = 1; i<Board.length; i++) {
if (i != 1) {
System.out.println("\t");
System.out.print(i-1);
}
for (int j = 1; j <Board.length; j++) {
if ((j == 8 && i == 8) ||(j ==9 && i == 9) ||(j == 10 && i == 10) ||(j == 2 && i == 2) )
{
Board[i][j] = '*';
System.out.print(Board[i][j]);
}
else {
if (i == 1) {
System.out.print("\t");
System.out.print(j-1);
}
else {
Board[i][j] = '_';
System.out.print("\t");
System.out.print(""+Board[i][j]);
}
}
(the * means that the word cant be placed there)
Is there a way to place a word in a 2d array in a specific position?
Yes you can implement that. The pseudo-code is something like this:
public void placeWordHorizontally(char[][] board, String word, int x, int y) {
for (int i = 0; i < word.length(); i++) {
if (y + i >= board[x].length) {
// fail ... edge of board
} else if (board[x][y + i]) == '*') {
// fail ... blocked.
} else {
board[x][y + i] = word.charAt(i);
}
}
}
and to do the vertical case you add i etcetera to the x position.
I won't give you the exact code because you'll learn more if you fill in the details yourself.

Categories

Resources