Skip to content
Snippets Groups Projects
Grid.java 7.37 KiB
Newer Older
  • Learn to ignore specific revisions
  • AZZOUG Lydia's avatar
    AZZOUG Lydia committed
    import java.util.*;
    
    Alexis Nasr's avatar
    Alexis Nasr committed
    
    /**
     * {@code Grid} instances represent the grid in <i>The Game of Life</i>.
     */
    
    Alexis Nasr's avatar
    Alexis Nasr committed
    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>
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
         * <li>Any live {@link Cell} with two or three live neighbours lives on to the next generation.</li>
    
    Alexis Nasr's avatar
    Alexis Nasr committed
         * <li>Any live {@link Cell} with more than three live neighbours dies, i.e. overpopulation.</li>
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
         * <li>Any dead {@link Cell} with exactly three live neighbours becomes a live cell, i.e. reproduction.</li>
    
    Alexis Nasr's avatar
    Alexis Nasr committed
         * </ul>
         */
        void nextGeneration() {
            goToNextState(calculateNextStates());
        }
    
        private boolean[][] calculateNextStates() {
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
            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;
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
        private boolean calculateNextState(int rowIndex, int columnIndex) {
            Cell cell = getCell(rowIndex, columnIndex);
            int numberOfAliveNeighbours = countAliveNeighbours(rowIndex, columnIndex);
            return cell.isAliveInNextState(numberOfAliveNeighbours);
    
    Alexis Nasr's avatar
    Alexis Nasr committed
        }
    
        private int countAliveNeighbours(int rowIndex, int columnIndex) {
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
            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));
    
    Alexis Nasr's avatar
    Alexis Nasr committed
        }
    
        private List<Cell> getNeighbours(int rowIndex, int columnIndex) {
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
            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;
    
    Alexis Nasr's avatar
    Alexis Nasr committed
        }
    
        private void goToNextState(boolean[][] nextState) {
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
            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();
                    }
                }
            }
    
    Alexis Nasr's avatar
    Alexis Nasr committed
        }
    
        /**
         * Sets all {@link Cell}s in this {@code Grid} as dead.
         */
        void clear() {
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
            for (Iterator<Cell> gridIt = iterator(); gridIt.hasNext(); ) {
                Cell cell = gridIt.next();
                cell.setDead();
            }
    
    Alexis Nasr's avatar
    Alexis Nasr committed
        }
    
        /**
         * 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}
         */
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
    
    
    Alexis Nasr's avatar
    Alexis Nasr committed
        void randomGeneration(Random random) {
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
            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();
            */
    
    
    AZZOUG Lydia's avatar
    AZZOUG Lydia committed
    }