Is there any way of avoiding this block of code? - java

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]++;

Related

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

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

How to find specific neighbors in a two-dimensional array

I have an exercise where I have a 2D array in Java. I take user input, a String, that looks something like "F3 F7" and I mark the coordinates given on the array. Please see below picture.
2DArray
My problem is the fact that I need to check the neighbors of the input to make sure that future inputs do not touch (neither vertically, nor horizontally).
I found the below code in a post here, but I simply do not have the inspiration on how to implement it in order to check only for a specific set in the array.
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");
}
}

Dynamic programming - Getting number of paths in grid from starting point to end point

I have a matrix, a start point and an end point, and I want to compute a matrix where each matrix[i][j] represents the number of paths from starting point to end point which go by the (i, j) position.
My solution computes the total number of paths from starting point to end point correctly (the value stored in matrix[startx][starty] or matrix[endx][endy]), but not all of the other values are correct.
What do you suggest me?
My code is as follows:
private static long solve() {
board[startx][starty] = 1;
for (int i = endx; i <= startx; i++) {
for (int j = endy; j >= starty; j--) {
if (i > 0 && j < board[i].length - 1)
board[i][j] += board[i - 1][j] + board[i][j + 1];
else if (i > 0)
board[i][j] += board[i - 1][j];
else if (j < tablero[i].length - 1)
board[i][j] += board[i][j + 1];
}
}
for(int j = starty + 1; j < endy; j++) {
board[endx][j] = board[endx + 1][j] +
board[endx][j - 1];
}
for(int i = endx + 1; i < startx; i++) {
board[i][endy] = board[i + 1][endy] +
board[i][endy - 1]);
}
board[endx][endy] = board[endx][endy - 1] +
board[endx + 1][endy]);
return board[startx][starty];
}
Thank you.
Don't you just start out with something like this:
[[0,0,0,0,0,0]
,[0,0,1,0,0,0]
,[0,0,1,0,0,0]
,[0,0,1,1,1,0]
,[0,0,0,0,0,0]
,[0,0,0,0,0,0]]
and then M[i][j] = M[i-1][j] + M[i][j-1] ?
[[0,0,0,0,0,0]
,[0,0,1,3,6,0]
,[0,0,1,2,3,0]
,[0,0,1,1,1,0]
,[0,0,0,0,0,0]
,[0,0,0,0,0,0]]

finding the average of a 2-d array in a pgm file in java

Hey I am suppose to build a low pass filter for a 2-d array for a pgm file. The program is suppose to replace each pixel with the average of it and its 8 nearest neighbors. I am stuck and have no idea what i'm doing wrong. thanks for the help. Now it is giving me a java.lang.ArrayIndexOutOfBoundsException: -1 error.
public static int[][] lowpass(int[][] image)
{
int height = image.length;
int width = image[0].length;
int[][] result = new int[height][width];
int sum;
int avg;
for (int col = 0; col < image.length; col++)
{
result[0][col] = image[0][col];
result[height - 1][col] = image[height - 1][col];
}
for (int row = 0; row < image[0].length; row++)
{
result[row][0] = image[row][0];
result[row][width - 1] = image[row][width - 1];
}
for (int row = 1; row < height - 1; row++)
{
for (int col = 1; col < width - 1; col++)
{
sum = image[row - 1][col - 1] + image[row - 1][col] + image[row - 1][col + 1] + image[row][col - 1] + image[row][col] + image[row][col + 1] + image[row +1][col - 1] + image[row +1][col] + image[row + 1][col + 1];
avg = sum / 9;
result[row][col] = avg;
}
}
return result;
}
You have many errors in your code:
You iterate over all cells, not only on neighbors.
You never add value to sum.
You need to reset it every time you check a new cell.
I would write a simpler method calculateAvg(image, col, row) which would calculate the average based on cell and neighbors. Don't forget to check what happen on edges.

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
}
}

Categories