diff options
Diffstat (limited to 'src/main/java/uk/co/notori/gol/Panel.java')
| -rw-r--r-- | src/main/java/uk/co/notori/gol/Panel.java | 249 |
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 |
