We change the "Step" button into a "Stop/Go" button.
Besides just changing the label on the button, we also
need to create another thread. One thread will run the
Life game; the original thread will continue to listen
for button presses.
This isn't as difficult as it might seem. Our new class SeparateSubTask extends Thread goes into an infinite loop, executing the code to make one step, then sleeping for awhile. The code for the "Stop/Go" button either creates and starts this thread, or stops it, depending on whether the thread is currently running. |
import java.awt.*; import java.applet.Applet; import java.awt.event.*; // needed for ActionListener public class Life extends Applet { static int boardSize = 10; Cell [][] board; Cell [][] nextBoard; Button goButton; MyCanvas canvas; SeparateSubTask subtask; boolean running = false; /** * Creates an empty (all cells dead) playing board of the given boardSize. */ static Cell[][] emptyBoard (int boardSize) { Cell[][] result = new Cell[boardSize][boardSize]; for (int i = 0; i < boardSize; i++) for (int j = 0; j < boardSize; j++) result[i][j] = new Cell (); return result; } public void init () { setLayout (new BorderLayout ()); goButton = new Button ("Stop/Go"); add (BorderLayout.NORTH, goButton); // Finally, add code to make the button do something goButton.addActionListener (new GoButton ()); board = emptyBoard (boardSize); // -------------------------------- start of test data board[3][4].setAlive (true); board[4][5].setAlive (true); board[5][3].setAlive (true); board[5][4].setAlive (true); board[5][5].setAlive (true); // -------------------------------- end of test data canvas = new MyCanvas (board, boardSize); add (BorderLayout.CENTER, canvas); } class GoButton implements ActionListener { public void actionPerformed (ActionEvent e) { if (running) { subtask.stop (); running = false; } else { subtask = new SeparateSubTask (); subtask.start (); running = true; } } } class SeparateSubTask extends Thread { public void run () { int numberOfNeighbors; while (true) { nextBoard = emptyBoard (boardSize); for (int i = 0; i < boardSize; i++) for (int j = 0; j < boardSize; j++) { numberOfNeighbors = Cell.countLiveNeighbors (board, i, j); if (board[i][j].getAlive ()) { if (numberOfNeighbors == 2 || numberOfNeighbors == 3) nextBoard[i][j].setAlive (true); } else // cell is dead if (numberOfNeighbors == 3) nextBoard[i][j].setAlive (true); } board = nextBoard; canvas.board = nextBoard; // otherwise it still uses the old one // ...then make the changes visible. canvas.paint (canvas.getGraphics ()); repaint (); try { sleep (500); } catch (Exception e) { } } } } } class MyCanvas extends Canvas { int boardSize; Cell board[][]; MyCanvas (Cell [][] board, int boardSize) { this.board = board; this.boardSize = boardSize; } public void paint (Graphics g) { Dimension d = getSize (); int cellWidth = d.width / boardSize; int cellHeight = d.height / boardSize; for (int i = 0; i < boardSize; i++) { for (int j = 0; j < boardSize; j++) { if (board[i][j].getAlive ()) g.setColor (Color.blue); else g.setColor (Color.white); g.fillOval (i * cellWidth, j * cellHeight, cellWidth, cellHeight); } } } } /** * A Cell is one element of a two-dimensional array in John Conway's * "Game of Life." It is either "alive" or "dead." * @author Dave Matuszek */ class Cell { boolean alive = false; /** * Constructs a Cell in a given state (alive or dead). */ Cell (boolean alive) { this.alive = alive; } /** * Constructs a Cell in a "dead" state. */ Cell () { this (false); } /** * Sets this cell to be alive or dead. */ void setAlive (boolean alive) { this.alive = alive; } /** * Returns the state (alive or dead) of this cell. */ boolean getAlive () { return alive; } // Deleted: static boolean isAlive (int i, int j) /** * Count the number of living cells adjacent to this one. * Cells outside the array bounds are considered "dead." * This routine has been modified to eliminate references to * Life.isAlive (). */ static int countLiveNeighbors (Cell [][] board, int i, int j) { int limit = Life.boardSize - 1; int count = 0; for (int ii = i - 1; ii <= i + 1; ii++) for (int jj = j - 1; jj <= j + 1; jj++) { if (ii == i && jj == j) continue; if (ii < 0 || ii > limit) continue; if (jj < 0 || jj > limit) continue; if (board[ii][jj].getAlive ()) count++; } return count; } }