GameOfLife IndexOutOfBounds Error-handling - java

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.

Related

Finding adjacent matrix: Java.lang.ArrayIndexOutOfBoundsException

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.

Trying to check everything adjacent in Matrix

I was wondering if there was a more simple way to do this? The project requires me to write this method that uses another method that returns a Boolean of true or false if there is treasure located there. I got that method down, but it now wants me to write a method that returns how much treasure is located adjacent (in all directions) to a set place in a row and column. I mapped this out on a piece of paper and came out with... this. But, I feel like I am repeating code but I don't understand any other way that can satisfy the condition. I would love for it to be more condensed... I was thinking 2 for loops? But there's two conditions that wouldn't work in the for loop.
//precondition: 0<=row<rows in map and 0<=col<cols in map
//postcondition: returns a count of the number of treasures in the cells adjacent to the location row,col
//horizontally, vertically, and diagonally.
public int numAdjacent(int row, int col) {
if(hasTreasure(row,col)) {
return -1;
}
int numOfTreasure = 0;
if ((0<=row && row < mapHeight()) && (0<=col && col < mapWidth())) {
if(hasTreasure(row - 1,col - 1)) {
numOfTreasure++;
}
}
if (0<=row && row < mapHeight()) {
if(hasTreasure(row - 1,col)) {
numOfTreasure++;
}
}
if ((0<=row && row < mapHeight()) && 0<=col && col < mapWidth()) {
if(hasTreasure(row - 1,col + 1)) {
numOfTreasure++;
}
}
if (0<=row && row < mapHeight()) {
if(hasTreasure(row + 1,col)) {
numOfTreasure++;
}
}
if ((0<=row && row < mapHeight()) && 0<=col && col < mapWidth()) {
if(hasTreasure(row + 1,col + 1)) {
numOfTreasure++;
}
}
if ((0<=row && row < mapHeight()) && 0<=col && col < mapWidth()) {
if(hasTreasure(row + 1,col - 1)) {
numOfTreasure++;
}
}
if (0<=col && col < mapWidth()) {
if(hasTreasure(row,col + 1)) {
numOfTreasure++;
}
}
if (0<=col && col < mapWidth()) {
if(hasTreasure(row,col - 1)) {
numOfTreasure++;
}
}
return numOfTreasure;
}
You're on the right track with using nested for-loops! Because we're dealing with a matrix, each element has 8 adjacent neighbors at which treasure can be located. For this reason, we can use nested for-loops to check if each adjacent neighbor has treasure; if the neighbor's coordinates are out-of-bounds, we simply skip it within the loop.
public int numAdjacent(int row, int col) {
int numOfTreasure = 0;
for (int currentCol = col - 1; currentCol <= col + 1; currentCol++) {
for (int currentRow = row - 1; currentRow <= row + 1; currentRow++) {
if (currentRow < 0 || currentRow >= mapHeight() || currentCol < 0 || currentCol >= mapWidth()) {
continue;
}
numOfTreasure += hasTreasure(currentRow, currentCol) ? 1 : 0;
}
}
return numOfTreasure;
}
Once you understand that for-loop, it can be simplified even further:
public int numAdjacent(int row, int col) {
int numOfTreasure = 0;
for (int currentCol = Math.max(0, col - 1); currentCol <= Math.min(col + 1, mapWidth() - 1); currentCol++) {
for (int currentRow = Math.max(0, row - 1); currentRow <= Math.min(row + 1, mapHeight() - 1); currentRow++) {
numOfTreasure += hasTreasure(currentRow, currentCol) ? 1 : 0;
}
}
return numOfTreasure;
}

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.

ArrayOutofBounds Exception even though it checks if the square is on the edge

This code is part of the code for my Conway's Game of Life simulation. This particular method is a 'step', advancing the game forward by one generation.
There seems to be an error when it attempts to check if the square straight up is true or false (this is a 10 x 10 boolean array at the moment). The code's intention is to check every square and count how many neighbors each square has. I have if statements making it so that the squares on the edges and corners go under special conditions (e.g. the one in the top right doesn't check for the squares straight up, top right, and directly right)
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 10
at Life.step(Life.java:71)
The error is above and Line 71 is the if statement that checks for a neighbor straight down
public void step() {
System.out.println("Step");
System.out.println(cells.length);
System.out.println(cells[0].length);
boolean[][] nextCells = new boolean[cells.length][cells[0].length];
for (int row = 0; row < cells.length; row++) {
for (int col = 0; row < cells[0].length; col++) {
int neighborCount = 0;
// checks for neighbor straight down
if (row > 0 && cells[row - 1][col] == true) {
neighborCount++;
}
// lower right
if (row > 0 && col < cells[0].length - 1 && cells[row - 1][col + 1] == true) {
neighborCount++;
}
// right
if (col < cells[0].length - 1 && cells[row][col + 1] == true) {
neighborCount++;
}
// upper right
if (row < cells.length - 1 && col < cells[0].length - 1 && cells[row + 1][col + 1] == true) {
neighborCount++;
}
// straight up
if (row < cells.length - 1 && cells[row + 1][col] == true) {
neighborCount++;
}
// upper left
if (row < cells.length - 1 && col > 0 && cells[row + 1][col - 1] == true) {
neighborCount++;
}
// left
if (col > 0 && cells[row][col - 1] == true) {
neighborCount++;
}
// lower left
if (row > 0 && col > 0 && cells[row - 1][col - 1]) {
neighborCount++;
}
Look at the line above where the error is being thrown:
for (int col = 0;row< cells[0].length; col++) {
This should be:
for (int col = 0;col< cells[row].length; col++) {

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