diff --git a/src/main/java/matrix/ListMatrix.java b/src/main/java/matrix/ListMatrix.java index 27fbd83090d553fe8e9203d3d79e45216dff828d..b929766ad8d8c6776d814be04af22379fc70b7db 100644 --- a/src/main/java/matrix/ListMatrix.java +++ b/src/main/java/matrix/ListMatrix.java @@ -35,7 +35,7 @@ public class ListMatrix<T> implements Matrix<T> { } private void initializeWith(MatrixInitializer<T> initializer) { - for (int x=0; x<width; x++) { + for (int x = 0; x < width; x++) { List<T> column = new ArrayList<>(height); for (int y = 0; y < height; y++) { @@ -43,7 +43,6 @@ public class ListMatrix<T> implements Matrix<T> { } matrix.add(column); } - } diff --git a/src/main/java/model/Cell.java b/src/main/java/model/Cell.java index 1c280949903623fddde7252f82639317f9dfb50a..d768bc4ad8c2a4ee4d06dfe43294cc9464d38a3d 100644 --- a/src/main/java/model/Cell.java +++ b/src/main/java/model/Cell.java @@ -1,8 +1,5 @@ package model; -import model.automata.GameOfLifeAutomaton; -import model.automata.GameOfLifeState; - import java.util.ArrayList; import java.util.List; @@ -14,16 +11,17 @@ import java.util.List; */ public class Cell<T> implements Lens<T> { + private T content; + // la liste des objets écoutant les modifications du contenu de la cellule private final List<OnChangeListener<T>> listeners = new ArrayList<>(); - private T initialContent; /** Initialize a new cell with a given value. * * @param initialContent the value initially stored by the cell. */ public Cell(T initialContent) { - this.initialContent = initialContent; + this.content = initialContent; } /** Add a {@link OnChangeListener} to react to any change of value in the cell. @@ -42,12 +40,12 @@ public class Cell<T> implements Lens<T> { * @param value the new content of this {@link Cell} */ public void set(T value) { - T oldValue = initialContent; - initialContent = value; + T oldValue = this.content; + this.content = value; - for (OnChangeListener<T> L : listeners) { - L.valueChanged(oldValue, value); - } + for (OnChangeListener<T> listener : listeners) { + listener.valueChanged(oldValue, value); + } } /** @@ -56,6 +54,8 @@ public class Cell<T> implements Lens<T> { * @return the current content of this {@link Cell} */ public T get(){ - return initialContent; + return this.content; } } + + diff --git a/src/main/java/model/CellularAutomatonSimulation.java b/src/main/java/model/CellularAutomatonSimulation.java index 0d72f9c11c977d5b32fa6e19d24a3c4536b41b96..cc968436f955d1c2f7045f67cf55e95062683cbf 100644 --- a/src/main/java/model/CellularAutomatonSimulation.java +++ b/src/main/java/model/CellularAutomatonSimulation.java @@ -4,19 +4,19 @@ import controller.Simulation; import matrix.Coordinate; import matrix.ListMatrix; import javafx.scene.paint.Color; -import model.*; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import java.util.Random; + + /** * {@link CellularAutomatonSimulation} instances run <i>The Game of Life</i>. * - * @param <S> The type of state used in the simulation. + * @param <S> The type of state used in the simulation. */ -public class CellularAutomatonSimulation<S extends State<S>> implements Simulation { +public class CellularAutomatonSimulation<S extends State<S>> + implements Simulation { private final ListMatrix<Cell<S>> grid; private final Cell<Integer> generationNumber = new Cell<>(0); @@ -39,14 +39,15 @@ public class CellularAutomatonSimulation<S extends State<S>> implements Simulati this.generator = generator; } + @Override public int numberOfColumns() { - return this.grid.width(); + return automaton.numberOfColumns(); } @Override public int numberOfRows() { - return this.grid.height(); + return automaton.numberOfRows(); } /** @@ -56,86 +57,45 @@ public class CellularAutomatonSimulation<S extends State<S>> implements Simulati * @return The cell at the specified coordinate. */ public Cell<S> at(Coordinate coordinate) { - return this.grid.get(coordinate.x(), coordinate.y()); + return grid.get(coordinate); } @Override public void updateToNextGeneration() { - ListMatrix<Cell<S>> nextMatrix = nextGenerationMatrix(); - for (Coordinate coordinate : this.grid.coordinates()) { - this.grid.get(coordinate.x(), coordinate.y()) - .set(nextMatrix.get(coordinate.x(), coordinate.y()).get()); + ListMatrix<S> nextStates = nextGenerationMatrix(); + for (Coordinate coordinate : grid.coordinates()) { + grid.get(coordinate).set(nextStates.get(coordinate)); } - this.generationNumber.set(this.generationNumber.get() + 1); // Increment generation number + generationNumber.set(generationNumber.get() + 1); } - /** - * Computes the {@link ListMatrix} of states obtained after a single step of updates + /** Computes the {@link ListMatrix} of states obtained after a single step of updates * of the simulation. * * @return the states of each cell after one generation */ - private ListMatrix<Cell<S>> nextGenerationMatrix() { - ListMatrix<Cell<S>> nextGrid = new ListMatrix<>( - this.grid.width(), - this.grid.height(), - new ConstantCellInitializer<>(automaton.defaultState()) // Pass the state directly + private ListMatrix<S> nextGenerationMatrix() { + return new ListMatrix<>( + numberOfColumns(), + numberOfRows(), + new NextGenerationInitializer<>(this) ); - - for (Coordinate coordinate : this.grid.coordinates()) { - S currentState = this.grid.get(coordinate.x(), coordinate.y()).get(); - List<S> neighbors = getNeighbors(coordinate); - S nextState = currentState.update(neighbors); - nextGrid.get(coordinate.x(), coordinate.y()).set(nextState); - } - - return nextGrid; } - - /** - * Calculates the neighbors of a cell at the given coordinate. - * - * @param coordinate The coordinate of the cell. - * @return A list of states representing the neighbors of the cell. - */ - private List<S> getNeighbors(Coordinate coordinate) { - List<S> neighbors = new ArrayList<>(); - for (Coordinate neighbor : coordinate.orthodiagonalNeighbours()) { - if (isValidCoordinate(neighbor)) { - neighbors.add(this.grid.get(neighbor.x(), neighbor.y()).get()); - } - } - return neighbors; - } - - /** - * Validates if the given coordinate is within the bounds of the grid. - * - * @param coordinate The coordinate to validate. - * @return True if the coordinate is valid; false otherwise. - */ - private boolean isValidCoordinate(Coordinate coordinate) { - return coordinate.x() >= 0 && coordinate.x() < this.grid.width() - && coordinate.y() >= 0 && coordinate.y() < this.grid.height(); - } - @Override public void next(Coordinate coordinate) { - Cell<S> cell = this.at(coordinate); - List<S> neighbors = getNeighbors(coordinate); - S nextState = cell.get().update(neighbors); - cell.set(nextState); + Cell<S> cell = at(coordinate); + cell.set(cell.get().next()); } @Override public void copy(Coordinate source, Coordinate destination) { - S sourceState = this.at(source).get(); - this.at(destination).set(sourceState); + Cell<S> sourceCell = at(source); + at(destination).set(sourceCell.get()); } @Override public Color getColor(Coordinate coordinate) { - return this.at(coordinate).get().getColor(); + return at(coordinate).get().getColor(); } @Override @@ -146,28 +106,32 @@ public class CellularAutomatonSimulation<S extends State<S>> implements Simulati } @Override - public void setGenerationNumberChangeListener(OnChangeListener<Integer> listener) { + public void setGenerationNumberChangeListener(OnChangeListener<Integer> listener){ this.generationNumber.addOnChangeListener(listener); } + @Override public void clear() { - for (Coordinate coordinate : this.grid.coordinates()) { - this.at(coordinate).set(this.automaton.defaultState()); + for(Coordinate coordinate : grid.coordinates()) { + at(coordinate).set(automaton.defaultState()); } - this.generationNumber.set(0); // Reset generation counter + generationNumber.set(0); } + @Override public void reset() { - for (Coordinate coordinate : this.grid.coordinates()) { - this.grid.set(coordinate.x(), coordinate.y(), new Cell<>(this.automaton.defaultState())); + for(Coordinate coordinate : grid.coordinates()) { + at(coordinate).set(automaton.randomState(generator)); } - this.generationNumber.set(0); + generationNumber.set(0); } @Override public Iterator<Coordinate> iterator() { return this.grid.coordinates().iterator(); } + + } \ No newline at end of file diff --git a/src/main/java/model/NextGenerationInitializer.java b/src/main/java/model/NextGenerationInitializer.java index 2fc8e80249a7f4de40ef4de4ea89f5d006fd790a..6b4cff82c19d0735da15ca2879b6c64ee11dd220 100644 --- a/src/main/java/model/NextGenerationInitializer.java +++ b/src/main/java/model/NextGenerationInitializer.java @@ -31,14 +31,15 @@ public class NextGenerationInitializer<S extends State<S>> implements MatrixInit @Override public S initialValueAt(Coordinate coordinate) { - List<Coordinate> coordinates = coordinate.orthogonalNeighbours(); - List<S> states = new ArrayList<>(); - for (Coordinate c : coordinates) { - states.add(simulation.at(this.wrap(c)).get()); + List<Coordinate> neighborCoordinates = coordinate.orthodiagonalNeighbours(); + List<S> neighborStates = new ArrayList<>(); + + for (Coordinate neighbor : neighborCoordinates) { + neighborStates.add(simulation.at(this.wrap(neighbor)).get()); } - return simulation.at(coordinate).get().update(states); - } + return simulation.at(coordinate).get().update(neighborStates); + } /** Computes the grid {@link Coordinate} for an arbitrary {@link Coordinate}, even outside * the grid. This is done by considering that the grid wraps over its edges, connecting the left side to the right * side, and the top side to the bottom side. This way, every cell has 4 orthogonal diff --git a/src/main/java/model/automata/GameOfLifeAutomaton.java b/src/main/java/model/automata/GameOfLifeAutomaton.java index c3ed542a844b391b52cc94262d7df3327e8d92c7..0caeca91d02f19303ab704ecb3cd4dce51697fc5 100644 --- a/src/main/java/model/automata/GameOfLifeAutomaton.java +++ b/src/main/java/model/automata/GameOfLifeAutomaton.java @@ -6,8 +6,8 @@ import java.util.Random; public class GameOfLifeAutomaton implements CellularAutomaton<GameOfLifeState> { - private final int numberOfColumns; - private final int numberOfRows; + private final int numberOfColumns; + private final int numberOfRows; public GameOfLifeAutomaton(int numberOfColumns, int numberOfRows) { this.numberOfColumns = numberOfColumns; diff --git a/src/main/java/model/automata/GameOfLifeState.java b/src/main/java/model/automata/GameOfLifeState.java index e47516c152a2e06c7b083dd4028229bd0a103a83..c3931e157461a09987bde873f79648a4ad839a41 100644 --- a/src/main/java/model/automata/GameOfLifeState.java +++ b/src/main/java/model/automata/GameOfLifeState.java @@ -4,6 +4,7 @@ import javafx.scene.paint.Color; import model.State; import java.util.List; +import java.util.Random; /** * {@link GameOfLifeState} instances represent the possible states of a {@link GameOfLifeState}. @@ -11,61 +12,27 @@ import java.util.List; public enum GameOfLifeState implements State<GameOfLifeState> { ALIVE, DEAD; - @Override public Color getColor() { - switch (this) { - case ALIVE: - return Color.RED; - case DEAD: - return Color.WHITE; - default: - return Color.WHITE; - } + return this == ALIVE ? Color.RED : Color.WHITE; } - /* correction avec if : - if this.equals(ALIVE) { - return COLOR.RED; - else { - return COLOR.WHITE; - */ - @Override public GameOfLifeState next() { - switch (this) { - case ALIVE: - return DEAD; - case DEAD: - return ALIVE; - default: - return DEAD; - } + return this == ALIVE ? DEAD : ALIVE; } - /* correction avec if : - if this.equals(ALIVE) { - return DEAD; - else { - return ALIVE; - */ @Override - public GameOfLifeState update(List<GameOfLifeState> neighbours) { - int count = State.count(ALIVE, neighbours); - switch (this) { - case DEAD: - if (count == 3) { - return ALIVE; - } - break; - case ALIVE: - if (count == 3) { - return ALIVE; - } else if (count == 2) { - return ALIVE; - } - break; + public GameOfLifeState update(List<GameOfLifeState> neighbors) { + int aliveCount = State.count(ALIVE, neighbors); + + if (this == ALIVE) { + return (aliveCount == 2 || aliveCount == 3) ? ALIVE : DEAD; + } else { + return (aliveCount == 3) ? ALIVE : DEAD; } - return DEAD; } -} + public GameOfLifeState randomState(Random generator) { + return generator.nextBoolean() ? GameOfLifeState.ALIVE : GameOfLifeState.DEAD; + } +} \ No newline at end of file