// LifeApp.java import java.awt.*; import java.awt.event.*; import java.net.*; import java.io.*; public class LifeApp extends Frame implements ActionListener, ItemListener, Runnable { private static final byte STOPPED = 0, STARTED = 1; private LifeStarter ls = null; private TextField genField, statusField; private Choice presetChoice, boardChoice; private Button contPause, reset, about; private int currentGen, boardType, presetNo; private String pattern = "", version = "The Game of Life v1.17"; private LifeBoard board; private Thread runner = null, thisThread = null; private boolean runsFromApplet; private Slider slider; private byte status; public static Image image; public static final String COPYRIGHT = "\u00a9"; public LifeApp(LifeStarter _ls, boolean _runsFromApplet) { super("The Game of Life"); ls = _ls; runsFromApplet = _runsFromApplet; setBackground(SystemColor.control); try { if (ls != null) { URL url = new URL(ls.getCodeBase() + "Images/smallSmile.gif"); trackImage(getToolkit().getImage(url)); } else trackImage(getToolkit().getImage("Images/smallSmile.gif")); } catch (MalformedURLException mfe) { System.err.println("Error: " + mfe); } genField = new TextField(5); genField.setEditable(false); genField.setBackground(Color.white); statusField = new TextField(37); statusField.setEditable(false); statusField.setBackground(Color.white); statusField.setText("Click on the cells where you want " + '"' + "life" + '"' + " to exist."); String presets[] = {"Blank board", "Random board", "Barber pole", "Harvester", "Glider", "Tumbler"}; presetChoice = new Choice(); for(int i = 0; i < presets.length; i++) presetChoice.add(presets[i]); presetChoice.addItemListener(this); String boardTypes[] = {"Finite", "Torus"}; boardChoice = new Choice(); for(int i = 0; i < boardTypes.length; i++) boardChoice.add(boardTypes[i]); boardChoice.addItemListener(this); Label title = new Label("The Game of Life", Label.CENTER); title.setFont(new Font("sansserif", Font.BOLD, 30)); boardType = 0; board = new LifeBoard(boardType, image, 20, 35); contPause = new Button(" Start "); contPause.addActionListener(this); reset = new Button(" Reset "); reset.addActionListener(this); about = new Button(" About "); about.addActionListener(this); Panel bottomPanel = new Panel(); bottomPanel.setLayout(new FlowLayout()); bottomPanel.add(new Label("Board type:", Label.RIGHT)); bottomPanel.add(boardChoice); bottomPanel.add(new Label("Configurations:", Label.RIGHT)); bottomPanel.add(presetChoice); bottomPanel.add(new Label("")); bottomPanel.add(contPause); bottomPanel.add(reset); bottomPanel.add(about); slider = new Slider("Delay in msec.", 70, 10, 20, 510); Panel bottomPanel2 = new Panel(); bottomPanel2.setLayout(new FlowLayout()); bottomPanel2.add(new Label("Generation:", Label.RIGHT)); bottomPanel2.add(genField); bottomPanel2.add(slider); bottomPanel2.add(new Label("Status:", Label.RIGHT)); bottomPanel2.add(statusField); Panel wholeBottom = new Panel(); wholeBottom.setLayout(new BorderLayout()); wholeBottom.add("North", bottomPanel); wholeBottom.add("South", bottomPanel2); Panel boardPanel = new Panel(); boardPanel.setLayout(new FlowLayout()); boardPanel.add(board); Panel mainPanel = new Panel(); mainPanel.setLayout(new BorderLayout()); mainPanel.add("North", new Box(boardPanel, "Playing Field", Box.LEFT)); mainPanel.add("Center", new Box(wholeBottom, "Tools & Options", Box.LEFT)); Panel titlePanel = new Panel(); titlePanel.setLayout(new FlowLayout()); titlePanel.add(title); Panel thePanel = new Panel(); thePanel.setLayout(new BorderLayout()); thePanel.add("North", titlePanel); thePanel.add("South", mainPanel); setLayout(new BorderLayout()); add("North", thePanel); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { if (runsFromApplet) ls.close(); else System.exit(0); } }); validate(); pack(); setResizable(false); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); Point p = new Point((int)((d.getWidth() - this.getWidth())/2), (int)((d.getHeight() - this.getHeight())/2)); setLocation(p); contPause.requestFocus(); setVisible(true); } private void trackImage(Image _image) { image = _image; MediaTracker tracker = new MediaTracker(this); tracker.addImage(image, 0); try { tracker.waitForAll(); } catch(InterruptedException ie) { System.err.println("Image loading interrupted: " + ie); } } public String loadPreset(int presetNo) { BufferedReader input; StringBuffer config = new StringBuffer(); String file = ""; if (presetNo == 2) file = "BarberPole.txt"; else if (presetNo == 3) file = "Harvester.txt"; else if (presetNo == 4) file = "Glider.txt"; else if (presetNo == 5) file = "Tumbler.txt"; try { if (ls != null) { URL url = new URL(ls.getCodeBase(), file); input = new BufferedReader(new InputStreamReader(url.openStream())); } else input = new BufferedReader(new FileReader(file)); String line = ""; while ((line = input.readLine()) != null) config.append(line); input.close(); } catch (IOException ioe) { System.err.println("Error opening file: " + ioe); } return config.toString(); } public void start() { stop(); if (runner == null) { status = STARTED; runner = new Thread(this); runner.start(); } } public void stop() { if (runner != null) { status = STOPPED; runner = null; } } public void resetGame() { genField.setText(""); contPause.setLabel(" Start "); presetChoice.select(0); presetChoice.setEnabled(true); boardChoice.setEnabled(true); statusField.setText("Click on the cells where you want " + '"' + "life" + '"' + " to exist."); board.clear(); board.setChangeable(true); } public void delay() { try { runner.sleep(slider.getValue()); } catch (InterruptedException ie) { System.err.println("Error: " + ie); } } public void run() { thisThread = Thread.currentThread(); while ((runner == thisThread) && (currentGen < Integer.MAX_VALUE)) { if (currentGen == 1) { genField.setText(Integer.toString(currentGen)); delay(); } currentGen += 1; genField.setText(Integer.toString(currentGen)); board.makeNextGeneration(); delay(); if ((status == STARTED) && (!(board.isOneAlive()))) { currentGen -= 1; if (currentGen == 1) { MessageBox mb = new MessageBox(ls, this, "Too Bad", "Your configuration killed everyone off in " + currentGen + " generation.", "frown.gif"); } else { MessageBox mb = new MessageBox(ls, this, "Too Bad", "Your configuration killed everyone off in " + currentGen + " generations.", "frown.gif"); } resetGame(); currentGen = Integer.MAX_VALUE; } } } public void actionPerformed(ActionEvent ae) { pattern = ""; boolean isRandom = false; if (ae.getSource() == contPause) { if (contPause.getLabel().equals(" Start ")) { if (!board.isOneAlive()) { MessageBox mb = new MessageBox(ls, this, "Error", "Board has not been initialized.", "exclaim.gif"); } else { contPause.setLabel(" Pause "); statusField.setText("Game in session."); presetChoice.setEnabled(false); boardChoice.setEnabled(false); board.setChangeable(false); currentGen = 1; start(); } } else if (contPause.getLabel().equals("Continue")) { contPause.setLabel(" Pause "); statusField.setText("Game in session."); start(); } else { contPause.setLabel("Continue"); statusField.setText("Game paused by user."); stop(); } } else if (ae.getSource() == reset) { stop(); resetGame(); } else if (ae.getSource() == about) { AboutBox aboutBox = new AboutBox( ls, this, version, "Written by Brian S. Borowski", "Concept by John H. Conway", "Examples by Robert L. Kruse", COPYRIGHT + " 1999-2002 Brian S. Borowski", "All Rights Reserved.", "information.gif"); } } public void itemStateChanged(ItemEvent ie) { if (ie.getSource() == boardChoice) { if (boardChoice.getSelectedIndex() != boardType) { boardType = boardChoice.getSelectedIndex(); board.setBoardType(boardType); } } else if (ie.getSource() == presetChoice) { board.clear(); if (presetChoice.getSelectedIndex() == 1) board.randomize(); else if (presetChoice.getSelectedIndex() > 1) board.setPresetConfig(loadPreset(presetChoice.getSelectedIndex())); } } public static void main(String[] args) { LifeApp la = new LifeApp(null, false); } }