Get all neighbors of cell in array without out of bounds exception - java

I'm trying to make an ArrayList out of all the cells that neighbor a given cell in an array. Currently, my code works for any cell that does not have neighbors in the last row or right-most column. If it does have neighbors in these, I get the error message: "Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3"
Here's my code:
public ArrayList<Cell> getNeighbors(int row, int col) {
ArrayList<Cell> neighbors = new ArrayList<Cell>();
for (int r = row - 1; r <= row + 1; r++) {
for (int c = col - 1; c <= col + 1; c++) {
if (!(r == row && c == col)) {
if ((c >= 0 && r >= 0) && (c <= (col + 1) && r <= (row + 1))) {
neighbors.add(landscape[r][c]);
}
}
}
}
return neighbors;
}
Getting the neighbors of cell (1, 1) in a 2x2 grid like this one
0 0 0
0 0 0
0 1 1
returns: [0, 0, 0, 0, 0, 0, 1, 1] (Works correctly)
but if I look for the neighbors of any cell in row/col 2, I get the error and I don't know what I'm doing wrong.
Please help!!

Your bounds check is wrong.
c >= 0 && r >= 0 && r < landscape.length && c < landscape[r].length

Related

how to replace a 2D array for a new 2D array in a console in Java?

My code has some logic issues with the problem mentioned above.
What I'm trying to do is to print a 2D array in the console, and then, after asking for the user's input, the array will change and will replace the old one for this new one in the console.
Here is an example of what I'm trying to do.
Don't pay attention to the numbers on the array, what I am asking only has to do with the elements that are printed in the console.
The console will look like this
What column do you want to shoot (A, B, C, D, E, F)
The number that is going to be shoot is ---1---
After the user gives the column, the console will look like this.
What column do you want to shoot (A, B, C, D, E, F)
The number that is going to be shoot is ---1---
A
3 3 2 1 1 3
2 2 3 1 1 3
2 3 3 1 3 3
2 2 3 3 1 3
1 3 1 2 2 3
2 2 1 1 3 2
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
What column do you want to shoot (A, B, C, D, E, F)
The number that is going to be shoot is ---2---
The code that I attached at the end does all of this, but the problem starts after the user gives the second input. After the user gives his second input (his second column) the console will look like this:
What column do you want to shoot (A, B, C, D, E, F)
The number that is going to be shoot is ---1---
A
3 3 2 1 1 3
2 2 3 1 1 3
2 3 3 1 3 3
2 2 3 3 1 3
1 3 1 2 2 3
2 2 1 1 3 2
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
What column do you want to shoot (A, B, C, D, E, F)
The number that is going to be shoot is ---2---
B
2 2 2 3 3 1
3 3 2 1 1 3
2 2 3 1 1 3
2 3 3 1 3 3
2 2 3 3 1 3
1 3 1 2 2 3
0 0 1 1 3 2
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
What column do you want to shoot (A, B, C, D, E, F)
The number that is going to be shoot is ---3---
What it's doing is that it keeps printing and printing new boards instead of "updating" the same board.
What I am trying to achieve is the following: (What I am showing is what I want the console to look like)
(User gives the first input)
Console:
The number that is going to be shoot is ---2---
A
3 3 2 1 1 3
2 2 3 1 1 3
2 3 3 1 3 3
2 2 3 3 1 3
1 3 1 2 2 3
2 2 1 1 3 2
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
(User gives second input)
Console:
What column do you want to shoot (A, B, C, D, E, F)
The number that is going to be shoot is ---3---
A
2 2 2 3 3 1
3 3 2 1 1 3
2 2 3 1 1 3
2 3 3 1 3 3
2 2 3 3 1 3
1 3 1 2 2 3
0 0 1 1 3 2
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
(The only 2 changes here are the number that is going to be shoot and the numbers in the array)
In a few words all I want to do is to "update" the board with the result instead of printing and printing new boards over and over again.
The code below is the code I have so far. I included a pseudo code so that you can see what each method does (The whole game structure is on the game() method). I would prefer to not change the code for any of the methods rather than the gameOver method since it is the one that is in "charge" of clearing the consoles and all that stuff. (If you find an answer and involves changing another method that's ok)
Again, the only thing that i'm confused about is on how to replace the existing board instead of printing new boards, not with the content of the arrays.
Here's the code
import java.util.Scanner;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Collections;
public class Project {
public static final int[][] NEIGHBOURS = // adjacent cells
{{0, 1}, // horizontal -
{1, 0}, // vertical |
{1, 1}, // diagonal \
{1, -1}}; // diagonal /
private List<Island> islands = new ArrayList<>(); // collection of Islands
private int[][] grid; // matrix
public Project(int[][] grid) {
this.grid = grid;
}
public static int[][]board = { {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} };
public static int[][]numberBoard = createBoard(6, /*Number of colums*/ 5, /*Number of rows*/ 3 /*Bubble types in the board (1, 2 or 3)*/);
//creates random board
public static void main( String[] args) {
game();
}
public static void game() {
String input; //the Input
int randomNumber;
int[] location;
board = combine(board, numberBoard); //Empty Board to Randomized Board
while(gameOver(board).equals("GAME CONTINUES")) {
gameOver(board); //Scans the array to see if the game is still going or not
//The code below up to "shiftRow" shouldn't really matter with the question because all it's doing is to make changes to the array
//but does not print anything to the console so I seperated them.
randomNumber = createRandomNumber(3); //creates a randomNumber
input = shoot(randomNumber); //Input
board = putNumber(board, input, randomNumber); //Places Input
location = numberLocation(board, input, randomNumber); //Gets location of the placed number
board = destroyAdjacentNumbers(board, location[0], location[1], randomNumber); //Deletes any number that is both, a neighbor and
//has the same value as the number placed
Project destroyIslands = new Project(board); //destroys the islands (Chunks of numbers that are completely surrounded by zeros)
destroyIslands.deleteIslandBoard2();
shiftRow(board); //Shifts the row down
destroyIslands.printGrid(); //prints the grid
}
if(gameOver(board).equals("CONGRATULATIONS, YOU WON THE GAME!")) {
clearConsole();
System.out.println("CONGRATULATIONS, YOU WON THE GAME!");
} else if(gameOver(board).equals("YOU LOST THE GAME!")) {
clearConsole();
System.out.println("YOU LOST THE GAME!");
}
}
public static int[][] createBoard(int cols, int rows, int numBubbleTypes) {
int[][] board = new int[rows][cols];
for( int row = 0; row < rows; row++ ) {
for( int col = 0; col < cols; col++ ) {
board[row][col] = (int)(Math.random() * (double)numBubbleTypes) + 1;
}
}
return board;
}
public static int createRandomNumber(int type) {
double randomNumber = Math.random();
randomNumber = randomNumber * type;
int roundedNumber = (int) Math.floor(randomNumber);
int result = roundedNumber + 1;
return result;
}
public static void printGrid(int[][] grid) {
for( int row = 0; row < grid.length; row++ ) {
for( int col = 0; col < grid[row].length; col++ ) {
System.out.print( grid[row][col] + " " );
}
System.out.println("");
}
}
public static int[][] shiftRow( int[][] grid ) {
/*
* Pseudocode:
* Shift down first row to second row, then third row goes up two rows
*
* Shift each row down one (except the last row), then shift bottom row to the top
*
* Store the row after the current row in a temporary box, then overwrite the next row
* with the first, then repeat (excluding the last row).
*/
int[] tempList = new int[ grid[0].length ]; //0, 0, 0
for( int col = 0; col < grid[0].length; col++ ) {
tempList[col] = grid[0][col];
}
for( int row = 0; row < grid.length - 1; row++ ) {
int[] currentList = new int[ grid[row].length ];
for( int col = 0; col < grid[row].length; col++ ) {
currentList[col] = tempList[col];
tempList[col] = grid[row+1][col];
grid[row+1][col] = currentList[col];
}
}
int[][]newRow = createBoard(6, 1, 3);
for( int col = 0; col < grid[0].length; col++ ) {
grid[0][col] = newRow[0][col];
}
return grid;
}
public static void fillBoard(int[]array) {
}
public static String shoot(int number) {
System.out.println("What column do you want to shoot (A, B, C, D, E, F)");
System.out.println("The number that is going to be shoot is ---" + number + "--- ");
Scanner scanShoot = new Scanner(System.in);
String input = scanShoot.nextLine();
return input;
}
private static void clearConsole() {
System.out.print('\u000C'); //Clear terminal
}
public static int[][] combine(int[][]board, int[][] numberBoard) {
for(int i = 0; i < numberBoard.length; i++) {
for(int j = 0; j < numberBoard[i].length; j++) {
board[i][j] = numberBoard[i][j];
}
}
return board;
}
public static int[][] putNumber(int[][] board, String columnInput, int randomNumber) {
if(columnInput.equals("A") ) {
for(int row = 0; row < board.length; row++) {
if(board[row][0] == 0) {
board[row][0] = randomNumber;
break;
}
}
}
if(columnInput.equals("B") ) {
for(int row = 0; row < board.length; row++) {
if(board[row][1] == 0) {
board[row][1] = randomNumber;
break;
}
}
}
if(columnInput.equals("C") ) {
for(int row = 0; row < board.length; row++) {
if(board[row][2] == 0) {
board[row][2] = randomNumber;
break;
}
}
}
if(columnInput.equals("D") ) {
for(int row = 0; row < board.length; row++) {
if(board[row][3] == 0) {
board[row][3] = randomNumber;
break;
}
}
}
if(columnInput.equals("E") ) {
for(int row = 0; row < board.length; row++) {
if(board[row][4] == 0) {
board[row][4] = randomNumber;
break;
}
}
}
if(columnInput.equals("F") ) {
for(int row = 0; row < board.length; row++) {
if(board[row][5] == 0) {
board[row][5] = randomNumber;
break;
}
}
}
return board;
}
public static int [] numberLocation(int [][] board, String column, int randomNumber) {
int columnIndex = column.charAt (0) - 'A';
int saveRow = -1;
for (int row = 0; row < board.length; row++) {
if (columnIndex >= 0 && columnIndex < board[row].length && board [row][columnIndex] == 0) {
board [row][columnIndex] = randomNumber;
saveRow = row;
break;
}
}
return new int [] { saveRow, columnIndex };
}
public static void destroyNumbers(int num, int[][] grid) {
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == num) {
grid[i][j] = 0;
}
}
}
}
public static int[][] destroyAdjacentNumbers(int[][] array, int row, int col, int num) {
if (row < 0 || row >= array.length || col < 0 || col >= array[row].length) {
return array;
}
if (array[row][col] == num) {
array[row][col] = 0;
}
if (row > 0 && array[row - 1][col] == num) {
array[row - 1][col] = 0;
destroyAdjacentNumbers(array, row - 1, col, num);
}
if (row < array.length - 1 && array[row + 1][col] == num) {
array[row + 1][col] = 0;
destroyAdjacentNumbers(array, row + 1, col, num);
}
if (col > 0 && array[row][col - 1] == num) {
array[row][col - 1] = 0;
destroyAdjacentNumbers(array, row, col - 1, num);
}
if (col < array[row].length - 1 && array[row][col + 1] == num) {
array[row][col + 1] = 0;
destroyAdjacentNumbers(array, row, col + 1, num);
}
return array;
}
public static void numberShot(int number) {
System.out.println("The number that is going to be shot is " + " --- " + number + " --- " );
}
public static String gameOver(int[][] array) {
boolean hasEmpty = false;
boolean hasNonEmpty = false;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (array[i][j] == 0) {
hasEmpty = true;
} else {
hasNonEmpty = true;
}
}
}
if (hasEmpty && hasNonEmpty) {
return "GAME CONTINUES";
} else if (hasEmpty) {
clearConsole();
return "CONGRATULATIONS, YOU WON THE GAME!";
} else {
clearConsole();
return "YOU LOST THE GAME!";
}
}
public static int[][] deleteIslandBoard(int[][] array) {
// Create a boolean array to track which cells have been visited
boolean[][] visited = new boolean[array.length][array[0].length];
// Iterate
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[0].length; j++) {
// If the cell is not visited and is part of an island
if (!visited[i][j] && array[i][j] != 0) {
// Delete the island by setting all cells to 0
deleteIsland(array, i, j, visited);
}
}
}
// Return the modified array
return array;
}
public static void deleteIsland(int[][] array, int i, int j, boolean[][] visited) {
// Check if the current cell is out of board or if it has already been visited
if (i < 0 || i >= array.length || j < 0 || j >= array[0].length || visited[i][j]) {
return;
}
// Mark the current cell as visited
visited[i][j] = true; // If the current cell is part of the island, set it to 0
if (array[i][j] != 0) {
array[i][j] = 0;
// Recursively delete the neighboring cells that are part of the island
deleteIsland(array, i - 1, j, visited);
deleteIsland(array, i + 1, j, visited);
deleteIsland(array, i, j - 1, visited);
deleteIsland(array, i, j + 1, visited);
}
}
public class Island implements Comparable<Island> {
private List<int[]> cells = new ArrayList<>();
public void addCell(int[] cell) {
cells.add(cell);
}
public void destroy() {
cells.forEach(cell -> grid[cell[0]][cell[1]] = 0);
}
#Override
public int compareTo(Island other) {
return Integer.compare(cells.size(), other.cells.size());
}
}
public void deleteIslandBoard2() {
exploreIslands();
deleteSmallerIslands();
}
public void exploreIslands() {
boolean[][] visited = new boolean[grid.length][grid[0].length];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (!visited[i][j] && grid[i][j] != 0) { // if a New Island was found
exploreIsland(new int[]{i, j}, visited); // explore the Island, i.e. index all its cell and mark them as visited
}
}
}
}
/**
* Depth first search implementation
*/
public void exploreIsland(int[] cell, boolean[][] visited) {
Island island = new Island();
islands.add(island); // updating the list of Islands
Deque<int[]> stack = new ArrayDeque<>();
stack.push(cell);
while (!stack.isEmpty()) {
int[] next = stack.poll();
island.addCell(next);
for (int[] shift : NEIGHBOURS) {
int row = next[0] + shift[0];
int col = next[1] + shift[1];
if (isValid(row, col) && !visited[row][col]) { // if cell exist, non-zero and not visited yet
stack.push(new int[]{row, col});
visited[row][col] = true;
}
}
}
}
public boolean isValid(int row, int col) {
return row >= 0 && row < grid.length
&& col >= 0 && col < grid[0].length
&& grid[row][col] != 0;
}
public void deleteSmallerIslands() {
if (islands.isEmpty()) return; // otherwise Collections.max() would throw NoSuchElementException
Island largest = Collections.max(islands);
for (Island next : islands) {
if (next != largest) next.destroy();
}
}
public void printGrid() {
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
System.out.print(grid[i][j] + " ");
}
System.out.println();
}
}
}
Most of this code shouldn't matter, just the methods that print stuff!!!!!!!!!!!!!!!

