Initial commit

This commit is contained in:
2021-04-04 01:21:49 +02:00
commit 9eca62e785
6 changed files with 351 additions and 0 deletions

View 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
View File

@@ -0,0 +1,9 @@
package main.java;
import main.java.view.GameOfLife;
public class Main {
public static void main(String[] args) {
new GameOfLife();
}
}

View 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();
}
}

View 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;
}
}

View 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);
}
}
}

View 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);
}
}
}
}
}