patternjavaModerate
Game of Life in Java
Viewed 0 times
lifegamejava
Problem
I wrote John Conway's Game of Life in Java:
```
class GameOfLife {
static int countSurrounding(int[][] board, int a, int b) {
int count = 0;
int[][] surrounding = {{a - 1, b - 1},
{a - 1, b },
{a - 1, b + 1},
{a , b - 1},
{a , b + 1},
{a + 1, b - 1},
{a + 1, b },
{a + 1, b + 1}};
for (int i[]: surrounding) {
try {
if (board[i[0]][i[1]] == 1) {
count++;
}
}
catch (ArrayIndexOutOfBoundsException e) {}
}
return count;
}
static void printBoard(int[][] board) {
for (int[] i: board) {
for (int j: i) {
if (j == 1) {
System.out.print("#");
}
else {
System.out.print(".");
}
}
System.out.println();
}
System.out.println();
}
public static void main(String[] args) {
int[][] nextBoard = {{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 1, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 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}};
int[][] board = new int[nextBoard.length][nextBoard[0].length];
for (int gen = 0; gen < 25; gen++) {
for (int i = 0; i < nextBoard.length; i++) {
for (int j = 0; j < nextBoard[i].length; j++) {
boar
```
class GameOfLife {
static int countSurrounding(int[][] board, int a, int b) {
int count = 0;
int[][] surrounding = {{a - 1, b - 1},
{a - 1, b },
{a - 1, b + 1},
{a , b - 1},
{a , b + 1},
{a + 1, b - 1},
{a + 1, b },
{a + 1, b + 1}};
for (int i[]: surrounding) {
try {
if (board[i[0]][i[1]] == 1) {
count++;
}
}
catch (ArrayIndexOutOfBoundsException e) {}
}
return count;
}
static void printBoard(int[][] board) {
for (int[] i: board) {
for (int j: i) {
if (j == 1) {
System.out.print("#");
}
else {
System.out.print(".");
}
}
System.out.println();
}
System.out.println();
}
public static void main(String[] args) {
int[][] nextBoard = {{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 1, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 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}};
int[][] board = new int[nextBoard.length][nextBoard[0].length];
for (int gen = 0; gen < 25; gen++) {
for (int i = 0; i < nextBoard.length; i++) {
for (int j = 0; j < nextBoard[i].length; j++) {
boar
Solution
A few suggestions:
-
Each cell in the Game of Life has exactly two states: dead or alive. Unless you plan to implement
-
The
-
In
Given an index
The same thing for columns (
This itself assumes that
While this is longer, this doesn't abuse exceptions for something totally non-exceptional.
-
The
-
In
-
Now something is becoming obvious: We have collected a few static methods that operate on our
The class could be easily extended to have a static default board, or a constructor that creates a random board.
-
Each “Game of Life” can be described by a ruleset like
then
-
Each cell in the Game of Life has exactly two states: dead or alive. Unless you plan to implement
-1 as undead, I'd suggest you use booleans instead of integers to indicate the state.-
The
int i[] is a bit odd; i is normally used for indices, not for whole rows.-
In
countSurrounding you are using Exceptions to count the surrounding living cells. This is wasteful and unnecessary; we can determine the correct bounds ourself.Given an index
i in an array row, we can get the lower index min and the upper index max byint minRow = i == 0 ? 0 : i - 1;
int maxRow = i == (row.length - 1) ? (row.length - 1) : i + 1;The same thing for columns (
j index in an array column):int minCol = j == 0 ? 0 : j - 1;
int maxCol = j == (column.length - 1) ? (column.length - 1) : j + 1;This itself assumes that
i and j always are inside the bounds. We can then loop over the surrounding cells likefor (int row_idx = minRow; row_idx <= maxRow; row_idx++) {
for (int idx = minCol; idx <= maxCol; idx++) {
if (board[row_idx][idx] && !(row_idx == i && idx == j)) { // assumes board is implemented with booleans
count++
}
}
}While this is longer, this doesn't abuse exceptions for something totally non-exceptional.
-
The
printBoard is fine, except for my first two criticisms. The if/else can be condensed to a ternary; I'd find this easier to read:for (boolean row[] : board) {
for (boolean cell : row) {
System.out.print( cell ? "#" : "." );
}
System.out.println();
}-
In
main, you initialize nextBoard with the initial board, then copy it over into board. This is slightly useless. I'd propose to refactor your main into a method boolean[][] nextGeneration(boolean[][] board). Your main would then look likeint[][] initialBoard = ...;
public static void main(String[] args) {
int[][] board = new int[nextBoard.length][nextBoard[0].length];
// copy over the initial board
for (int i = 0; i < initialBoard.length; i++) {
for (int j = 0; j < initalBoard[i].length; j++) {
board[i][j] = initialBoard[i][j];
}
}
// loop over 25 generations
printBoard(board);
for (int gen = 0; gen < 25; gen++) {
System.out.println("\nGeneration " + gen);
board = nextGeneration(board);
printBoard(board);
}
}-
Now something is becoming obvious: We have collected a few static methods that operate on our
board array. This is a sign that we should create a seperate class:Board
========
- board: boolean[][]
--------
- countSurrounding(i: int, j: int): int
+ toString(): String
+ nextGeneration(): BoardThe class could be easily extended to have a static default board, or a constructor that creates a random board.
-
Each “Game of Life” can be described by a ruleset like
23/3. The digits before the slash determine when a living cell stays alive, the digits after the slash determine when a new cell is born. Generalizing nextGeneration to be able to play with all possible rules is a nice exercise.private boolean nextCellState(int i, int j) {
int count = countSurrounding(i, j);
int rules[] = board[i][j] ? stayAlive : birthNew;
for (int rule : rules) {
if (rule == count) {
return true;
}
}
return false;
}then
public Board nextGeneration() {
boolean next[][] = new boolean[board.length][board[0].length];
int rows = board.length;
int cols = board.[0].length;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
next[i][j] = nextCellState(i, j);
}
}
return new Board(next);
}Code Snippets
int minRow = i == 0 ? 0 : i - 1;
int maxRow = i == (row.length - 1) ? (row.length - 1) : i + 1;int minCol = j == 0 ? 0 : j - 1;
int maxCol = j == (column.length - 1) ? (column.length - 1) : j + 1;for (int row_idx = minRow; row_idx <= maxRow; row_idx++) {
for (int idx = minCol; idx <= maxCol; idx++) {
if (board[row_idx][idx] && !(row_idx == i && idx == j)) { // assumes board is implemented with booleans
count++
}
}
}for (boolean row[] : board) {
for (boolean cell : row) {
System.out.print( cell ? "#" : "." );
}
System.out.println();
}int[][] initialBoard = ...;
public static void main(String[] args) {
int[][] board = new int[nextBoard.length][nextBoard[0].length];
// copy over the initial board
for (int i = 0; i < initialBoard.length; i++) {
for (int j = 0; j < initalBoard[i].length; j++) {
board[i][j] = initialBoard[i][j];
}
}
// loop over 25 generations
printBoard(board);
for (int gen = 0; gen < 25; gen++) {
System.out.println("\nGeneration " + gen);
board = nextGeneration(board);
printBoard(board);
}
}Context
StackExchange Code Review Q#26033, answer score: 14
Revisions (0)
No revisions yet.