Select Git revision
FirefighterBoardTest.java
Forked from
COUETOUX Basile / FirefighterStarter
Source project has a limited visibility.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Grid.java 6.83 KiB
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[this.getNumberOfRows()][this.getNumberOfColumns()];
for(int i = 0; i < this.getNumberOfRows(); i++){
for(int j = 0; j < this.getNumberOfColumns(); j++){
nextState[i][j] = calculateNextState(i,j,this.getCell(i,j));
}
}
return nextState;
}
private char getAverageNeighboursColor(int rowIndex,int columnIndex)
{
int redCount=0;
int blueCount=0;
List<Cell> neighbours = this.getNeighbours(rowIndex,columnIndex);
for(Cell currentCell : neighbours)
{
if(currentCell.isAlive())
{
if(currentCell.getColor()=='R'){redCount++;}
else{blueCount++;}
}
}
if(blueCount>redCount)
{
return 'B';
}
return 'R';
}
private boolean calculateNextState(int rowIndex, int columnIndex, Cell cell) {
int neighbours = this.countAliveNeighbours(rowIndex,columnIndex);
if(cell.isAlive()){
if(neighbours == 2 || neighbours == 3){
return true;
}
}
else{
if(neighbours == 3){
cell.setColor(this.getAverageNeighboursColor(rowIndex,columnIndex));
return true;
}
}
return false;
}
private int countAliveNeighbours(int rowIndex, int columnIndex) {
int count = 0;
List<Cell> Neighbours = this.getNeighbours(rowIndex, columnIndex);
for(Cell cell : Neighbours){
if(cell.isAlive()){
count++;
}
}
return count;
}
private List<Cell> getNeighbours(int rowIndex, int columnIndex) {
List<Cell> Neighbours= new ArrayList<Cell>();
for(int i = rowIndex -1; i <= rowIndex + 1; i++) {
for (int j = columnIndex-1; j <= columnIndex + 1; j++) {
if(i != rowIndex || j != columnIndex){
Neighbours.add(this.getCell(i,j));
}
}
}
return Neighbours;
}
private void goToNextState(boolean[][] nextState) {
for(int i = 0; i < this.getNumberOfRows(); i++){
for(int j = 0; j < this.getNumberOfColumns(); j++){
if(nextState[i][j]){
this.getCell(i,j).setAlive();
}
else{
this.getCell(i,j).setDead();
}
}
}
}
/**
* Sets all {@link Cell}s in this {@code Grid} as dead.
*/
void clear() {
for(int i = 0; i < this.getNumberOfRows(); i++){
for(int j = 0; j < this.getNumberOfColumns(); j++){
this.getCell(i,j).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) {
for(int i = 0; i < this.getNumberOfRows(); i++){
for(int j = 0; j < this.getNumberOfColumns(); j++){
if(random.nextBoolean()){
if(random.nextBoolean()){
this.getCell(i,j).setColor('r');
}
else{
this.getCell(i,j).setColor('b');
}
this.getCell(i,j).setAlive();
}
else{
this.getCell(i,j).setDead();
}
}
}
}
}