Initial commit
This commit is contained in:
82
src/main/java/GenerationAlgorithm.java
Normal file
82
src/main/java/GenerationAlgorithm.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package main.java;
|
||||||
|
|
||||||
|
import main.java.model.Universe;
|
||||||
|
|
||||||
|
public class GenerationAlgorithm {
|
||||||
|
|
||||||
|
private final Universe universe;
|
||||||
|
private final int uniSize;
|
||||||
|
private static final int[][] NEIGHBOURS = {
|
||||||
|
{-1, +1}, { 0,+1}, {+1, +1},
|
||||||
|
{-1, 0}, {+1, 0},
|
||||||
|
{-1, -1}, { 0,-1}, {+1, -1}};
|
||||||
|
|
||||||
|
public GenerationAlgorithm(Universe universe) {
|
||||||
|
this.universe = universe;
|
||||||
|
this.uniSize = universe.getUniverseSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evolveUniverse () {
|
||||||
|
boolean[][] nextMatrix = new boolean[uniSize][uniSize];
|
||||||
|
|
||||||
|
int nextLivingCells = 0;
|
||||||
|
|
||||||
|
for (int col = 0; col < uniSize; col++) {
|
||||||
|
for (int row = 0; row < uniSize; row++) {
|
||||||
|
int neighbors = countAliveNeighbors(col, row);
|
||||||
|
|
||||||
|
// Game of life rules implementation
|
||||||
|
// Survival: Each live cell with either 2 or 3 alive neighbors will remain alive.
|
||||||
|
// Births: Each dead cell adjacent to exactly three living neighbors will become alive.
|
||||||
|
// Death: Each live cell with less than 2 or more than 3 alive neighbors will die.
|
||||||
|
if ((isAlive(col, row) && (neighbors > 1 && neighbors < 4))
|
||||||
|
|| (!isAlive(col, row) && neighbors == 3)) {
|
||||||
|
nextMatrix[col][row] = true;
|
||||||
|
nextLivingCells++;
|
||||||
|
} else {
|
||||||
|
nextMatrix[col][row] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
universe.setLivingCells(nextLivingCells);
|
||||||
|
universe.setMatrix(nextMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countAliveNeighbors(int x, int y) {
|
||||||
|
int alive = 0;
|
||||||
|
for (int[] offset : NEIGHBOURS) {
|
||||||
|
if (isAlive(x + offset[0], y + offset[1])) {
|
||||||
|
alive++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAliveCells(){
|
||||||
|
return this.universe.getLivingCells();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAlive(int x, int y) {
|
||||||
|
return universe.getMatrix()[checkBoundaries(x)][checkBoundaries(y)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int checkBoundaries(int coordinate) {
|
||||||
|
// Universe is periodic
|
||||||
|
if (coordinate < 0) {
|
||||||
|
coordinate = uniSize - 1;
|
||||||
|
}
|
||||||
|
if (coordinate > uniSize - 1) {
|
||||||
|
coordinate = 0;
|
||||||
|
}
|
||||||
|
return coordinate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean[][] getMatrix() {
|
||||||
|
return this.universe.getMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetUniverse() {
|
||||||
|
this.universe.initializeUniverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/main/java/Main.java
Normal file
9
src/main/java/Main.java
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package main.java;
|
||||||
|
|
||||||
|
import main.java.view.GameOfLife;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new GameOfLife();
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/main/java/controller/Controller.java
Normal file
70
src/main/java/controller/Controller.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package main.java.controller;
|
||||||
|
|
||||||
|
import main.java.GenerationAlgorithm;
|
||||||
|
import main.java.model.Universe;
|
||||||
|
import main.java.view.Grid;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
public class Controller extends Thread {
|
||||||
|
|
||||||
|
private GenerationAlgorithm generationAlgorithm;
|
||||||
|
private final JLabel genLabel;
|
||||||
|
private final JLabel aliveLabel;
|
||||||
|
private final Grid grid;
|
||||||
|
private boolean playing;
|
||||||
|
private int generation = 1;
|
||||||
|
private int speed = 500;
|
||||||
|
|
||||||
|
public Controller(GenerationAlgorithm generationAlgorithm, JLabel genLabel, JLabel aliveLabel, Grid grid) {
|
||||||
|
this.generationAlgorithm = generationAlgorithm;
|
||||||
|
this.genLabel = genLabel;
|
||||||
|
this.aliveLabel = aliveLabel;
|
||||||
|
this.grid = grid;
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(speed);
|
||||||
|
if (playing) {
|
||||||
|
generationAlgorithm.evolveUniverse();
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playPause() {
|
||||||
|
playing = !playing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
playing = false;
|
||||||
|
generationAlgorithm.resetUniverse();
|
||||||
|
generation = 1;
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeUniSize(Universe universe) {
|
||||||
|
this.grid.setSize(universe.getUniverseSize());
|
||||||
|
this.generationAlgorithm = new GenerationAlgorithm(universe);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeSpeed(int speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUI() {
|
||||||
|
genLabel.setText("Generation: " + generation++);
|
||||||
|
aliveLabel.setText("Living cells: " + generationAlgorithm.getAliveCells());
|
||||||
|
grid.setMatrix(generationAlgorithm.getMatrix());
|
||||||
|
grid.repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
48
src/main/java/model/Universe.java
Normal file
48
src/main/java/model/Universe.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package main.java.model;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class Universe {
|
||||||
|
|
||||||
|
private final int universeSize;
|
||||||
|
private int livingCells;
|
||||||
|
private boolean[][] matrix;
|
||||||
|
|
||||||
|
public Universe(int universeSize) {
|
||||||
|
this.universeSize = universeSize;
|
||||||
|
matrix = new boolean[universeSize][universeSize];
|
||||||
|
initializeUniverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initializeUniverse() {
|
||||||
|
livingCells = 0;
|
||||||
|
for(int i = 0; i < universeSize; i++) {
|
||||||
|
for(int j = 0; j < universeSize; j++) {
|
||||||
|
matrix[i][j] = new Random().nextBoolean();
|
||||||
|
if ((matrix[i][j])) {
|
||||||
|
livingCells++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUniverseSize() {
|
||||||
|
return universeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLivingCells() {
|
||||||
|
return livingCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLivingCells(int livingCells) {
|
||||||
|
this.livingCells = livingCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean[][] getMatrix() {
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMatrix(boolean[][] matrix) {
|
||||||
|
this.matrix = matrix;
|
||||||
|
}
|
||||||
|
}
|
||||||
99
src/main/java/view/GameOfLife.java
Normal file
99
src/main/java/view/GameOfLife.java
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package main.java.view;
|
||||||
|
|
||||||
|
import main.java.GenerationAlgorithm;
|
||||||
|
import main.java.controller.Controller;
|
||||||
|
import main.java.model.Universe;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ItemEvent;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
public class GameOfLife extends JFrame {
|
||||||
|
private static final int WINDOW_WIDTH= 600;
|
||||||
|
private static final int WINDOW_HEIGHT= 730;
|
||||||
|
private static final int UNIVERSE_SIZE = 20;
|
||||||
|
private transient Controller controller;
|
||||||
|
|
||||||
|
public GameOfLife() {
|
||||||
|
super("Game of life");
|
||||||
|
|
||||||
|
Universe universe = new Universe(UNIVERSE_SIZE);
|
||||||
|
GenerationAlgorithm generationAlgorithm = new GenerationAlgorithm(universe);
|
||||||
|
|
||||||
|
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||||
|
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||||
|
setLocationRelativeTo(null);
|
||||||
|
setLayout(new BorderLayout());
|
||||||
|
setUIFont(new javax.swing.plaf.FontUIResource(new Font("SansSerif", Font.BOLD, 16)));
|
||||||
|
FlowLayout flowlayout = new FlowLayout(FlowLayout.LEFT, 10, 10);
|
||||||
|
Dimension buttonDimension = new Dimension(100,30);
|
||||||
|
|
||||||
|
JPanel inputPanel = new JPanel();
|
||||||
|
inputPanel.setLayout(flowlayout);
|
||||||
|
|
||||||
|
JToggleButton playButton = new JToggleButton("Play");
|
||||||
|
playButton.setPreferredSize(buttonDimension);
|
||||||
|
playButton.addActionListener(e -> controller.playPause());
|
||||||
|
playButton.addItemListener(event -> {
|
||||||
|
if (event.getStateChange() == ItemEvent.SELECTED) {
|
||||||
|
playButton.setText("Pause");
|
||||||
|
} else {
|
||||||
|
playButton.setText("Play");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
inputPanel.add(playButton);
|
||||||
|
|
||||||
|
JButton resetButton = new JButton("Reset");
|
||||||
|
resetButton.setPreferredSize(buttonDimension);
|
||||||
|
resetButton.addActionListener(e -> controller.reset());
|
||||||
|
resetButton.addActionListener(e -> playButton.setSelected(false));
|
||||||
|
inputPanel.add(resetButton);
|
||||||
|
|
||||||
|
JPanel sizeSpinner = new JPanel();
|
||||||
|
sizeSpinner.setLayout(new BoxLayout(sizeSpinner, BoxLayout.X_AXIS));
|
||||||
|
sizeSpinner.add(new JLabel("Size "));
|
||||||
|
SpinnerNumberModel sizeInput = new SpinnerNumberModel(20, 10, 30, 1);
|
||||||
|
sizeInput.addChangeListener(e -> controller.changeUniSize(new Universe((Integer)sizeInput.getValue())));
|
||||||
|
sizeInput.addChangeListener(e -> playButton.setSelected(false));
|
||||||
|
sizeSpinner.add(new JSpinner(sizeInput));
|
||||||
|
inputPanel.add(sizeSpinner);
|
||||||
|
|
||||||
|
inputPanel.add(new JLabel("Speed"));
|
||||||
|
|
||||||
|
JSlider speedSlider = new JSlider(50, 1500, 1000);
|
||||||
|
speedSlider.setInverted(true);
|
||||||
|
speedSlider.setPreferredSize(new Dimension(190,30));
|
||||||
|
speedSlider.addChangeListener(e -> controller.changeSpeed(speedSlider.getValue()));
|
||||||
|
inputPanel.add(speedSlider);
|
||||||
|
|
||||||
|
add(inputPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
Grid grid = new Grid(UNIVERSE_SIZE);
|
||||||
|
add(grid, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JPanel labelPanel = new JPanel();
|
||||||
|
JLabel genLabel = new JLabel();
|
||||||
|
JLabel aliveLabel = new JLabel();
|
||||||
|
labelPanel.add(genLabel);
|
||||||
|
labelPanel.add(aliveLabel);
|
||||||
|
labelPanel.setLayout(flowlayout);
|
||||||
|
add(labelPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
controller = new Controller(generationAlgorithm, genLabel, aliveLabel, grid);
|
||||||
|
controller.start();
|
||||||
|
|
||||||
|
setResizable(false);
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUIFont (javax.swing.plaf.FontUIResource f){
|
||||||
|
Enumeration<Object> keys = UIManager.getDefaults().keys();
|
||||||
|
while (keys.hasMoreElements()) {
|
||||||
|
Object key = keys.nextElement();
|
||||||
|
Object value = UIManager.get (key);
|
||||||
|
if (value instanceof javax.swing.plaf.FontUIResource)
|
||||||
|
UIManager.put (key, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/main/java/view/Grid.java
Normal file
43
src/main/java/view/Grid.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package main.java.view;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class Grid extends JPanel {
|
||||||
|
private int size;
|
||||||
|
private boolean[][] matrix;
|
||||||
|
|
||||||
|
public Grid(int size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(int size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMatrix(boolean[][] matrix) {
|
||||||
|
this.matrix = matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
|
||||||
|
int cellWidth = getWidth()/size;
|
||||||
|
int cellHeight = getHeight()/size;
|
||||||
|
|
||||||
|
for (int col = 0; col < size; col++) {
|
||||||
|
// Paint grid
|
||||||
|
g.drawLine(0, cellHeight * col, cellWidth * size, cellHeight * col);
|
||||||
|
g.drawLine(cellWidth * col, 0, cellWidth * col, cellHeight * size);
|
||||||
|
g.drawLine(0, cellHeight * size, cellWidth * size, cellHeight * size);
|
||||||
|
g.drawLine(cellWidth * size, 0, cellWidth * size, cellHeight * size);
|
||||||
|
for (int row = 0; row < size; row++) {
|
||||||
|
// Paint living cells
|
||||||
|
if (matrix[col][row]) {
|
||||||
|
g.fillRect(cellWidth * row, cellHeight * col, cellWidth, cellHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user