strange IndexOutOfBound error - java

Hello I am writing a program for a programming class and I am getting a:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 18
at Life.countNeighbors(Life.java:200)
at Life.genNextGrid(Life.java:160)
I've gotten ArrayIndexOutOfBoundsException errors before, usually caused when I try to add or substract a index of an array. However this time it is quite different and I was hoping someone here can point out why the error is occuring.
info about my program: the program is like John Conway game of life. using a 2d array and then setting certain elements to (true = alive) or (false = dead) the program then determine if a cell lives or dies in the next generation base on the number of neighbors it has. (3 neighbors = birth of a new cell) (2,3 neighbor = they stay alive) anything else they died in the next generation.
The IndexOutOfBound error is caused by this line according to my editor:
if(!(grid[1][1]) && !(grid[1][18]) && !(grid[18][1]) && !(grid[18][18]))
I created the above line as a constraint, and it should not tell java to search a index beyond the bounds of the original array since they are merely booleans (true/false)statement in the end. If anyone can help me debug this error that would be splendid.
HERE IS MY CODE: (does not include main method)
public static void clearGrid ( boolean[][] grid )
{
int col;
int row = 1;
while(row < 18){
for(col = 1; col < 18; col++){
grid[row][col]= false;//set each row to false
}
row++;
}//set all elements in array to false
}
public static void genNextGrid ( boolean[][] grid )
{
//new tempprary grid
boolean[][] TempGrid = new boolean[GRIDSIZE][GRIDSIZE];
TempGrid= grid; // copy the current grid to a temporary grid
int row = 1;
int col = 1;
countNeighbors(TempGrid, row, col); // passes the TempGrid to countNieghbor method
for(row = 1; row < 18; row++){
countNeighbors(TempGrid, row, col);
for(col = 1; col < 18; col++){
countNeighbors(TempGrid, row, col);
if(countNeighbors(grid, row, col) == 3)
{
TempGrid[row][col] = true;
}
else if(countNeighbors(grid, row, col) == 2 || countNeighbors(grid, row, col) == 3)
{
TempGrid[row][col] = true;
}
else
{
TempGrid[row][col] = false;
}
}
}
}
public static int countNeighbors ( final boolean[][] grid, final int row, final int col )
{
int n = 0; //int used to store the # of neighbors
int temprow = row;
int tempcol = col;
//count # of neighbors for the cell on the edge but not the corner
for(temprow = row; temprow <= 18; temprow++)
{
for(tempcol = row; tempcol <= 18; tempcol++)
{
if(temprow == 1 || temprow == 18 || tempcol == 1 || tempcol ==18)
{
if(!(grid[1][1]) && !(grid[1][18]) && !(grid[18][1]) && !(grid[18][18]))
{
if(grid[temprow][tempcol] == true)
{
n++;
}
}
}
}
}
//count # of neighbors for the corner cells
for(temprow = row; temprow <= 18; temprow++)
{
for(tempcol = row; tempcol <= 18; tempcol++)
{
if(grid[1][1] || grid[1][18] || grid[18][1] || grid[18][18])
{
if(grid[temprow][tempcol] == true)
{
n++;
}
}
}
}
// count the cells that are not on the edge or corner
while(temprow >= 2 && tempcol >= 2 && temprow <= 17 && tempcol <= 17)
{
for(temprow = row; temprow-1 <= temprow+1; temprow++)
{
for(tempcol = col; tempcol-1 <= tempcol+1; tempcol++)
{
if(grid[temprow][tempcol] == true)
{
n++;
}
}
}
}
return n; // return the number of neighbors
}

Without a full stack trace and an indication as to where the problem lies, this is my best guess:
grid[18][1]
The value 18 is beyond the size of the array you can access, in Java arrays are zero based (0). Since I have seen 17 all throughout your post, this seems like the most logical reason why.

In Java, array indices are numbered from 0 to n-1. From looking at your code, it would appear that it assumes that they are numbered from 1 to n.

Related

Finding path depending on cells' value on 2D grid array

I have a grid composed with JLabel. Each cell has 3 states:
public enum Token{
VIDE, CERCLE_ROUGE, CERCLE_BLEU
}
An empty cell == Token.VIDE
I have this simple algorithm that find all neighbors of a given cell then I use swing custom painting to draw a polygon following the path having the center of the label as points.
private CellsList getNeighbors(int row, int col) {
CellsList neighbors = new CellsList();
for (int colNum = col - 1 ; colNum <= (col + 1) ; colNum +=1 ) {
for (int rowNum = row - 1 ; rowNum <= (row + 1) ; rowNum +=1 ) {
if(!((colNum == col) && (rowNum == row))) {
if(withinGrid (rowNum, colNum ) ) {
neighbors.add( new int[] {rowNum, colNum});
}
}
}
}
return neighbors;
}
here is the condition to have a path:
if((size() >= MIN_PATH_LEGTH) && neighbors.contains(origin) ) {
add(cell);
return true;
}
Now I want to make it more precise by adding conditions such as a path can be valid if only there are at least 4 cells with the same value found in the neighborhood AND at least one opposite value.
Example:
Red cells at (11, 10)(10, 11)(11, 12)(12, 11) can form a valid path if only there is at least a Blue cell at (11, 11). (See image below)
And the following can't be a valid path, so no drawing:
For now, the algorith finds a path only with the minimal value (int MIN_PATH_LEGTH = 3) I've defined but I can't find a way to define the second condition (at least one opposite cell value within the neighborhood)
I'll edit with new elements if needed.
test before calling this method if the redCell's path OK:
public boolean isThereABlueCellWithinMyRedPath() {
// height = height of your map
// width = width of yout map
// this array is suppose to be in an other place...
Cell[][] cellArray = new Cell[height][width];
// ... so are those two lists
List<Cell> blueCellsList = new ArrayList<>();
List<Cell> redCellsList = new ArrayList<>();
//foreach blueCell on the map ...
for (Cell blueCell : blueCellsList) {
boolean north = false;
boolean east = false;
boolean south = false;
boolean west = false;
int originX = blueCell.getX();
int originY = blueCell.getY();
// ... if there is a redCell at north...
for (int i = originY; i >= 0; i--) {
if (redCellsList.contains(cellArray[originX][i])) {
north = true;
break;
}
}
// ... East ...
for (int i = originX; i < cellArray[originX].length; i++) {
if (redCellsList.contains(cellArray[i][originY])) {
east = true;
break;
}
}
// ... South ...
for (int i = originY; i < cellArray.length; i++) {
if (redCellsList.contains(cellArray[originX][i])) {
south = true;
break;
}
}
// ... West ...
for (int i = originX; i >= 0; i--) {
if (redCellsList.contains(cellArray[i][originY])) {
west = true;
break;
}
}
// ... I am surrended by redCell
if (south && east && north && west)
return true;
}
return false;
}
I did not try the code but it seems to work.
My answer is based on the code posted in a previous answer.
Path class
Add isWithinLoop to check if a cell is within path by checking if it has a
path-cell to its left, right, top and bottom.
Also add getContainedWithin which returns a collection of all cells that are bounded by the path, and their token is of the opposite color of the path
//returns a collection of all cells that are bounded by the path
//and their token is of the opposite color of the path
List<int[]> getContainedWithin() {
//find path max and min X values, max and min Y values
minPathRow = grid[0].length; //set min to the largest possible value
maxPathCol = grid.length;
maxPathRow = 0; //set max to the largest possible value
maxPathCol = 0;
//find the actual min max x y values of the path
for (int[] cell : this) {
minPathRow = Math.min(minPathRow, cell[0]);
minPathCol = Math.min(minPathCol, cell[1]);
maxPathRow = Math.max(maxPathRow, cell[0]);
maxPathCol = Math.max(maxPathCol, cell[1]);
}
//todo remove after testing
System.out.println("x range: "+minPathRow + "-"
+ maxPathRow + " y range: " + minPathCol + "-" + maxPathCol);
List<int[]> block = new ArrayList<>(25);
int[] cell = get(0);//get an arbitrary cell in the path
Token pathToken = grid[cell[0]][cell[1]]; //keep a reference to its token
//iterate over all cells within path x, y limits
for (int col = minPathCol; col < (maxPathCol); col++) {
for (int row = minPathRow; row < (maxPathRow); row++) {
//check cell color
Token token = grid[row][col];
if ((token == pathToken) || (token == Token.VIDE)) {
continue;
}
if (isWithinLoop(row,col)) {
block.add(new int[] {row, col});
}
}
}
return block;
}
//check if row, col represent a cell with in path by checking if it has a
//path-cell to its left, right, top and bottom
private boolean isWithinLoop(int row, int col) {
if( isPathCellOnLeft(row, col)
&&
isPathCellOnRight(row, col)
&&
isPathCellOnTop(row, col)
&&
isPathCellOnBottom(row, col)
) {
return true;
}
return false;
}
private boolean isPathCellOnLeft(int cellRow, int cellCol) {
for ( int col = minPathCol; col < cellCol ; col++) {
if(getPath().contains(new int[] {cellRow, col})) {
return true;
}
}
return false;
}
private boolean isPathCellOnRight(int cellRow, int cellCol) {
for ( int col = cellCol; col <= maxPathCol ; col++) {
if(getPath().contains(new int[] {cellRow, col})) {
return true;
}
}
return false;
}
private boolean isPathCellOnTop(int cellRow, int cellCol) {
for ( int row =minPathRow; row < cellRow ; row++) {
if(getPath().contains(new int[] {row, cellCol})) {
return true;
}
}
return false;
}
private boolean isPathCellOnBottom(int cellRow, int cellCol) {
for ( int row = cellRow; row <= maxPathRow; row++) {
if(getPath().contains(new int[] {row, cellCol})) {
return true;
}
}
return false;
}
}
Model class
Add a getter method to access getContainedWithin:
List<int[]> getContainedWithin() {
return (path == null ) ? null : path.getContainedWithin();
}
Control class
Update ModelListener to ignore a path if getContainedWithin is empty:
private class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
IndexedPropertyChangeEvent iEvt = (IndexedPropertyChangeEvent)evt;
int index = iEvt.getIndex();
int row = index / Model.COLS;
int col = index % Model.COLS;
Token token = (Token) evt.getNewValue();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
view.setCell(token, row, col);
CellsList path = model.getPath();
//ignore path if null, empty or encloses no cell
if((path == null) || path.isEmpty()
|| model.getContainedWithin().isEmpty()) {
return;
}
view.addPath(path);
view.refresh();
}
});
}
}
The complete code can be downloaded for this repo.
Maybe you can make a list of blue cells and redcells and if you want to test if a there's a blue cell within the red cell's path you:
go to NORTH until you meet a redCell or a map limit : if it 's a map limit you test with the next blueCell, else you go back to your position and do the same for EAST, SOUTH, WEST.
If on the 4 sides you find a redCell first, you return true else you return false.
It can be enough if you want to test in a quite small map. But if the shape made by the red cell can be free I don't find a better way.

