Description

Conways Game of Life is a simple 2D evolution simulation. This is the first Java project in which I built a graphical interface since the graphical output is much faster than drawing Conways Game of Life on the command prompt. This version is 84 lines long and runs single-threaded. Parallelism would be possible, too, but one CPU core is more than enough even for 1920x1080 pixels when each field is represented by a single pixel.


Rule Modification

Changing the rules of Conways Game of Life results in a completely different simulation. Most changes will make the simulation unstable though, letting more pixels die than there are created or filling the whole screen with alive pixels that can't die anymore. It turns out that the original set of rules is the most stable solution over time.
One of the more stable changes produces a very interesting result. The second rule is changed to 0 from the original 2. This produces a simulation which looks like the solidifying of a polycrystaline material. Slowly either horizontal or vertical patterns start to form on random places and they keep growing until they meet up at random boundaries. The space between two areals needs lots of time to finally become stable.
The two images below show the crystal formation at two different steps in time, the second one shows the crystalization almost being finished.


Source Code

import javax.swing.JFrame; import java.awt.Color; import java.awt.image.BufferedImage; import java.awt.Graphics2D; import java.awt.Toolkit; import java.awt.Point; public class GameOfLife extends JFrame { private final Graphics2D g; private final BufferedImage frame; private final int cx = Toolkit.getDefaultToolkit().getScreenSize().width, cy = Toolkit.getDefaultToolkit().getScreenSize().height; public static void main(String[] args) { new GameOfLife(); } public GameOfLife() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setExtendedState(JFrame.MAXIMIZED_BOTH); setUndecorated(true); getContentPane().setBackground(Color.BLACK); getContentPane().setCursor(Toolkit.getDefaultToolkit().createCustomCursor(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB), new Point(0, 0), "")); setVisible(true); frame = new BufferedImage(cx, cy, BufferedImage.TYPE_INT_RGB); // TYPE_3BYTE_BGR is slow g = (Graphics2D)frame.getGraphics(); g.setColor(Color.WHITE); run(); } public void run() { double st; final int res = 3; // resolution (must be >1) final boolean[][] m = new boolean[cx/res][cy/res]; final boolean[][] c = new boolean[cx/res][cy/res]; int n; random(m); while(true) { st = time(); for(int y=0; y < m[0].length; y++) { for(int x=0; x < m.length; x++) { n = count(m,x,y); // ---------- rules ---------- if(m[x][y]==false && n==3) c[x][y] = true; else if(m[x][y]==true && n<2) c[x][y] = false; // n<0 for crystal growth else if(m[x][y]==true && n>3) c[x][y] = false; else if(m[x][y]==true) c[x][y] = true; } } for(int y=0; y < m[0].length; y++) { for(int x=0; x < m.length; x++) { m[x][y] = c[x][y]; // update field if(m[x][y]) g.fillRect(x*res, y*res, res-1, res-1); // draw field } } this.getGraphics().drawImage(frame, 0, 0, null); g.clearRect(0, 0, cx, cy); pause(1.0/60.0-time()+st); } } public int count(boolean[][] m, int x, int y) { int n=0, a=x-1, b=x+1, c=y-1, d=y+1; if(x == 0) a = m.length-1; // toroidal field else if(x == m.length-1) b = 0; if(y == 0) c = m[0].length-1; else if(y == m[0].length-1) d = 0; if(m[a][c]) n++; // neighbour count if(m[a][y]) n++; if(m[a][d]) n++; if(m[x][c]) n++; if(m[x][d]) n++; if(m[b][c]) n++; if(m[b][y]) n++; if(m[b][d]) n++; return n; } public void random(boolean[][] m) { for(int y=0; y < m[0].length; y++) for(int x=0; x < m.length; x++) m[x][y] = Math.random() < 0.3125; } public double time() { return System.nanoTime()*1E-9; } public void pause(double s) { if(s > 0) { try { Thread.sleep((int)(s*1E3)); } catch(Exception e) {} } } }

Download

GameOfLife.jar