import java.util.*; /** * {@code Grid} instances represent the grid in <i>The Game of Life</i>. */ public class Grid implements Iterable<Cell> { private final int numberOfRows; private final int numberOfColumns; private final Cell[][] cells; /** * Creates a new {@code Grid} instance given the number of rows and columns. * * @param numberOfRows the number of rows * @param numberOfColumns the number of columns * @throws IllegalArgumentException if {@code numberOfRows} or {@code numberOfColumns} are * less than or equal to 0 */ public Grid(int numberOfRows, int numberOfColumns) { this.numberOfRows = numberOfRows; this.numberOfColumns = numberOfColumns; this.cells = createCells(); } @Override public Iterator<Cell> iterator() { return new GridIterator(this); } private Cell[][] createCells() { Cell[][] cells = new Cell[getNumberOfRows()][getNumberOfColumns()]; for (int rowIndex = 0; rowIndex < getNumberOfRows(); rowIndex++) { for (int columnIndex = 0; columnIndex < getNumberOfColumns(); columnIndex++) { cells[rowIndex][columnIndex] = new Cell(); } } return cells; } /** * Returns the {@link Cell} at the given index. * * <p>Note that the index is wrapped around so that a {@link Cell} is always returned. * * @param rowIndex the row index of the {@link Cell} * @param columnIndex the column index of the {@link Cell} * @return the {@link Cell} at the given row and column index */ public Cell getCell(int rowIndex, int columnIndex) { return cells[getWrappedRowIndex(rowIndex)][getWrappedColumnIndex(columnIndex)]; } private int getWrappedRowIndex(int rowIndex) { return (rowIndex + getNumberOfRows()) % getNumberOfRows(); } private int getWrappedColumnIndex(int columnIndex) { return (columnIndex + getNumberOfColumns()) % getNumberOfColumns(); } /** * Returns the number of rows in this {@code Grid}. * * @return the number of rows in this {@code Grid} */ public int getNumberOfRows() { return numberOfRows; } /** * Returns the number of columns in this {@code Grid}. * * @return the number of columns in this {@code Grid} */ public int getNumberOfColumns() { return numberOfColumns; } /** * Transitions all {@link Cell}s in this {@code Grid} to the next generation. * * <p>The following rules are applied: * <ul> * <li>Any live {@link Cell} with fewer than two live neighbours dies, i.e. underpopulation.</li> * <li>Any live {@link Cell} with two or three live neighbours lives on to the next generation.</li> * <li>Any live {@link Cell} with more than three live neighbours dies, i.e. overpopulation.</li> * <li>Any dead {@link Cell} with exactly three live neighbours becomes a live cell, i.e. reproduction.</li> * </ul> */ void nextGeneration() { goToNextState(calculateNextStates()); } private boolean[][] calculateNextStates() { boolean [][] nextState = new boolean[getNumberOfRows()][getNumberOfColumns()]; for(int rowIndex=0; rowIndex<getNumberOfRows(); rowIndex++){ for (int columnIndex = 0; columnIndex < getNumberOfColumns(); columnIndex++) { nextState[rowIndex][columnIndex] = calculateNextState(rowIndex,columnIndex); } } return nextState; } private boolean calculateNextState(int rowIndex, int columnIndex) { Cell cell = getCell(rowIndex, columnIndex); int numberOfAliveNeighbours = countAliveNeighbours(rowIndex, columnIndex); return cell.isAliveInNextState(numberOfAliveNeighbours); } private int countAliveNeighbours(int rowIndex, int columnIndex) { List<Cell> neighboursList = getNeighbours(rowIndex, columnIndex); Iterator<Cell> iterator = neighboursList.iterator(); int counter = 0; while(iterator.hasNext()) { if(iterator.next().isAlive()) counter++; } return counter; } private boolean aliveNeighboursMajColor(int rowIndex, int columnIndex){ List<Cell> neighboursList = getNeighbours(rowIndex, columnIndex); int count = countAliveNeighbours(rowIndex, columnIndex); Iterator<Cell> iterator = neighboursList.iterator(); int redCount = 0; while(iterator.hasNext()) { Cell cell = iterator.next(); if (cell.isAlive() && cell.isRed()) redCount++; } return (redCount>(count/2)); } private List<Cell> getNeighbours(int rowIndex, int columnIndex) { List<Cell> neighboursList = new ArrayList<Cell>(); neighboursList.add(getCell(rowIndex, columnIndex+1)); neighboursList.add(getCell(rowIndex, columnIndex-1)); neighboursList.add(getCell(rowIndex+1, columnIndex)); neighboursList.add(getCell(rowIndex-1, columnIndex)); neighboursList.add(getCell(rowIndex+1, columnIndex+1)); neighboursList.add(getCell(rowIndex+1, columnIndex-1)); neighboursList.add(getCell(rowIndex-1, columnIndex+1)); neighboursList.add(getCell(rowIndex-1, columnIndex-1)); return neighboursList; } private void goToNextState(boolean[][] nextState) { for(int rowIndex=0; rowIndex<this.numberOfRows; rowIndex++) { for (int columnIndex = 0; columnIndex < this.numberOfColumns; columnIndex++) { Cell cell = getCell(rowIndex, columnIndex); if (nextState[rowIndex][columnIndex]) { if(cell.isDead()) { boolean redColor = aliveNeighboursMajColor(rowIndex, columnIndex); cell.setisRed(redColor); } cell.setAlive(); }else{ cell.setDead(); } } } } /** * Sets all {@link Cell}s in this {@code Grid} as dead. */ void clear() { for (Iterator<Cell> gridIt = iterator(); gridIt.hasNext(); ) { Cell cell = gridIt.next(); cell.setDead(); } } /** * Goes through each {@link Cell} in this {@code Grid} and randomly sets it as alive or dead. * * @param random {@link Random} instance used to decide if each {@link Cell} is alive or dead * @throws NullPointerException if {@code random} is {@code null} */ void randomGeneration(Random random) { Iterator<Cell> gridIt = iterator(); while (gridIt.hasNext()) { Cell cell = gridIt.next(); boolean randomStat = random.nextBoolean(); if (randomStat) { cell.setAlive(); randomStat = random.nextBoolean(); if (randomStat) cell.setisRed(true); else cell.setisRed(false); }else { cell.setDead(); } } // Spaceships Test /* Cell cell0 = getCell(1,1); Cell cell1 = getCell(2,2); Cell cell2 = getCell(1,3); Cell cell3 = getCell(2,3); Cell cell4 = getCell(3,2); cell0.setAlive();cell1.setAlive();cell2.setAlive();cell3.setAlive();cell4.setAlive(); */ } }