Java 2D Array manipulation

I have to modify the below method:
private final static int NUM = 6;
public void fun(int[][] grid) {
for(int row = 0; row < NUM; row++) {
for(int col = 0; col < NUM; col++) {
if((grid[row][col] % 2) == 0) {
grid[row][col] = 0;
}
}
}
}
This method checks if it's a even number and if so it replaces its value with 0. Simple.
I now need to modify it so that it directs each cell to simultaneously replace its value with its number of diagonal neighbors that hold a value of 0.
I've thought about this for about an hour and tried many different solutions, most of which resulted in an out of bounds exception. I'm stumped and don't know how to accomplish this.
If the code is right, using the integers for the grid array below, it will reproduce the numbers shown in the bottom of the picture.
What is the problem, you just need to put if statements, like there can be maximum 4 possible neighbors so check that how many are equal to 0. But this is not enough you just need to add one more condition in each of the if statements. The condition would be that the neighbor you are trying to check is possible or not.
That is: Total 4 neighbors. If the coordinates of your main cell are x, y then:
1st Diagonal neighbor: x-1, y-1
2nd Diagonal neighbor: x-1, y+1
3rd Diagonal neighbor: x+1, y+1
4th Diagonal neighbor: x+1, y-1
These are all the 4 diagonal neighbors' coordinates but the last thing you need to check is whether they go out of bonds or not. For example for checking the 1st Diagonal neighbor I would do:
if((x-1)>0 && (y-1)>0){
//and then check here if that block is = `0`
}
and for other having say x+1 or y+1 you will need to check whether or not they are less than the NUM. Like if I want to check the 3rd Diagonal Neighbor:
if((x+1)<NUM && (y+1)<NUM){
//and then check here if that block is = `0`
}
Update: What do you mean by check here if that block is = 0?
If you want to check that is the diagonal neighboring blocks are equal to 0 or not then you will need to do it in a loop. Here is how:
public void fun(int[][] grid) {
for(int row = 0; row < NUM; row++) {
for(int col = 0; col < NUM; col++) {
if((grid[row][col] % 2) == 0) {
grid[row][col] = 0;
}
}
}
for(row = 0; row< NUM; row++){
for(int col = 0; col < NUM; col++) {
int count = 0;
// To check for the 1st Diagonal Neighbor
if((row-1)>0 && (col-1)>0){
if(grid[row-1][col-1]==0){
count++;
}
}
//Similarly for 2nd, 3rd and 4th Diagonal Neighbors
//and then
grid[row][col]=count;
}
}
}
Update 2:
For say the 3rd diagonal neighbor the code block would be like this:
if((row+1)<NUM && (col+1)<NUM){
if(grid[row+1][col+1]==0){
count++;
}
}
Answer
final private static int NUM = 6;
public void fun(int[][] grid) {
for(int row = 0; row < NUM; row++) {
for(int col = 0; col < NUM; col++) {
int counter = 0;
if((row - 1) > 0 && (col - 1) > 0) {
if(grid[row - 1][col - 1] == 0) {
counter++;
}
}
if((row - 1) > 0 && (col + 1) < NUM) {
if(grid[row - 1][col + 1] == 0) {
counter++;
}
}
if((row + 1) < NUM && (col - 1) > 0) {
if(grid[row + 1][col - 1] == 0) {
counter++;
}
}
if((row + 1) < NUM && (col + 1) < NUM) {
if(grid[row + 1][col + 1] == 0) {
counter++;
}
}
grid[row][col] = counter;
}
}
}

