Hello, this is my first post to Java Programming forums, so hopefully all goes well.
I've finished implementing the code for a 2D boolean array-based implementation for John Conway's Game Of Life. The program functions properly (without-errors) under all conditions, however I would like to improve it's effiicency.
I've pasted the section of the code in question below. This will probably make most experienced programmers laugh or cry, but I am beginner, so that's to be expected.
What I'm looking for is some detailed and specific ways to improve the code to make it less stressful on the CPU, and make it easier to read. In particular, I'm looking for ways to get rid of the excessive if statements for neighbor checking, and to reduce the number of cells checked by the nextGeneration methods (to only cells that will be subject to surviving, dying, or being vivified).
ALIVE and DEAD are boolean constants that correspond to true and false respectively.
MAX_ROWS and MAX_COLS are int constants defining he limits of the grid (array size).
// copyMap: // Precondtions: None. // Postcondtion: 'map' is a deep copy of 'sourceMap'. // private void copyMap(boolean sourceMap[][]) { for(int r = 0; r < MAX_ROWS; r++){ for(int c = 0; c < MAX_COLS; c++){ map[r][c] = sourceMap[r][c]; } } } // clearMap: // Precondtions: None. // Postcondtion: Sets all cells of the 'targetMap' to DEAD. // private void clearMap(boolean targetMap[][]) { for(int r = 0; r < MAX_ROWS; r++){ for(int c = 0; c < MAX_COLS; c++){ targetMap[r][c] = DEAD; } } } // getFlatNeighborCount: // Precondtions: 0 <= row < MAX_ROWS and 0 <= col < MAX_COLS. // Postcondtion: A count of all LIVE neighbors of the cell at [row, col] is // returned where its neighbors are all the ADJACENT cells // including those // a) In the rows BELOW and ABOVE the cell (if any exist). // b) In the columns LEFT and RIGHT of the cell (if any exist). // Thus, a cell adjacent to a board edge (or corner) has // fewer neighbors than other cells. // private int getFlatNeighborCount(int row, int col){ int count = 0; if(row - 1 >= 0 && map[row - 1][col]){ count++; } if(row + 1 < MAX_ROWS && map[row + 1][col]){ count++; } if(col - 1 >= 0 && map[row][col - 1]){ count++; } if(col + 1 < MAX_COLS && map[row][col + 1]){ count++; } if((row - 1 >= 0 && col - 1 >= 0) && map[row -1][col -1]){ count++; } if((row - 1 >= 0 && col + 1 < MAX_COLS) && map[row - 1][col + 1]){ count++; } if((row + 1 < MAX_ROWS && col - 1 >= 0) && map[row + 1][col -1]){ count++; } if((row + 1 < MAX_ROWS && col + 1 < MAX_COLS) && map[row + 1][col + 1]){ count++; } return count; } // nextGenerationForFlatGrid: // Precondtions: None // Postcondtion: The next generation of live and dead cells is calculated using // a) the FLAT neighbor counts. // b) the current birth, survival and death count rules. // c) the rules are applied to the counts obtained from the current // generation's configuration of live and dead cells. // The current 'map' is updated to the next generation's configuration // of live and dead cells. // d) the global variable 'generation' is increased by 1 // public void nextGenerationForFlatGrid() { for(int row = 0; row < MAX_ROWS; row++){ for(int col = 0; col < MAX_COLS; col++){ int neighborCount = getFlatNeighborCount(row, col); if(!map[row][col] && neighborCount == 3){ newMap[row][col] = ALIVE; } else if(map[row][col] && (neighborCount == 2 || neighborCount == 3)){ newMap[row][col] = ALIVE; } else if(map[row][col] && neighborCount <= 1){ newMap[row][col] = DEAD; } else if(map[row][col] && neighborCount >= 4){ newMap[row][col] = DEAD; } } } copyMap(newMap); clearMap(newMap); generation++; } // ==> 5. Implement the game of life for torus grid. /**getTorusNeighborCount * Preconditions: 0 <= row < MAX_ROWS and 0 <= col < MAX_COLS. * Postconditions: The count is increased for each living adjacent neighbor. * This counts only neighbors located on adjacent edges of the grid. * The count is returned when finished. */ public int getTorusNeighborCount(int row, int col){ int count = 0; if((row == MAX_ROWS - 1) && map[0][col]){ count++; } if((row == MAX_ROWS - 1 && col > 0) && map[0][col - 1]){ count++; } if((row == MAX_ROWS - 1 && col < MAX_COLS - 1) && map[0][col + 1]){ count++; } if(row == 0 && map[MAX_ROWS - 1][col]){ count++; } if((row == 0 && col > 0) && map[MAX_ROWS - 1][col - 1]){ count++; } if((row == 0 && col < MAX_COLS - 1) && map[MAX_ROWS - 1][col + 1]){ count++; } if((col == MAX_COLS - 1) && map[row][0]){ count++; } if((col == MAX_COLS - 1 && row > 0) && map[row - 1][0]){ count++; } if((col == MAX_COLS - 1 && row < MAX_ROWS - 1) && map[row + 1][0]){ count++; } if((col == 0) && map[row][MAX_COLS - 1]){ count++; } if((col == 0 && row > 0) && map[row - 1][MAX_COLS - 1]){ count++; } if((col == 0 && row < MAX_ROWS - 1) && map[row + 1][MAX_COLS - 1]){ count++; } if((row == 0 && col == 0) && map[MAX_ROWS - 1][MAX_COLS - 1]){ count++; } if((row == MAX_ROWS - 1 && col == 0) && map[0][MAX_COLS - 1]){ count++; } if((row == 0 && col == MAX_COLS - 1) && map[MAX_ROWS - 1][0]){ count++; } if((row == MAX_ROWS - 1 && col == MAX_COLS - 1) && map[0][0]){ count++; } return count; } /** nextGenerationForTorusGrid() * Precondition: None * Postcondition: The grid is updated utilizing the FLAT and TORUS neighbor counts. * The same birth, survival and death rules apply as with the next FLAT generation. * The generation variable is increased by 1. * */ public void nextGenerationForTorusGrid() { for(int row = 0; row < MAX_ROWS; row++){ for(int col = 0; col < MAX_COLS; col++){ int neighborCount = getFlatNeighborCount(row, col) + getTorusNeighborCount(row, col); if(!map[row][col] && neighborCount == 3){ newMap[row][col] = ALIVE; } else if(map[row][col] && (neighborCount == 2 || neighborCount == 3)){ newMap[row][col] = ALIVE; } else if(map[row][col] && neighborCount <= 1){ newMap[row][col] = DEAD; } else if(map[row][col] && neighborCount >= 4){ newMap[row][col] = DEAD; } } } copyMap(newMap); clearMap(newMap); generation++; }