aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/uk/co/notori/gol/Panel.java
diff options
context:
space:
mode:
authornotori <188390306+n0tori@users.noreply.github.com>2025-03-13 12:28:08 +0000
committernotori <188390306+n0tori@users.noreply.github.com>2025-03-13 12:28:08 +0000
commit3f80ccbfc0dd2f3b4295e506e7ce5931b720e2ee (patch)
tree17b44f56b7aaec5247dbed939e2f567a55b83ce0 /src/main/java/uk/co/notori/gol/Panel.java
project files
Diffstat (limited to 'src/main/java/uk/co/notori/gol/Panel.java')
-rw-r--r--src/main/java/uk/co/notori/gol/Panel.java249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/main/java/uk/co/notori/gol/Panel.java b/src/main/java/uk/co/notori/gol/Panel.java
new file mode 100644
index 0000000..00c8d51
--- /dev/null
+++ b/src/main/java/uk/co/notori/gol/Panel.java
@@ -0,0 +1,249 @@
+package uk.co.notori.gol;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import java.util.Random;
+
+/**
+ * The grid for Conway's Game of Life
+ */
+public class Panel extends JPanel implements MouseListener {
+ public static Dimension rootSize;
+
+ private static final int DEFAULT_WIDTH = 40;
+ private static final int DEFAULT_HEIGHT = 40;
+ private static final int CELL_SIZE = 15;
+ private static final Color ALIVE_COLOR = Color.BLACK;
+ private static final Color DEAD_COLOR = Color.WHITE;
+ private static final Color GRID_COLOR = Color.GRAY;
+
+ private boolean[][] grid;
+ private boolean[][] nextGrid;
+ private int width;
+ private int height;
+ private boolean running;
+ private javax.swing.Timer timer;
+ private int generation;
+ private int population;
+
+ private int updateCounter = 0;
+ // update UI every 7 frames approx. every other second at medium speed
+ private static final int UPDATE_FREQUENCY = 7;
+
+ private Random random = new Random();
+
+ /**
+ * Create game Panel
+ */
+ public Panel(Dimension rootSize) {
+ super();
+
+ Panel.rootSize = rootSize;
+
+ // calculate width and height based on screen size
+ // create space for buttons
+ this.width = rootSize.width / CELL_SIZE;
+ this.height = (rootSize.height - 100) / CELL_SIZE;
+
+ grid = new boolean[width][height];
+ nextGrid = new boolean[width][height];
+
+ // size of the grid
+ setPreferredSize(new Dimension(width * CELL_SIZE, height * CELL_SIZE));
+ setLayout(null);
+
+ running = false;
+ generation = 0;
+ population = 0;
+
+ // Set up timer for animation
+ ActionListener animationListener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (running) {
+ evolve();
+ updatePopulation();
+ generation++;
+ repaint();
+
+ updateCounter++;
+
+ // update UI counters so it's not visually annoying
+ if (updateCounter >= UPDATE_FREQUENCY) {
+ updateCounter = 0;
+ // update the UI with new generation and population count
+ if (getParent() instanceof MainUI) {
+ ((MainUI) getParent()).updateCounters(generation, population);
+ }
+ }
+ }
+ }
+ };
+ timer = new javax.swing.Timer(300, animationListener);
+
+ initializeRandomGrid();
+
+ addMouseListener(this);
+
+ setVisible(true);
+ setOpaque(true);
+
+ timer.setInitialDelay(1000);
+ timer.start();
+ running = true;
+ }
+
+ /**
+ * Initialize the grid with random cells
+ */
+ public void initializeRandomGrid() {
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ grid[x][y] = random.nextDouble() < 0.3;
+ }
+ }
+ updatePopulation();
+ generation = 0;
+ updateCounter = 0;
+ if (getParent() instanceof MainUI) {
+ ((MainUI) getParent()).updateCounters(generation, population);
+ }
+ repaint();
+ }
+
+ public void clearGrid() {
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ grid[x][y] = false;
+ }
+ }
+ updatePopulation();
+ generation = 0;
+ updateCounter = 0;
+ if (getParent() instanceof MainUI) {
+ ((MainUI) getParent()).updateCounters(generation, population);
+ }
+ repaint();
+ }
+
+
+ private void evolve() {
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ int neighbors = countNeighbors(x, y);
+ if (grid[x][y]) {
+ nextGrid[x][y] = neighbors == 2 || neighbors == 3;
+ } else {
+ nextGrid[x][y] = neighbors == 3;
+ }
+ }
+ }
+
+ boolean[][] temp = grid;
+ grid = nextGrid;
+ nextGrid = temp;
+ }
+
+ private int countNeighbors(int x, int y) {
+ int count = 0;
+ for (int dx = -1; dx <= 1; dx++) {
+ for (int dy = -1; dy <= 1; dy++) {
+ if (dx == 0 && dy == 0) continue;
+
+ int nx = (x + dx + width) % width;
+ int ny = (y + dy + height) % height;
+
+ if (grid[nx][ny]) {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+
+ private void updatePopulation() {
+ population = 0;
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ if (grid[x][y]) {
+ population++;
+ }
+ }
+ }
+ }
+
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+
+ // Draw the grid
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ if (grid[x][y]) {
+ g.setColor(ALIVE_COLOR);
+ } else {
+ g.setColor(DEAD_COLOR);
+ }
+ g.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
+
+ g.setColor(GRID_COLOR);
+ g.drawRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
+ }
+ }
+ }
+
+ public void play() {
+ if (!running) {
+ running = true;
+ timer.start();
+ }
+ }
+
+ public void pause() {
+ if (running) {
+ running = false;
+ timer.stop();
+
+ // force a final update when pausing
+ if (getParent() instanceof MainUI) {
+ ((MainUI) getParent()).updateCounters(generation, population);
+ }
+ }
+ }
+
+ public void reset() {
+ pause();
+ initializeRandomGrid();
+ generation = 0;
+ updatePopulation();
+ }
+
+ // empty implementations
+ public void mouseClicked(MouseEvent e) {}
+ public void mousePressed(MouseEvent e) {}
+ public void mouseReleased(MouseEvent e) {}
+ public void mouseEntered(MouseEvent e) {}
+ public void mouseExited(MouseEvent e) {}
+
+ public boolean isRunning() {
+ return running;
+ }
+
+ public int getGeneration() {
+ return generation;
+ }
+
+ public int getPopulation() {
+ return population;
+ }
+
+ public void setSpeed(int delay) {
+ timer.setDelay(delay);
+ }
+
+ public int getDelay() {
+ return timer.getDelay();
+ }
+} \ No newline at end of file