Is there any way of avoiding this block of code?

I am remaking minesweeper for practice, and wrote this bit of code to avoid IndexOutOfBounds errors. Is there a way of avoiding this so I don't have to explicitly write out an if statement every possible error? I thought of making each array 2 indexes larger, and just ignoring the first and last index. Am I missing something obvious?
if (row > 0 && col > 0)
ray[row - 1][col - 1] += 1;
if (row > 0)
ray[row - 1][col] += 1;
if (row > 0 && col < height - 1)
ray[row - 1][col + 1] += 1;
if (col > 0)
ray[row][col - 1] += 1;
if (col < height - 1)
ray[row][col + 1] += 1;
if (row < width - 1 && col > 0)
ray[row + 1][col - 1] += 1;
if (row < width - 1)
ray[row + 1][col] += 1;
if (row < width - 1 && col < height - 1)
ray[row + 1][col + 1] += 1;
You can use a loop instead and define the bounds once. Something like:
int startRow = max(row - 1, 0);
int endRow = min(row + 1, width - 1);
int startCol = max(col - 1, 0);
int endCol = min(col + 1, height - 1);
for (int r = startRow; r <= endRow; r++)
for (int c = startCol; c <= endCol; c++)
if (r != row || c != col) //it looks like you want to skip this cell
ray[r][c] += 1;
Alternatively, if the operation is reversible (as in this code, you are adding 1), you can simply reverse the operation for the middle cell after the loop. This would be more efficient since it eliminates (at most) 12 comparisons, provided the operation itself were simple:
int startRow = max(row - 1, 0);
int endRow = min(row + 1, width - 1);
int startCol = max(col - 1, 0);
int endCol = min(col + 1, height - 1);
for (int r = startRow; r <= endRow; r++)
for (int c = startCol; c <= endCol; c++)
ray[r][c] += 1;
//reverse the operation for the middle cell
ray[row][col] -= 1;
You can simplify your code a bit by using nested if statements. (For instance, you wouldn't need to check that row > 0 more than once.)
However, I'd go with making the array 2 larger n each dimension, let row vary from 1 through height and col vary from 1 through width, and ignore what happens at the edges.
In your code, you seem to be pairing row with width and col with height, which seems backwards to me.
Yes it can be done with for loop
for(int r=row-1; r<=row+1; r++)
for(int c=col-1; c<=col+1; c++)
if( r>=0 && r<ROWS && c>=0 && c<COLS && !(r==row && c==col) )
ray[r][c]++;

Find elements surrounding an element in an array

I have a multidimensional array, I want to get the elements surrounding a particular element in that array.
For example if I have the following:
[[1,2,3,4,5,6]
[8,9,7,5,2,6]
[1,6,8,7,5,8]
[2,7,9,5,4,3]
[9,6,7,5,2,1]
[4,7,5,2,1,3]]
How do I find all the 8 elements around any of the above elements? And how do I take care of elements at the edges?
One way I figured out is, to write a 9 line code for this , which is obvious, but is there a better solution?
You can use 'direction array' in form
[[-1,-1], [-1,0],[1,0]..and so on]
And method which takes point coordinate and iterates through direction array -> add direction numbers to coordinates, check indexes are not out of bounds and collect results.
Something like this:
private static int[][] directions = new int[][]{{-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0, -1}};
static List<Integer> getSurroundings(int[][] matrix, int x, int y){
List<Integer> res = new ArrayList<Integer>();
for (int[] direction : directions) {
int cx = x + direction[0];
int cy = y + direction[1];
if(cy >=0 && cy < matrix.length)
if(cx >= 0 && cx < matrix[cy].length)
res.add(matrix[cy][cx]);
}
return res;
}
For (i, j) ->
(i - 1, j - 1)
(i - 1, j)
(i - 1, j + 1)
(i, j - 1)
(i, j + 1)
(i + 1, j - 1)
(i + 1, j)
(i + 1, j + 1)
Now, at the edges, you can check for num % row == 0, then its at row edge...
and , num % col == 0 then its column edge..
Here's is how you can proceed: -
Given an index (i, j).. You can find elements in a rows adjacent to j for i - 1, then i, and then i + 1. (NOTE : - for index i you just have to access j - 1, and j + 1)
Subsequently you also can check for the row edge and column edge..
Here, you can look at the code below, how it can happen: -
// Array size
int row = 6;
int col = 6;
// Indices of concern
int i = 4;
int j = 5;
// To the left of current Column
int index = i - 1;
for (int k = -1; k < 2; k++) {
if (index % row > 0 && ((j + k) % col) > 0) {
System.out.println(arr[index][j + k]);
}
}
// In the current Column
index = i;
// Increment is 2 as we don't want (i, j)
for (int k = -1; k < 2; k = k + 2) {
if (index % row > 0 && ((j + k) % col) > 0) {
System.out.println(arr[index][j + k]);
}
}
// To the right of current Column
index = i + 1;
for (int k = -1; k < 2; k++) {
if (index % row > 0 && ((j + k) % col) > 0) {
System.out.println(arr[index][j + k]);
}
}
UPDATE : - The above code can further be simplified.. But I leave that task to you..
HINT: - You can reduce one for loop from there..
for (i = 0; i < array.length; i++) {
for (j = 0; j < array[i].length; j++) {
for (x = Math.max(0, i - 1); x <= Math.min(i + 1, array.length); x++) {
for (y = Math.max(0, j - 1); y <= Math.min(j + 1,
array[i].length); y++) {
if (x >= 0 && y >= 0 && x < array.length
&& y < array[i].length) {
if(x!=i || y!=j){
System.out.print(array[x][y] + " ");
}
}
}
}
System.out.println("\n");
}
}
Thanks to all the people who have answered, but i figured it out with the help of this post which i found just now, and above is the solution. thanks again :)
Base case is just to obtain neighbour elements by indexing shifting. For (i,j) it will be (i + 1, j), (i - 1, j), etc.
On the edges I use two approaches:
Modulo % operator to avoid IndexOutOfBounds exception, but it sometimes confuse with wrong elements indexation.
Wrap your matrix with one layer of default elements. It adds some extraspace for holding matrices, but makes your code more readable without catching exception, lot ifs and so on. This trick often used when representation maze as matrix.
Example: your default element is 0.
0 0 0 0 0 0
0 1 2 3 4 0
0 2 6 7 3 0
0 1 3 5 7 0
0 2 4 6 2 0
0 0 0 0 0 0
Note: do not forget iterate through actual array size, not extended.
This is my solution for your problem written in Ruby. Instead of calculating if element is at edge you could access elements "over" the edge and handle "nil" values or exceptions that happen there. Then remove "nil" values from final list. This solution is not as good as calculating if some "point" is over the edge or not.
big_map = [[1,2,3,4,5,6],
[8,9,7,5,2,6],
[1,6,8,7,5,8],
[2,7,9,5,4,3],
[9,6,7,5,2,1],
[4,7,5,2,1,3]]
# monkey patch classes to return nil.
[NilClass, Array].each do |klass|
klass.class_eval do
def [](index)
return nil if index < 0 or index > self.size rescue nil
self.fetch(index) rescue nil
end
end
end
class Array
# calculate near values and remove nils with #compact method.
def near(i,j)
[ self[i - 1][j - 1], self[i - 1][j - 0], self[i - 1][j + 1],
self[i - 0][j - 1], self[i - 0][j + 1],
self[i + 1][j - 1], self[i + 1][j - 0], self[i + 1][j + 1],
].compact
end
end
puts big_map.near(1,1).inspect
# => [1, 2, 3, 8, 7, 1, 6, 8]
puts big_map.near(0,0).inspect
# => [2, 8, 9]
puts big_map.near(5,5).inspect
# => [2, 1, 1]
I was working on he same problem and came up with a small optimized solution to find the surrounding numbers of any point in a 2D matrix, hope this helps, please comment if I can shorten the logic somehow
Code:-
import java.util.ArrayList;
public class test {
public static void main(String[] arg){
int[][] arr = {{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25}};
//int[][] arr = {{width,2,3},{4,5,6},{7,8,9}};
ArrayList<Integer> al = new ArrayList<Integer>();
int x = 2, y = 2;
int width = 2; //change the value of width, according to the requirement
for(int i = 0; i < 5; i++){
for(int j = 0; j < 5; j++){
if( (i == (x-width) && ( (y+width) >= j && j >= (y-width))) || (i == (x+width) && ( (y+width) >= j && j >= (y-width))) || (j == (y-width) && ( (x+width) >= i && i >= (x-width))) || (j == (y+width) && ( (x+width) >= i && i >= (x-width))) ){
//if( x >= 0 && i < (i+width) && y >= 0 && j < (j+width))
{
al.add(arr[i][j]);
}
}
}
}
System.out.println(al);
}
}
You didnt mention if you want cyclical neighbours for edges or ignores cyclical neighbours. Assuming you want cyclical neighbours here is the code,
List<Integer> getNeighbours(int[][] mat, int x, int y){
List<Integer> ret = new ArrayList<Integer>();
int rows = mat.length;
int cols = mat[0].length;
for(int i=-1,i<=1;i++)
for(int j=-1;j<=1;j++)
if(i||j) ret = ret.add(mat[(x+i)%rows][(y+j)%cols]);
return ret;
}
(x-1, y-1) -> upper left
(x-1, y) -> left
(x-1, y+1) -> lower left
(x, y+1) -> up
(x, y) -> current position
(x, y-1) -> down
(x+1, y+1) -> upper right
(x+1, y) -> right
(x+1, y-1) -> lower right
You can use this as guide. Now all you need to do is add them in a try catch.
for( int x=0; x<arr.length; x++ ){
for(int y=0; y<arr[x].length; y++){
if( arr[x][y] == 8 ){
try{
System.out.println("Upper Left is: " + arr[x-1][y-1]);
}catch(ArrayIndexOutOfBoundsException e){
//do something
}
try{
System.out.println("Left is: " + arr[x-1][y]);
}catch(ArrayIndexOutOfBoundsException e){
//do something
}
//.....and others
}
}

More efficient way to check neighbours in a two-dimensional array in Java

Hey all, for a few of my college assignments I've found the need to check neighbouring cells in 2-dimensional arrays (grids). The solution I've used is a bit of a hack using exceptions, and I'm looking for a way to clean it up without having loads of if statements like some of my classmates. My current solution is
for ( int row = 0; row < grid.length; row++ ) {
for ( int col = 0; col < grid.length; col++ ) {
// this section will usually be in a function
// checks neighbours of the current "cell"
try {
for ( int rowMod = -1; rowMod <= 1; rowMod++ ) {
for ( int colMod = -1; colMod <= 1; colMod++ ) {
if ( someVar == grid[row+rowMod][col+colMod] ) {
// do something
}
}
}
} catch ( ArrayIndexOutOfBoundsException e ) {
// do nothing, continue
}
// end checking neighbours
}
}
I shudder to think of the inefficiency using exceptions to get my code to work causes, so I'm looking for suggestions as to how I could remove the reliance on exceptions from my code without sacrificing readability if it's possible, and just how I could make this code segment generally more efficient. Thanks in advance.
You can try this.
First decide the size of the grid Lets say its 8 X 8 & assign MIN_X = 0, MIN_Y = 0, MAX_X =7, MAX_Y =7
Your curren position is represented by thisPosX , thisPosY, then try this:
int startPosX = (thisPosX - 1 < MIN_X) ? thisPosX : thisPosX-1;
int startPosY = (thisPosY - 1 < MIN_Y) ? thisPosY : thisPosY-1;
int endPosX = (thisPosX + 1 > MAX_X) ? thisPosX : thisPosX+1;
int endPosY = (thisPosY + 1 > MAX_Y) ? thisPosY : thisPosY+1;
// See how many are alive
for (int rowNum=startPosX; rowNum<=endPosX; rowNum++) {
for (int colNum=startPosY; colNum<=endPosY; colNum++) {
// All the neighbors will be grid[rowNum][colNum]
}
}
you can finish it in 2 loops.
So row and col currently contain the coordinate of the cell that I want to check the neighbours of. So if I have a class variable called START_OF_GRID which contains 0, my solution would be as follows:
int rowStart = Math.max( row - 1, START_OF_GRID );
int rowFinish = Math.min( row + 1, grid.length - 1 );
int colStart = Math.max( col - 1, START_OF_GRID );
int colFinish = Math.min( col + 1, grid.length - 1 );
for ( int curRow = rowStart; curRow <= rowFinish; curRow++ ) {
for ( int curCol = colStart; curCol <= colFinish; curCol++ ) {
// do something
}
}
why can't you check row+rowMod and col+colMod for validity before array access?
something like:
r=row+rowMod;
c=col+colMod;
if (r < 0 || c < 0 || r >= grid.length || c >= grid.length) continue;
alternatively (no continue):
if (r >= 0 && c >= 0 && r < grid.length && c < grid.length &&
someVar == grid[r][c]) { /* do something */ }
The basic principle is not to access things that are out of bounds -- so either protect the bounds or don't go out of bounds in the first place. That is, start at a place where you won't immediately go out of bounds and stop before you get out of bounds.
for ( int row = 1; row < grid.length - 1; row++ ) {
for ( int col = 1; col < grid.length - 1; col++ ) {
// this section will usually be in a function
// checks neighbours of the current "cell"
for ( int rowMod = -1; rowMod <= 1; rowMod++ ) {
for ( int colMod = -1; colMod <= 1; colMod++ ) {
if ( someVar == grid[row+rowMod][col+colMod] ) {
// do something
}
}
}
// end checking neighbours
}
}
Like your current code, this doesn't necessarily deal appropriately with edge conditions -- that is, it applies a 3x3 grid everywhere that the 3x3 grid fits within the matrix, but does not shrink the grid to a 2x2, 2x3 or 3x2 grid when on the edge of the matrix. It will, however, allow a method in the main body checking a 3x3 grid to observe every cell in the matrix.
If I understand your code correctly, and am correctly guessing your concerns, you're trying to avoid checking a non-existent neighbour when the cell of interest is on one edge of the grid. One approach, which may or may not suit your application, is to put a 1-cell wide border all the way round your grid. You then run your loops across the interior of this expanded grid, and all the cells you check have 4 neighbours (or 8 if you count the diagonally neighbouring cells).
How about this:
private static void printNeighbours(int row, int col, int[][] Data, int rowLen, int colLen)
{
for(int nextR=row-1; nextR<=row+1; nextR++)
{
if(nextR<0 || nextR>=rowLen)
continue; //row out of bound
for(int nextC=col-1; nextC<=col+1; nextC++)
{
if(nextC<0 || nextC>=colLen)
continue; //col out of bound
if(nextR==row && nextC==col)
continue; //current cell
System.out.println(Data[nextR][nextC]);
}
}
}
private void fun(char[][] mat, int i, int j){
int[] ith = { 0, 1, 1, -1, 0, -1 ,-1, 1};
int[] jth = { 1, 0, 1, 0, -1, -1 ,1,-1};
// All neighbours of cell
for (int k = 0; k < 8; k++) {
if (isValid(i + ith[k], j + jth[k], mat.length)) {
//do something here
}
}
}
private boolean isValid(int i, int j, int l) {
if (i < 0 || j < 0 || i >= l || j >= l)
return false;
return true;
}

Categories