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