managing references in parameter passing in java

A friend gave me a class that tries to solve sudoku puzzels. Thing is the changes of the array inside the method is not reflected in the original array. Here's the code:
public static void solve(int array[][], int row, int col)
{
if( row > 8 )
{
printBoard(array); // this gives the correct result
return;
}
if( array[row][col] != 0 )
nextEmptyCell(array, row, col );
else
{
for( int num = 1; num < 10; num++ )
{
if(validityRowColBox(array, row, col, num))
{
array[row][col] = num;
nextEmptyCell(array, row, col);
}
}
array[row][col] = 0;
}
}
public static void nextEmptyCell(int array[][], int row, int col)
{
if( col < 8 )
solve(array, row, col + 1 );
else
solve(array, row + 1, 0 );
}
//This boolean methods will checks the validity of the number for the given row, columns and its designated box.
public static boolean validityRowColBox(int array[][], int row, int col, int num)
{
for(int c = 0; c <9; c++ )
{
if( array[row][c] == num )
return false;// It return false if the number is already exist in the given row.
}
for(int r = 0; r <9; r++ )
{
if(array[r][col] == num )
return false;// It return false if the number is already exist in the given columns.
}
row = (row / 3) * 3 ;
col = (col / 3) * 3 ;
for( int r = 0; r < 3; r++ )
{
for( int c = 0; c < 3; c++ )
{
if( array[row+r][col+c] == num )
return false;// It return false if the number is already exist in the designated box.
}
}
return true;// Otherwise true.
}
// sample input
public static int[][] easy ()
{
return new int[][]
{{0,0,0,2,6,0,7,0,1},
{6,8,0,0,7,0,0,9,0},
{1,9,0,0,0,4,5,0,0},
{8,2,0,1,0,0,0,4,0},
{0,0,4,6,0,2,9,0,0},
{0,5,0,0,0,3,0,2,8},
{0,0,9,3,0,0,0,7,4},
{0,4,0,0,5,0,0,3,6},
{7,0,3,0,1,8,0,0,0}};
}
public static void main(String args[])
{
int inputArray[][] = easy();
solve(inputArray,0,0);
printBoard(inputArray); // items still the same!
}
}
If I call the printBoard(array); function inside the method, the elements of the array appears to change. But when I call the printBoard(array); method in the main method on the original array, the changes are lost, the values are back to original again. I am extremely confused by this. None of the methods creates a new object so it should still point to the inputArray object. What's happening?
Edit: Here's the printBoard() method
public static void printBoard(int array[][])
{
//This is the board method.
for (int row = 0; row < array.length; row++)
{
if (row % 3 == 0)//If the row is divisible by 3 then print the plus(+) and minus(-) sign.
System.out.println("+-------+-------+-------+");
for (int col = 0; col < array[row].length; col++) {
if (col % 3 == 0)// If the column is divisible by 3 then print the or(|) symbol.
System.out.print("| ");
System.out.print(array[row][col]+ " ");
}
System.out.println("|");
}
System.out.println("+-------+-------+-------+");
}
The problem is that when you come back from the various recursive calls there is an instruction that modify the content of the array (see the comments):
for( int num = 1; num < 10; num++ )
{
if(validityRowColBox(array, row, col, num))
{
array[row][col] = num;
nextEmptyCell(array, row, col); // after you finish you come back from here
}
}
array[row][col] = 0; // ...and this will change the solution you found
Apparently this cause the array to come back to his original state.
I didn't look how the program works but avoiding to execute that instruction if we found the solution will return the correct array, for example:
public static boolean solve(int array[][], int row, int col) {
if (row > 8) {
printBoard(array);
return true;
}
if (array[row][col] != 0) {
return nextEmptyCell(array, row, col);
}
for (int num = 1; num < 10; num++) {
if (validityRowColBox(array, row, col, num)) {
array[row][col] = num;
if (nextEmptyCell(array, row, col)) {
return true; // if solution is found we just exit
}
}
}
array[row][col] = 0;
return false;
}
public static boolean nextEmptyCell(int array[][], int row, int col) {
if (col < 8) {
return solve(array, row, col + 1);
}
return solve(array, row + 1, 0);
}

