diff --git a/tp3/.classpath b/tp3/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..3f3893aff96296c1ce15c61728d13a5d97589bbe --- /dev/null +++ b/tp3/.classpath @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="src" path=""/> + <classpathentry kind="output" path=""/> +</classpath> diff --git a/tp3/.gitignore b/tp3/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..75cba99bdeddbac27389c31cab4ce0f93b40963d --- /dev/null +++ b/tp3/.gitignore @@ -0,0 +1,6 @@ +/Cell.class +/GameOfLife.class +/GameOfLifeGUI.class +/Grid.class +/GridIterator.class +/Main.class diff --git a/tp3/.project b/tp3/.project new file mode 100644 index 0000000000000000000000000000000000000000..ee3c8513423be73bdb1b08473ae9797f0fa6315e --- /dev/null +++ b/tp3/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>tp3</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/tp3/Cell.java b/tp3/Cell.java new file mode 100755 index 0000000000000000000000000000000000000000..d43fa01f7a70b75704a8f8de64a191d36008f995 --- /dev/null +++ b/tp3/Cell.java @@ -0,0 +1,112 @@ +import java.awt.Color; + +/** + * {@link Cell} instances represent the cells of <i>The Game of Life</i>. + */ + +public class Cell { + private boolean isAlive; + private Color color; + + public Cell(){ + this.isAlive = false; + this.color = Color.white; + } + + /** + * Determines whether this {@link Cell} is alive or not. + * + * @return {@code true} if this {@link Cell} is alive and {@code false} otherwise + */ + + public boolean isAlive() { + return this.isAlive; + } + + /** + * Determines whether this {@link Cell} is dead or not. + * + * @return {@code true} if this {@link Cell} is dead and {@code false} otherwise + */ + + public boolean isDead() { + return !this.isAlive; + } + + /** + * Sets the state of this {@link Cell} to alive. + * + * @param cellState the new state of this {@link Cell} + */ + + public void setAlive() { + this.isAlive = true; + } + + /** + * Sets the state of this {@link Cell} to dead. + * + * @param cellState the new state of this {@link Cell} + */ + + public void setDead() { + this.isAlive = false; + } + + + /** + * Change the state of this {@link Cell} from ALIVE to DEAD or from DEAD to ALIVE. + */ + + public void toggleState() { + if(this.isAlive) + this.isAlive = false; + else + this.isAlive = true; + } + + public boolean isAliveInNextState(int numberOfAliveNeighbours) { + if(isAlive()){ + if (numberOfAliveNeighbours == 2 || numberOfAliveNeighbours == 3) + return true; + else + return false; + } + else{ + if (numberOfAliveNeighbours == 3) + return true; + else + return false; + } + } + + + + public void setRed() { + color = Color.red; + } + + public void setBlue() { + color = Color.blue; + } + + + public boolean isRed() { + return color == Color.red; + } + public boolean isBlue() { + return color == Color.blue; + } + + +} + + + + + + + + + + diff --git a/tp3/GameOfLife.java b/tp3/GameOfLife.java new file mode 100755 index 0000000000000000000000000000000000000000..1d5bb85f326f29587b01ae16657bada3ef23b191 --- /dev/null +++ b/tp3/GameOfLife.java @@ -0,0 +1,87 @@ +import java.util.Random; + +/** + * {@link GameOfLife} instances run <i>The Game of Life</i>. + */ +public class GameOfLife { + + private final Random random = new Random(); + private final Grid grid; + private int generationNumber; + + /** + * Creates a new {@code GameOfLife} instance given the underlying {@link Grid}. + * + * @param grid the underlying {@link Grid} + * @throws NullPointerException if {@code grid} is {@code null} + */ + public GameOfLife(Grid grid) { + // this.grid = requireNonNull(grid, "grid is null"); + this.grid = grid; + grid.randomGeneration(random); + } + + /** + * Transitions into the next generationNumber. + */ + public void next() { + grid.nextGeneration(); + generationNumber++; + } + + + /** + * Returns the current generationNumber. + * + * @return the current generationNumber + */ + private int getGenerationNumber() { + return generationNumber; + } + + /** + * Returns the {@link Grid}. + * + * @return the {@link Grid} + */ + public Grid getGrid() { + return grid; + } + + /** + * Plays the game. + */ + public void play(int maxGenerations) { + for(int generation =0; generation < maxGenerations; generation++){ + this.next(); + System.out.println("generation : " + generation); + } + + + } + + /** + * Pauses the game. + */ + public void pause() { + // timeline.pause(); + } + + /** + * Clears the current game. + */ + public void clear() { + pause(); + grid.clear(); + generationNumber = 0; + } + + /** + * Clears the current game and randomly generates a new one. + */ + public void reset() { + clear(); + grid.randomGeneration(random); + } + +} diff --git a/tp3/GameOfLifeGUI.java b/tp3/GameOfLifeGUI.java new file mode 100755 index 0000000000000000000000000000000000000000..2f9d39d52ab3e074ff50ae9804448bc0a5526933 --- /dev/null +++ b/tp3/GameOfLifeGUI.java @@ -0,0 +1,52 @@ +import java.awt.*; +import java.awt.Graphics; +import javax.swing.*; + +public class GameOfLifeGUI extends JFrame { + private int squareSize = 7; + private int numberOfRows; + private int numberOfColumns; + private JLabel[][] labelGrid; + private GridLayout gridLayout; + private JPanel gridPanel; + private JFrame frame; + + public GameOfLifeGUI(Grid g) { + this.numberOfRows = g.getNumberOfRows(); + this.numberOfColumns = g.getNumberOfColumns(); + gridLayout = new GridLayout(numberOfRows, numberOfColumns); + gridPanel = new JPanel(gridLayout); + labelGrid = new JLabel[numberOfRows][numberOfColumns]; + for (int x = 0; x < numberOfColumns; x++) + for (int y = 0; y < numberOfRows; y++){ + labelGrid[x][y] = new JLabel("*"); + JLabel label; + if(g.getCell(x,y).isAlive()&& (g.getCell(x,y).isRed())) + labelGrid[x][y].setForeground(Color.red); + if(g.getCell(x,y).isAlive()&& (g.getCell(x,y).isBlue())) + labelGrid[x][y].setForeground(Color.blue); + else if (g.getCell(x, y).isDead()) + labelGrid[x][y].setForeground(Color.white); + gridPanel.add(labelGrid[x][y]); + } + frame = new JFrame("Game of Life"); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setContentPane(gridPanel); + frame.setSize(squareSize * numberOfRows, squareSize * numberOfColumns); + frame.setLocationByPlatform(true); + frame.setVisible(true); + } + + public void update(Grid g){ + for (int x = 0; x < numberOfColumns; x++) + for (int y = 0; y < numberOfRows; y++){ + JLabel label = labelGrid[x][y]; + if(g.getCell(x,y).isAlive() && (g.getCell(x,y).isRed())) + label.setForeground(Color.red); + if(g.getCell(x,y).isAlive() && (g.getCell(x,y).isBlue())) + label.setForeground(Color.blue); + else if (g.getCell(x,y).isDead()) + label.setForeground(Color.white); + } + } +} diff --git a/tp3/Grid.java b/tp3/Grid.java new file mode 100755 index 0000000000000000000000000000000000000000..136c6b0125b9ef4a8feee9ae980625ac3faa07d4 --- /dev/null +++ b/tp3/Grid.java @@ -0,0 +1,226 @@ +import java.awt.Color; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Random; + +/** + * {@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[][] nextStates = new boolean[getNumberOfRows()][getNumberOfColumns()]; + for (int rowIndex = 0; rowIndex < getNumberOfRows(); rowIndex++) { + for (int columnIndex = 0; columnIndex < getNumberOfColumns(); columnIndex++) { + nextStates[rowIndex][columnIndex] = calculateNextState(rowIndex, columnIndex, cells[rowIndex][columnIndex]); + } + } + return nextStates; + + } + + private boolean calculateNextState(int rowIndex, int columnIndex, Cell cell) { + int aliveNeighbours = countAliveNeighbours(rowIndex, columnIndex); + if (cell.isDead() && aliveNeighbours == 3) { + return true; + } + if (cell.isAlive() && ( aliveNeighbours == 2 || aliveNeighbours == 3) ) { + return true; + } + return false; + } + + private int countAliveNeighbours(int rowIndex, int columnIndex) { + List<Cell>list = getNeighbours(rowIndex, columnIndex); + int count = 0; + for (Cell Cell : list) { + if (Cell.isAlive()) { + count++; + } + } + return count; + } + + + private List<Cell> getNeighbours(int rowIndex, int columnIndex) { + List<Cell> neighbours = new ArrayList<Cell>(); + neighbours.add(getCell(rowIndex - 1, columnIndex - 1));//1 up left + neighbours.add(getCell(rowIndex - 1, columnIndex));//2 up + neighbours.add(getCell(rowIndex - 1, columnIndex +1));//3 up right + neighbours.add(getCell(rowIndex, columnIndex + 1));//4 right + neighbours.add(getCell(rowIndex + 1, columnIndex + 1));//5 down right + neighbours.add(getCell(rowIndex + 1, columnIndex));//6 down + neighbours.add(getCell(rowIndex + 1, columnIndex - 1));//7 down left + neighbours.add(getCell(rowIndex, columnIndex - 1));//8 left + return neighbours; + } + + private void goToNextState(boolean[][] nextState) { + + for (int rowIndex = 0; rowIndex < getNumberOfRows(); rowIndex++) { + for (int columnIndex = 0; columnIndex < getNumberOfColumns(); columnIndex++) { + if (nextState[rowIndex][columnIndex] == true) { + cells[rowIndex][columnIndex].setAlive(); + + if ( neighboursColor(rowIndex, columnIndex) ) { + cells[rowIndex][columnIndex].setRed(); + } + else + cells[rowIndex][columnIndex].setBlue(); + + } + else + cells[rowIndex][columnIndex].setDead(); + + + + + } + + } + } + + public boolean neighboursColor(int rowIndex, int columnIndex) { + List<Cell>color = getNeighbours(rowIndex, columnIndex); + int blue = 0; + int red = 0; + for (Cell Cell : color) { + if (Cell.isRed()) { + red++; + } + if (Cell.isBlue()){ + blue++; + } + } + + return red>blue; + } + + /** + * Sets all {@link Cell}s in this {@code Grid} as dead. + */ + void clear() { + for (int rowIndex = 0; rowIndex < getNumberOfRows(); rowIndex++) { + for (int columnIndex = 0; columnIndex < getNumberOfColumns(); columnIndex++) { + cells[rowIndex][columnIndex].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 rowIndex = 0; rowIndex < getNumberOfRows(); rowIndex++) { + for (int columnIndex = 0; columnIndex < getNumberOfColumns(); columnIndex++) { + + if (random.nextBoolean()) { + cells[rowIndex][columnIndex].setAlive(); + if (random.nextBoolean()) { + cells[rowIndex][columnIndex].setBlue(); + } + else + cells[rowIndex][columnIndex].setRed(); + } + else + cells[rowIndex][columnIndex].setDead(); + } + + } + } +} diff --git a/tp3/GridIterator.java b/tp3/GridIterator.java new file mode 100755 index 0000000000000000000000000000000000000000..19fc9e0f9169cd236e9195989a90ecdf71e3a91c --- /dev/null +++ b/tp3/GridIterator.java @@ -0,0 +1,31 @@ +import java.util.Iterator; + +/** + * {@link GridIterator} instances are used to iterate over the cells of a grid. + */ +public class GridIterator implements Iterator<Cell> { + private int rowIndex; + private int columnIndex; + private Grid grid; + + GridIterator(Grid grid) { + this.rowIndex = 0; + this.columnIndex = 0; + this.grid = grid; + } + + @Override + public boolean hasNext() { + return columnIndex < grid.getNumberOfColumns() && rowIndex < grid.getNumberOfRows(); + } + + @Override + public Cell next() { + final Cell result = grid.getCell(rowIndex, columnIndex); + columnIndex = (columnIndex +1) % grid.getNumberOfColumns(); + if(columnIndex == 0){ + rowIndex++; + } + return result; + } +} diff --git a/tp3/Main.java b/tp3/Main.java new file mode 100755 index 0000000000000000000000000000000000000000..bf344eedcdd0bf23ac4a256c6e08c5b4037f5117 --- /dev/null +++ b/tp3/Main.java @@ -0,0 +1,25 @@ +import java.io.*; +import java.awt.*; +import javax.swing.*; + +public class Main{ + public static void main(String args[]) throws IOException { + int NUMBER_OF_ROWS = 64; + int NUMBER_OF_COLUMNS = 64; + + GameOfLife gameOfLife = new GameOfLife(new Grid(NUMBER_OF_ROWS, NUMBER_OF_COLUMNS)); + + GameOfLifeGUI gui = new GameOfLifeGUI(gameOfLife.getGrid()); + + for(int generation =0; generation < 1000; generation++){ + try { + Thread.sleep(100); + } catch (InterruptedException ie) { + + } + gameOfLife.next(); + gui.update(gameOfLife.getGrid()); + } + + } +}