From a152b729204d4f0f7f9b058bdcd82d32e255c2aa Mon Sep 17 00:00:00 2001
From: Guyslain <guyslain.naves@lis-lab.fr>
Date: Mon, 9 Oct 2023 15:14:25 +0200
Subject: [PATCH] More refactoring, several simulations added

---
 build.gradle                                  |  2 +-
 ...ication.java => SimulatorApplication.java} | 42 ++++++-------
 src/main/java/controller/Controller.java      |  6 +-
 src/main/java/datastruct/Matrix.java          |  2 +-
 src/main/java/model/CellGrid.java             |  2 +-
 ....java => CellularAutomatonSimulation.java} | 44 ++++++-------
 ...er.java => NextGenerationInitializer.java} |  4 +-
 src/main/java/model/states/BiColorState.java  | 61 +++++++++++++++++++
 .../java/model/states/BriansBrainState.java   | 57 +++++++++++++++++
 .../model/{ => states}/GameOfLifeState.java   |  3 +-
 src/main/java/model/states/SeedsState.java    | 40 ++++++++++++
 11 files changed, 210 insertions(+), 53 deletions(-)
 rename src/main/java/{GameOfLifeApplication.java => SimulatorApplication.java} (56%)
 rename src/main/java/model/{CellularAutomataSimulation.java => CellularAutomatonSimulation.java} (62%)
 rename src/main/java/model/{OneStepMatrixInitializer.java => NextGenerationInitializer.java} (80%)
 create mode 100644 src/main/java/model/states/BiColorState.java
 create mode 100644 src/main/java/model/states/BriansBrainState.java
 rename src/main/java/model/{ => states}/GameOfLifeState.java (96%)
 create mode 100644 src/main/java/model/states/SeedsState.java

diff --git a/build.gradle b/build.gradle
index a8007cc..280df72 100644
--- a/build.gradle
+++ b/build.gradle
@@ -23,5 +23,5 @@ test {
 }
 
 application {
-    mainClassName = "GameOfLifeApplication"
+    mainClassName = "SimulatorApplication"
 }
\ No newline at end of file
diff --git a/src/main/java/GameOfLifeApplication.java b/src/main/java/SimulatorApplication.java
similarity index 56%
rename from src/main/java/GameOfLifeApplication.java
rename to src/main/java/SimulatorApplication.java
index 0d8e7c6..fb22b7f 100644
--- a/src/main/java/GameOfLifeApplication.java
+++ b/src/main/java/SimulatorApplication.java
@@ -5,12 +5,13 @@ import javafx.fxml.FXMLLoader;
 import javafx.scene.Parent;
 import javafx.scene.Scene;
 import javafx.stage.Stage;
-import model.CellGrid;
-import model.CellularAutomataSimulation;
-import model.GameOfLifeState;
+import model.CellularAutomatonSimulation;
+import model.states.BriansBrainState;
+import model.states.SeedsState;
 
 import java.io.IOException;
 import java.net.URL;
+import java.util.Random;
 
 import static java.util.Objects.requireNonNull;
 
@@ -18,38 +19,33 @@ import static java.util.Objects.requireNonNull;
  * Entry point for <i>The Game of Life</i> application.
  *
  */