Unsure about the logic of the code

I cant test my method's code manually yet as Im not done with other associated code yet, but I feel like the logic of the method public boolean isFilledAt(int row, int col) is wrong. The method returns true if the shape has a filled block (any char) at the given row/col position and false if the block is empty(the dot '.'). If the position is out of bounds, raise a FitItException with an informative message. Could smb please look through it and let me know if anything is wrong with the method's code? Thanks!
public class CreateShape {
private int height;
private int width;
private char dc;
private Rotation initialPos;
private char[][] shape = new char[height][width];
public boolean isFilledAt(int row, int col)
{
if(row < 0 || row >= height || col < 0 || col >= width)
throw new FitItException("Oops! Out of bounds!");
else
{
for (int i = 0; i < shape.length; i++)
for (int j = 0; j < shape[i].length; j++) {
if (shape[row][col] == dc)
return true;
}
}
return false;
}
public boolean isFilledAt(int row, int col) {
if(row < 0 || row >= height || col < 0 || col >= width)
throw new FitItException("Oops! Out of bounds!");
else
return (shape[row][col] == dc);
}
does the same as your code currently does. I'm not sure what you are going through the array for, you're not even using the i and j variables.

8 Non-Attacking Queens Algorithm with Recursion

I'm having trouble coding the 8 queens problem. I've coded a class to help me solve it, but for some reason, I'm doing something wrong. I kind of understand what's supposed to happen.
Also, we have to use recursion to solve it but I have no clue how to use the backtracking I've read about, so I just used it in the methods checking if a position is legitimate.
My board is String [] [] board = { { "O", "O"... etc etc with 8 rows and 8 columns.
If I'm getting anything wrong conceptually or making a grave Java mistake, please say so :D
Thanks!
public void solve () {
int Queens = NUM_Queens - 1;
while (Queens > 0) {
for (int col = 0; col < 8; col++) {
int row = -1;
boolean c = false;
while (c = false && row < 8) {
row ++;
c = checkPos (row, col);
}
if (c == true) {
board[row][col] = "Q";
Queens--;
}
else
System.out.println("Error");
}
}
printBoard ();
}
// printing the board
public void printBoard () {
String ret = "";
for (int i = 0; i < 8; i++) {
for (int a = 0; a < 8; a++)
ret += (board[i][a] + ", ");
ret += ("\n");
}
System.out.print (ret);
}
// checking if a position is a legitimate location to put a Queen
public boolean checkPos (int y, int x) {
boolean r = true, d = true, u = true, co = true;
r = checkPosR (y, 0);
co = checkPosC (0, x);
int col = x;
int row = y;
while (row != 0 && col != 0 ) { //setting up to check diagonally downwards
row--;
col--;
}
d = checkPosDD (row, col);
col = x;
row = y;
while (row != 7 && col != 0 ) { //setting up to check diagonally upwards
row++;
col--;
}
d = checkPosDU (row, col);
if (r = true && d = true && u = true && co = true)
return true;
else
return false;
}
// checking the row
public boolean checkPosR (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && x == 7)
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y, x+1);
}
// checking the column
public boolean checkPosC (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && y == 7)
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y+1, x);
}
// checking the diagonals from top left to bottom right
public boolean checkPosDD (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && (x == 7 || y == 7))
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y+1, x+1);
}
// checking the diagonals from bottom left to up right
public boolean checkPosDU (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && (x == 7 || y == 0))
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y-1, x+1);
}
}
As this is homework, the solution, but not in code.
Try to write a method that only handles what needs to happen on a single column; this is where you are supposed to use recursion. Do backtracking by checking if a solution exists, if not, undo your last change (i.e. change the queen position) and try again. If you only focus on one part of the problem (one column), this is much easier than thinking about all columns at the same time.
And as Quetzalcoatl points out, you are assigning false to your variable in the first loop. You probably do not want to do that. You should always enable all warnings in your compiler (run javac with -Xlint) and fix them.
You are trying some kind of brute-force, but, as you already mentioned, you have no recursion.
Your programs tries to put a queen on the first possible position. But at the end no solution is found. It follows that your first assumption (the position of your first queen) is invalid. You have to go back to this state. And have to assume that your checkPos(x,y) is false instead of true.
Now some hints:
As mentioned before by NPE int[N] queens is more suitable representation.
sum(queens) have to be 0+1+2+3+4+5+6+7=28, since a position has to be unique.
Instead of checking only the position of the new queen, you may check a whole situation. It is valid if for all (i,j) \in N^2 with queen(i) = j, there exists no (k,l) != (i,j) with abs(k-i) == abs(l-j)

