package model; import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.beans.property.ReadOnlyLongProperty; import javafx.beans.property.ReadOnlyLongWrapper; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.util.Duration; import java.util.Random; import static java.util.Objects.requireNonNull; /** * {@link GameOfLife} instances run <i>The Game of Life</i>. */ public class GameOfLife { private final Random random = new Random(); private static final int PERIOD_IN_MILLISECONDS = 100; private final Grid grid; private final ReadOnlyLongWrapper generationNumber = new ReadOnlyLongWrapper(); private Timeline timeline; /** * 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"); updateTimeline(); grid.randomGeneration(random); } private void updateTimeline() { Duration duration = new Duration(PERIOD_IN_MILLISECONDS); EventHandler<ActionEvent> eventHandler = event -> next(); KeyFrame keyFrame = new KeyFrame(duration, eventHandler); timeline = new Timeline(keyFrame); timeline.setCycleCount(Animation.INDEFINITE); } /** * Transitions into the next generationNumber. */ private void next() { grid.updateToNextGeneration(); generationNumber.set(getGenerationNumber() + 1); } /** * Returns the current generationNumber. * * @return the current generationNumber */ private long getGenerationNumber() { return generationNumber.get(); } /** * Returns the generationNumber {@link ReadOnlyLongProperty}. * * @return the generationNumber {@link ReadOnlyLongProperty} */ public ReadOnlyLongProperty generationNumberProperty() { return generationNumber.getReadOnlyProperty(); } /** * Returns the {@link Grid}. * * @return the {@link Grid} */ public Grid getGrid() { return grid; } /** * Plays the game. */ public void play() { timeline.play(); } /** * Pauses the game. */ public void pause() { timeline.pause(); } /** * Clears the current game. */ public void clear() { pause(); grid.clear(); generationNumber.set(0); } /** * Clears the current game and randomly generates a new one. */ public void reset() { clear(); grid.randomGeneration(random); } }