-public class GameOfLifeApplication extends Application {
+public class SimulatorApplication extends Application {
 
-  private static final int NUMBER_OF_ROWS = 40;
-  private static final int NUMBER_OF_COLUMNS = 70;
+  public static final int NUMBER_OF_ROWS = 40;
+  public static final int NUMBER_OF_COLUMNS = 70;
+
+  public static final Random GENERATOR = new Random();
 
   private static final String APP_NAME = "Game of Life";
   private static final String VIEW_RESOURCE_PATH = "/view/view.fxml";
 
-  private final CellularAutomataSimulation<GameOfLifeState> gameOfLife;
+  private final CellularAutomatonSimulation<SeedsState> gameOfLife;
   private Stage primaryStage;
   private Parent view;
 
   /**
    * Creates a new {@code GameOfLifeApplication} instance.
    */
-  public GameOfLifeApplication() {
-    this(new CellularAutomataSimulation<GameOfLifeState>(
-            new CellGrid<>(NUMBER_OF_COLUMNS, NUMBER_OF_ROWS, GameOfLifeState.ALIVE),
-            GameOfLifeState.DEAD,
-            GameOfLifeState::random
-    ));
+  public SimulatorApplication() {
+    this.gameOfLife =
+      new CellularAutomatonSimulation<>(
+              NUMBER_OF_COLUMNS,
+              NUMBER_OF_ROWS,
+              SeedsState.OFF,
+              SeedsState::random
+      );
   }
 
-  /**
-   * Creates a new {@code GameOfLifeApplication} instance given a {@link CellularAutomataSimulation} instance.
-   *
-   * @param cellularAutomataSimulation the {@link CellularAutomataSimulation} instance
-   * @throws NullPointerException if {@code gameOfLife} is {@code null}
-   */
-  private GameOfLifeApplication(CellularAutomataSimulation<GameOfLifeState> cellularAutomataSimulation) {
-    this.gameOfLife = requireNonNull(cellularAutomataSimulation, "game of life is null");
-  }
 
   @Override
   public void start(Stage primaryStage) throws IOException {
@@ -68,7 +64,7 @@ public class GameOfLifeApplication extends Application {
 
   private void initializeView() throws IOException {
     FXMLLoader loader = new FXMLLoader();
-    URL location = GameOfLifeApplication.class.getResource(VIEW_RESOURCE_PATH);
+    URL location = SimulatorApplication.class.getResource(VIEW_RESOURCE_PATH);
     loader.setLocation(location);
     view = loader.load();
     Controller controller = loader.getController();
diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java
index fcfd14f..84e73a3 100644
--- a/src/main/java/controller/Controller.java
+++ b/src/main/java/controller/Controller.java
@@ -11,7 +11,7 @@ import javafx.scene.control.Label;
 import javafx.scene.control.ToggleButton;
 import javafx.scene.control.ToggleGroup;
 import javafx.util.Duration;
-import model.CellularAutomataSimulation;
+import model.CellularAutomatonSimulation;
 import view.MatrixPane;
 
 import static java.util.Objects.requireNonNull;
@@ -52,9 +52,9 @@ public class Controller {
 
 
     /**
-     * Sets {@link CellularAutomataSimulation} instance.
+     * Sets {@link CellularAutomatonSimulation} instance.
      *
-     * @param simulation {@link CellularAutomataSimulation} instance
+     * @param simulation {@link CellularAutomatonSimulation} instance
      * @throws NullPointerException if {@code gameOfLife} is {@code null}
      */
 
diff --git a/src/main/java/datastruct/Matrix.java b/src/main/java/datastruct/Matrix.java
index 645efaf..dbe33a0 100644
--- a/src/main/java/datastruct/Matrix.java
+++ b/src/main/java/datastruct/Matrix.java
@@ -50,7 +50,7 @@ public class Matrix<T> {
 
     public Iterator<T> iterator() {
         Iterator<Coordinate> coordIterator = this.coordinatesIterator();
-        return new MatrixIterator(this, coordIterator);
+        return new MatrixIterator<>(this, coordIterator);
     }
 
     public Iterable<Coordinate> coordinates() {
diff --git a/src/main/java/model/CellGrid.java b/src/main/java/model/CellGrid.java
index 87dd605..5df1fb5 100644
--- a/src/main/java/model/CellGrid.java
+++ b/src/main/java/model/CellGrid.java
@@ -107,7 +107,7 @@ public class CellGrid<S extends State<S>> implements Iterable<Cell<S>> {
         return new Matrix<>(
                 this.numberOfColumns,
                 this.numberOfRows,
-                new OneStepMatrixInitializer<>(this)
+                new NextGenerationInitializer<>(this)
         );
     }
 
diff --git a/src/main/java/model/CellularAutomataSimulation.java b/src/main/java/model/CellularAutomatonSimulation.java
similarity index 62%
rename from src/main/java/model/CellularAutomataSimulation.java
rename to src/main/java/model/CellularAutomatonSimulation.java
index 1dd0fb7..8bd51b3 100644
--- a/src/main/java/model/CellularAutomataSimulation.java
+++ b/src/main/java/model/CellularAutomatonSimulation.java
@@ -12,29 +12,31 @@ import java.util.function.Supplier;
 import static java.util.Objects.requireNonNull;
 
 /**
- * {@link CellularAutomataSimulation} instances run <i>The Game of Life</i>.
+ * {@link CellularAutomatonSimulation} instances run <i>The Game of Life</i>.
  */
-public class CellularAutomataSimulation<S extends State<S>>
+public class CellularAutomatonSimulation<S extends State<S>>
         implements Simulation {
 
     private final CellGrid<S> grid;
-    private final Supplier<S> supplier;
+    private final Supplier<S> randomState;
     private final S defaultState;
     private final ReadOnlyLongWrapper generationNumber = new ReadOnlyLongWrapper();
 
     /**
-     * Creates a new {@code GameOfLife} instance given the underlying {@link CellGrid}.
+     * Creates a new {@code CellularAutomataSimulation} instance for a given automaton.
      *
-     * @param grid     the underlying {@link CellGrid}
-     * @param defaultState   the state value to use when clearing the grid
-     * @param supplier  a {@Link Supplier} to produce values to initialize or reset the grid
-     * @throws NullPointerException if {@code grid} is {@code null}
+     * @param width         an {@code int} representing the number of columns
+     * @param height        an {@code int} representing the number of rows
+     * @param defaultState  a state {@code S} used to fill the grid when using
+     *                      the clear action
+     * @param randomState  a generator of states {@code} used to fill the grid
+     *                      when using the reset action
      */
-    public CellularAutomataSimulation(CellGrid<S> grid, S defaultState, Supplier<S> supplier) {
-        this.grid = requireNonNull(grid, "grid is null");
-        this.supplier = requireNonNull(supplier, "supplier is null");
-        this.defaultState = requireNonNull(defaultState, "defaultState is null");
-        grid.fillRandomly(this.supplier);
+    public CellularAutomatonSimulation(int width, int height, S defaultState, Supplier<S> randomState) {
+        this.grid = new CellGrid<>(width, height, defaultState);
+        this.defaultState = defaultState;
+        this.randomState = randomState;
+        grid.fillRandomly(randomState);
     }
 
 
@@ -54,8 +56,8 @@ public class CellularAutomataSimulation<S extends State<S>>
      */
     @Override
     public void updateToNextGeneration() {
-        grid.updateToNextGeneration();
-        generationNumber.set(getGenerationNumber() + 1);
+        this.grid.updateToNextGeneration();
+        this.generationNumber.set(getGenerationNumber() + 1);
     }
 
     @Override
@@ -88,7 +90,7 @@ public class CellularAutomataSimulation<S extends State<S>>
      * @return the current generationNumber
      */
     private long getGenerationNumber() {
-        return generationNumber.get();
+        return this.generationNumber.get();
     }
 
     /**
@@ -97,7 +99,7 @@ public class CellularAutomataSimulation<S extends State<S>>
      * @return the generationNumber {@link ReadOnlyLongProperty}
      */
     public ReadOnlyLongProperty generationNumberProperty() {
-        return generationNumber.getReadOnlyProperty();
+        return this.generationNumber.getReadOnlyProperty();
     }
 
 
@@ -105,16 +107,16 @@ public class CellularAutomataSimulation<S extends State<S>>
      * Clears the current game.
      */
     public void clear() {
-        grid.clear(defaultState);
-        generationNumber.set(0);
+        this.grid.clear(this.defaultState);
+        this.generationNumber.set(0);
     }
 
     /**
      * Clears the current game and randomly generates a new one.
      */
     public void reset() {
-        clear();
-        grid.fillRandomly(supplier);
+        this.clear();
+        this.grid.fillRandomly(this.randomState);
     }
 
     @Override
diff --git a/src/main/java/model/OneStepMatrixInitializer.java b/src/main/java/model/NextGenerationInitializer.java
similarity index 80%
rename from src/main/java/model/OneStepMatrixInitializer.java
rename to src/main/java/model/NextGenerationInitializer.java
index 5348af2..787a379 100644
--- a/src/main/java/model/OneStepMatrixInitializer.java
+++ b/src/main/java/model/NextGenerationInitializer.java
@@ -6,11 +6,11 @@ import datastruct.MatrixInitializer;
 import java.util.ArrayList;
 import java.util.List;
 
-public class OneStepMatrixInitializer<S extends State<S>> implements MatrixInitializer<S> {
+public class NextGenerationInitializer<S extends State<S>> implements MatrixInitializer<S> {
 
     private final CellGrid<S> grid;
 
-    public OneStepMatrixInitializer(CellGrid<S> grid) {
+    public NextGenerationInitializer(CellGrid<S> grid) {
         this.grid = grid;
     }
 
diff --git a/src/main/java/model/states/BiColorState.java b/src/main/java/model/states/BiColorState.java
new file mode 100644
index 0000000..de0b791
--- /dev/null
+++ b/src/main/java/model/states/BiColorState.java
@@ -0,0 +1,61 @@
+package model.states;
+
+import javafx.scene.paint.Color;
+import model.State;
+
+import java.util.List;
+import java.util.Random;
+
+public enum BiColorState implements State<BiColorState> {
+    BLUE, RED, DEAD;
+
+
+
+    @Override
+    public Color getColor() {
+        return switch (this) {
+            case BLUE -> Color.BLUE;
+            case RED -> Color.RED;
+            case DEAD -> Color.WHITE;
+        };
+    }
+
+    @Override
+    public BiColorState next() {
+        return switch (this) {
+            case BLUE -> RED;
+            case RED -> DEAD;
+            case DEAD -> BLUE;
+        };
+    }
+
+    @Override
+    public BiColorState update(List<State<BiColorState>> neighbours) {
+        int countBlue = 0;
+        int countRed = 0;
+        for (State<BiColorState> neighbour : neighbours) {
+            if (neighbour == RED) {
+                countRed++;
+            }
+            if (neighbour == BLUE) {
+                countBlue++;
+            }
+        }
+        if (this == DEAD) {
+            return (countBlue + countRed != 3)? DEAD:
+                    countBlue > countRed? BLUE:
+                            RED;
+        }
+        return 2 <= countBlue + countRed && countBlue + countRed <= 3? this:
+                DEAD;
+    }
+
+
+    private final static Random generator = new Random();
+
+    public static BiColorState random() {
+        return generator.nextBoolean()? DEAD:
+                generator.nextBoolean()? RED:
+                        BLUE;
+    }
+}
diff --git a/src/main/java/model/states/BriansBrainState.java b/src/main/java/model/states/BriansBrainState.java
new file mode 100644
index 0000000..a90286c
--- /dev/null
+++ b/src/main/java/model/states/BriansBrainState.java
@@ -0,0 +1,57 @@
+package model.states;
+
+import javafx.scene.paint.Color;
+import model.State;
+
+import java.util.List;
+import java.util.Random;
+
+public enum BriansBrainState implements State<BriansBrainState> {
+    ON, OFF, DYING;
+
+    @Override
+    public Color getColor() {
+        return switch (this) {
+            case ON -> Color.WHITE;
+            case OFF -> Color.BLACK;
+            case DYING -> Color.BLUE;
+        };
+    }
+
+    @Override
+    public BriansBrainState next() {
+        return switch (this) {
+            case ON -> DYING;
+            case OFF -> ON;
+            case DYING -> OFF;
+        };
+    }
+
+    @Override
+    public BriansBrainState update(List<State<BriansBrainState>> neighbours) {
+        return switch (this) {
+            case ON -> DYING;
+            case DYING -> OFF;
+            case OFF -> {
+                int count = countList(ON, neighbours);
+                yield count==2 ? ON : OFF;
+            }
+        };
+    }
+
+    static <T>  int countList(T value, List<T> elements) {
+        int count = 0;
+        for (T v : elements) {
+            if (v.equals(value)) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    final static Random GENERATOR = new Random();
+
+    public static BriansBrainState random() {
+        return GENERATOR.nextInt(10) == 0 ? ON: OFF;
+    }
+}
diff --git a/src/main/java/model/GameOfLifeState.java b/src/main/java/model/states/GameOfLifeState.java
similarity index 96%
rename from src/main/java/model/GameOfLifeState.java
rename to src/main/java/model/states/GameOfLifeState.java
index 1956a55..6378a92 100644
--- a/src/main/java/model/GameOfLifeState.java
+++ b/src/main/java/model/states/GameOfLifeState.java
@@ -1,6 +1,7 @@
-package model;
+package model.states;
 
 import javafx.scene.paint.Color;
+import model.State;
 
 import java.util.List;
 import java.util.Random;
diff --git a/src/main/java/model/states/SeedsState.java b/src/main/java/model/states/SeedsState.java
new file mode 100644
index 0000000..0895372
--- /dev/null
+++ b/src/main/java/model/states/SeedsState.java
@@ -0,0 +1,40 @@
+package model.states;
+
+import javafx.scene.paint.Color;
+import model.State;
+
+import java.util.List;
+
+import static model.states.BriansBrainState.GENERATOR;
+import static model.states.BriansBrainState.countList;
+
+public enum SeedsState implements State<SeedsState> {
+    ON, OFF;
+    @Override
+    public Color getColor() {
+        return switch (this) {
+            case ON -> Color.WHITE;
+            case OFF -> Color.BLACK;
+        };
+    }
+
+    @Override
+    public SeedsState next() {
+        return switch (this) {
+            case ON -> OFF;
+            case OFF -> ON;
+        };
+    }
+
+    @Override
+    public SeedsState update(List<State<SeedsState>> neighbours) {
+        return switch (this) {
+            case ON -> OFF;
+            case OFF -> countList(ON,neighbours) == 2 ? ON: OFF;
+        };
+    }
+
+    public static SeedsState random() {
+        return GENERATOR.nextInt(10)==0? ON: OFF;
+    }
+}
-- 
GitLab