Java Bishop Chess Board

Im working on figuring out the maximum number of bishops I can place on a nxn board without them being able to attack each other. Im having trouble checking the Diagonals. below is my method to check the diagonals. The squares where a bishop currently is are marked as true so the method is supposed to check the diagonals and if it returns true then the method to place the bishops will move to the next row.
Im not quite sure whats going wrong, any help would be appreciated.
private boolean bishopAttack(int row, int column)
{
int a,b,c;
for(a = 1; a <= column; a++)
{
if(row<a)
{
break;
}
if(board[row-a][column-a])
{
return true;
}
}
for(b = 1; b <= column; b++)
{
if(row<b)
{
break;
}
if(board[row+b][column-b])
{
return true;
}
}
for(c = 1; b <= column; b++)
{
if(row<c)
{
break;
}
if(board[row+c][column+c])
{
return true;
}
}
return false;
}
for(c = 1; b <= column; b++)
Shouldn't it be
for(c = 1; c <= column; c++)
By the way:
1) Use i, j, k instead of a, b, c, etc. No REAL reason why... it's just convention.
2) You don't have to keep naming new variables. Try something like this:
for(int i = 1; i <= column; i++)
{
...
}
//because i was declared in the for loop, after the } it no longer exists and we can redeclare and reuse it
for(int i = 1; i <= column; i++)
{
...
}
3) Your error checking is incorrect. It should be something like this:
for(int i = 1; i < 8; i++)
{
int newrow = row - i;
int newcolumn = column - i;
if (newrow < 0 || newrow > 7 || newcolumn < 0 || newcolumn > 7)
{
break;
}
if (board[newrow][newcolumn])
{
return true;
}
}
Now when you copy+paste your for loop, you only have to change how newrow and newcolumn are calculated, and everything else (including loop variable name) will be identical. The less you have to edit when copy+pasting, the better. We also attempt all 7 squares so we don't have to change the ending condition - the if check within the loop will stop us if we attempt to go out of bounds in ANY direction.
4) Better still, of course, would be using the for loop only once and passing only the changing thing into it... something like...
private boolean bishopAttackOneDirection(int rowdelta, int coldelta, int row, int column)
{
for(int i = 1; i < 8; i++)
{
int newrow = row + rowdelta*i;
int newcolumn = column + columndelta*i;
if (newrow < 0 || newrow > 7 || newcolumn < 0 || newcolumn > 7)
{
break;
}
if (board[newrow][newcolumn])
{
return true;
}
}
return false;
}
private boolean BishopAttack(int row, int column)
{
return BishopAttackInOneDirection(-1, -1, row, column)
|| BishopAttackInOneDirection(1, -1, row, column)
|| BishopAttackInOneDirection(1, 1, row, column)
|| BishopAttackInOneDirection(-1, 1, row, column);
}
Probably not quite the expected answer, but there is no reason to make life more complex then it is.
Im working on figuring out the maximum number of bishops I can place on a nxn board without them being able to attack each other.
public int getMaximumNumberOfNonAttackingBishopsForSquareBoardSize(final int boardSize) {
if (boardSize < 2 || boardSize > (Integer.MAX_VALUE / 2))
throw new IllegalArgumentException("Invalid boardSize, must be between 2 and " + Integer.MAX_VALUE / 2 + ", got: " + boardSize);
return 2 * boardSize - 2;
}
Source: http://mathworld.wolfram.com/BishopsProblem.html

Categories

Resources