/**@author Thanh Lai
/* @version 2*/
import java.util.Scanner;
import javax.swing.JFrame;
public class MainGOL extends JFrame {
static Scanner scan = new Scanner(System.in);
static JFrame mainFrame;
static int Tcol;
static int Trow;
static int delay;
static int generation;
public static void main(String[] args) {
/* Prompting user input and check it */
System.out
.println("Please enter the width of the universe grid(10-50): ");
Tcol = scan.nextInt();
// check for 10 to 50
if (Tcol < 10 || Tcol > 50) {
if (Tcol < 10) {
System.out
.println("The width is less than 10. Default width is set to 10.");
Tcol = 10;
}
if (Tcol > 50) {
System.out
.println("The width is greater than 50. Default width is set to 50.");
Tcol = 50;
}
}
System.out
.println("Please enter the height of the universe grid(10-50): ");
Trow = scan.nextInt();
if (Trow < 10 || Trow > 50) {
if (Trow < 10) {
System.out
.println("The height is less than 10. Default height is set to 10.");
Trow = 10;
}
if (Trow > 50) {
System.out
.println("The height is greater than 50. Default height is set to 50.");
Trow = 50;
}
}
System.out.println("Please enter the delay between ticks(0-3000): ");
delay = scan.nextInt();
if (delay < 0 || delay > 3000) {
System.out
.println("The delay is out of range. Default delay is set to 500");
delay = 500;
}
System.out
.println("How many ticks(generations) to run before pausing(0-for continuously): ");
generation = scan.nextInt();
/* Create a main frame which contains a main panel */
mainFrame = new JFrame("Game of Life - Thanh Lai - A00831625");
/* Create a main panel and add it into the main frame */
PanelGOL obPanel = new PanelGOL();
mainFrame.getContentPane().add(obPanel);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.pack();
mainFrame.setVisible(true);
}
}
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Creatures extends JPanel {
public boolean alive = false;
public boolean goingToChange = false;
JLabel x = new JLabel(" ");
/*
* Once the Creatures object is created, the random state of the Creatures'
* cell will be generated
*/
public Creatures() {
if ((int) (Math.random() * 2) == 1) {
alive = true;
x.setText("X");
}
this.add(x);
}
}
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class PanelGOL extends JPanel {
static JPanel mainPanel;
static int ticks = 0;
/*
* Create creature cells object which represents for each cells in the main
* panel
*/
static Creatures cells[][] = new Creatures[MainGOL.Trow][MainGOL.Tcol];
/* Timer object 'fires' the action listener after delay period */
Timer time = new Timer(MainGOL.delay, new MyActionListener());
public PanelGOL() {
/*
* Create a grid layout for the main panel in order to describe the
* cells
*/
mainPanel = new JPanel(new GridLayout(MainGOL.Trow, MainGOL.Tcol, 2, 2));
this.addKeyListener(new TAdapter());
this.add(mainPanel);
buildWorld();
time.start();
this.setFocusable(true);
}
/* Initialize Creatures' object for each cells */
public static void buildWorld() {
for (int row = 0; row < MainGOL.Trow; row++) {
for (int col = 0; col < MainGOL.Tcol; col++) {
Creatures tempCreature = new Creatures();
tempCreature.setBackground(Color.orange);
mainPanel.add(cells[row][col] = tempCreature);
}
}
}
/*
* Create a method that return the state of the Creatures'
* objects
*/
public boolean checkState(int row, int col) {
return cells[row][col].alive;
}
/* Logical core of the program */
/*
* The method is to check eight neighbor cells - up, down, right, left, and
* diagonally-except for the cells on the edge of the grid . Finally, return
* the neighbors number
*/
public int checkNeighborOf(int row, int col) {
int neighbors = 0;
for (int r = row - 1; r <= row + 1; r++)
for (int c = col - 1; c <= col + 1; c++) {
if (r < 0 || c < 0 || r >= MainGOL.Trow || c >= MainGOL.Tcol)
continue;
if (r == row && c == col)
continue;
if (checkState(r, c))
neighbors++;
}
return neighbors;
}
/*
* Create a method to point that which cells are going to be changed after a
* tick. Due to death and give birth happens at the same time the
* goingToChange variable is declared to hold the state of each cell before
* they are actually "be killed or give birth"
*/
public void killOrCreate() {
for (int row = 0; row < MainGOL.Trow; row++)
for (int col = 0; col < MainGOL.Tcol; col++) {
if (checkNeighborOf(row, col) == 3 && !cells[row][col].alive) {
cells[row][col].goingToChange = true;
} else if (cells[row][col].alive
&& checkNeighborOf(row, col) == 2
|| checkNeighborOf(row, col) == 3) {
cells[row][col].goingToChange = false;
} else {
cells[row][col].goingToChange = cells[row][col].alive;
}
//to let the cell know it will be changed state (die --> alive or alive--> die)
}
}
/*
* Support the method above, this method is to change state of the cells
* through 'alive' variable
*/
private void changeState() {
for (int row = 0; row < MainGOL.Trow; row++)
for (int col = 0; col < MainGOL.Tcol; col++) {
if (cells[row][col].goingToChange) {
cells[row][col].alive = !cells[row][col].alive;
}
}
}
/*
* After all, rebuild the panels by re-setting its state to appropriate
* shown-text
*/
private void reBuildWorld() {
for (int row = 0; row < MainGOL.Trow; row++)
for (int col = 0; col < MainGOL.Tcol; col++) {
if (cells[row][col].alive)
cells[row][col].x.setText("X");
else
cells[row][col].x.setText(" ");
}
ticks++;
System.out.println("Generations: " + ticks);
}
/*
* MyActionListener class implements the whole checking cells, changing
* states and rebuilding the panels process
*/
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
killOrCreate();
changeState();
reBuildWorld();
MainGOL.mainFrame.pack();
MainGOL.mainFrame.repaint();
if (MainGOL.generation != 0 && ticks == MainGOL.generation) {
time.stop();
}
}
}
/* Key functions for the requirement */
private class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
/* space key pauses / resumes the game */
int spaceKey = e.getKeyCode();
if (spaceKey == 32) { // space key value is 32
if (time.isRunning()) {
time.stop();
} else
time.start();
}
/* escape key stops and exists the game at any point */
int EscKey = e.getKeyCode();
if (EscKey == 27) { // escape key value is 27
System.out.println("Exit program");
System.exit(0);
}
/* s key executes the game for one tick and pauses */
int sKey = e.getKeyCode(); // 83
if (sKey == 83) {
if (time.isRunning()) {
time.stop();
}
killOrCreate();
changeState();
reBuildWorld();
MainGOL.mainFrame.pack();
MainGOL.mainFrame.repaint();
}
}
}
}
Download the complete source code
Output: