C:\upload\java\Life\source\java\Life.java
// WIDTH = 700 HEIGHT = 400
/* ********************************************************************

                          LL         II   FFFFFF  EEEEEEE
                         LL         II   FF      EE
                        LL         II   FFFFF   EEEEEE
                       LL         II   FF      EE
                      LLLLLLL    II   FF      EEEEEEE
 
                                ( L i f e )

 This was originally written by Dean Moore in QBasic in Winter - Spring
 1996, as an assignment for a class the writer was teaching for
 the University of Maryland Asian Division (Okinawa), and was
 translated to C/C++ in March -- May, 1997, with a few modifications
 and different bells and whistles. During & after Winter 2000 it was 
 translated to Java.

 Actually, there are quite a few things that my students didn't have
 to do ... but I kept tinkering with the code.

 ---

 This program plays John Conway's game of Life. The game is played on
 a "large" grid, with certain counters initialized to "alive" at the
 outset, the rest "dead."
  
   One of many references is
   < http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life >

 All births and deaths occur simultaneously, and the next generation
 is computed as follows: anyone alive next to two or three living
 neighbors survives to the next generation. Anyone alive next to no
 or only one living neighbor dies of loneliness. Anyone with four or
 more living neighbors dies of overcrowding. A "dead" cell next to
 *exactly* three living neighbors comes to life in the next generation.

   ********************************************************************* */

import java.awt.Graphics;
import java.io.*;
import java.awt.*;
import java.awt.event.*;

final public class Life extends java.applet.Applet implements Runnable,
                                                        MouseListener,
                                                        MouseMotionListener,
                                                        ActionListener,

                                                        // Next two are where
                                                        // program constants &
                                                        // strings live.

                                                        Constants,
                                                        Strings

{    // Global variables follow. We minimize these as reasonable.

    boolean painted;    // We wait for the paint thread.

    boolean playAgain;
    int numberOfGames;
    boolean firstGame;
    Point default_gen_num_location;           // Constants whose purpose
    Point default_keep_going_button_location; // should be obvious by name.
    Point default_edit_game_button_location;
    Point default_quit_game_button_location;

    private static Objects objects;        // Holds objects.
    private static HandleButtons buttons;  // We use buttons an awful lot, and
                                           // maintain our own copy of the
                                           // buttons object.

    private static Vars vars;  /* Big class that holds variables. Big. There
                   are lots of variables. Lots of objects that communicate with
                   each other via this class, which is passed around from class
                   to class for communications. We use 'Get' and 'Set' methods
                   everywhere.

                   Historical note: the writer defined Class *Vars* as the
                   number of variables began to get unwieldy.
                */
   
    private Frame parentFrame;
                                        
    private PopupWindow error;        // For errors. Global to all.
    
    HandleASingleGeneration singleGenerationThread; // By name.
    Pause                   timeToSleepThread;      // For pauses, to let
                                                    // things finish.

    // Images follow. To avoid the flickering problem, we solely use
    // double-buffering.

    private Image    offScreenImage;     // We solely use
    private Graphics offScreenGraphics;  // double-buffering.

    private Thread runner;          // The main thread. There is a sub-thread
                                    // in the < run > method.

/*******************************************************************
    Initialization follows:
 ****************************************************************** */

    public void init()
    {
        objects             = null;  // Initialize
        buttons             = null;  // all 
        vars                = null;  // globals 
        parentFrame         = null;  // to
        error               = null;  // null
        offScreenImage      = null;  // for
        offScreenGraphics   = null;  // good
        runner              = null;  // measure.
        numberOfGames       = 0;     // How many games have we played?
        playAgain           = true;  // We always play at least once.
        firstGame           = true;  // At present, we are on the first
                                     // game.
        parentFrame = getParentFrame(); // Note this will live in both < vars >
                                        // and < objects >.
        if (parentFrame == null)
        {
            System.out.println("Parent frame null, < init > ?!?!");
            return;
        }

        Point appletSize = new Point(this.getSize().width,
                                     this.getSize().height);

        // Set up the offscreen image & its color:

        offScreenImage    = createImage(appletSize.x, appletSize.y);
        offScreenGraphics = offScreenImage.getGraphics();
        setBackground(COLOR_BACKGROUND);

        objects = new Objects(parentFrame,  // To what windows are attached, and
                              offScreenGraphics); // Graphics are needed by several
                                                  // objects.

        if (!objects.InstantiationsSucceeded())    // Did anything horrible
                                                   // happen?
        {
            System.out.println(INSTANTIATION_ERROR + ". < Life : init() > " +
                              UNRECOVERABLE_ERROR);
            return;
        }
        // Now we instantiate variables:
                              
        vars  = new Vars(parentFrame, objects.GetScreenLocations());  /* All of
                                                                 our non-global,
                                 "Must use 'get' and 'set' methods" variables
                                live in here.
                                                                       * 
                                Note: This is "new'd" in one and only one
                                place -- here. It is passed around our children,
                                and from our children to their children, and
                                this is the one and only master copy.

                                Note it requires the parent frame. This is a
                                must at instantiation; see the code of
                                < Vars.java >.

           Get & set dimensions & location. The "variables" class < vars > 
           *must* know width & height, or truly horrible things happen.
           We would not be able to set board parameters such as default 
           number of rows & columns.
        */
        vars.SetAppletWidth (appletSize.x);
        vars.SetAppletHeight(appletSize.y);

         // We must feed several cross references:

         objects.GetScreenLocations().SetVars(vars);
         objects.GetPaintBoardAndComputeNextGeneration().SetVars(vars);
         objects.GetGenNum().SetVars(vars);

         buttons = objects.GetButtons();    // We use buttons a lot, and maintain
                                            // our own copy of the buttons object.

         error = new PopupWindow(parentFrame, objects.GetScreenLocations(), ERROR_WINDOW_NAME);

        // Give the buttons action listeners:

        buttons.GetKeepGoingButton().addActionListener(this);
        buttons.GetEditGameButton() .addActionListener(this);
        buttons.GetQuitGameButton() .addActionListener(this);

        // Set the cursor later.

        // Define the gridbag layout where all this stuff will be set:

        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints constraints = new GridBagConstraints();
        setLayout(gridbag);

        // First set the canvas on which we paint the board:

        buildConstraints(constraints, 0,0,   // At column - row (0, 0)
                                      1,4,   // One column, three rows
                                      94,0,  // Eats most of the column,
                                             // all of the rows.
                                      1,     // Almost no
                                      1);    // padding
        constraints.fill = GridBagConstraints.NONE;
        constraints.anchor = GridBagConstraints.WEST;   // On left side 
                                                        // of board.

        gridbag.setConstraints(objects.GetPaintBoardAndComputeNextGeneration(),
                               constraints);  /* Set  contraints  for
                                                 < paintBoard > canvas  */

        /* Now define how the gridbag allocates components: 
           the generation number text field < genNum >, and the 
           buttons < keepGoingButton >and < editGameButton >.         */

        buildConstraints(constraints, 1,0, // Column two, row one
                                      1,1, // One row, one column
                                      2,33,// Little of the column, 
                                           // all of the row
                                      1,   // Almost no
                                      1);  // padding

        constraints.fill = GridBagConstraints.NONE;
        constraints.anchor = GridBagConstraints.WEST;  // On right side.

        gridbag.setConstraints(objects.GetGenNum(), constraints);  /* Set
                                                                 contraints for
                                                                 generation 
                                                                 number text
                                                                 field      */
        buildConstraints(constraints, 1,1,     // Column two, row two
                                      1,1,     // One row, one column
                                      2,33,    // Little of the column,
                                               // all of the row
                                      SMALL_PADDING,        // Thin
                                      SMALL_PADDING);       // padding         

        constraints.fill = GridBagConstraints.NONE;
        constraints.anchor = GridBagConstraints.EAST;  // On right side.

        gridbag.setConstraints(buttons.GetKeepGoingButton(), constraints);/* Set 
                                                            contraints 
                                            for "keep going" button    */

        buildConstraints(constraints, 1,2,    // Column two, row three
                                      1,1,    // One row, one column
                                      2,33,   // Little of the column, 
                                              // all of the row
                                      SMALL_PADDING,        // Thin
                                      SMALL_PADDING);       // padding
        constraints.fill = GridBagConstraints.NONE;
        constraints.anchor = GridBagConstraints.EAST;  // On right side.

        gridbag.setConstraints(buttons.GetEditGameButton(), constraints); /* Set 
                                                          contraints 
                                          for "Edit game?" button   */
        
        buildConstraints(constraints, 1,3,     // Column two, row four
                                      1,1,     // One row, one column
                                      2,33,   // Little of the column, 
                                               // all of the row
                                      SMALL_PADDING,        // Thin
                                      SMALL_PADDING);       // padding
        constraints.fill = GridBagConstraints.NONE;
        constraints.anchor = GridBagConstraints.EAST;  // On right side.

        gridbag.setConstraints(buttons.GetQuitGameButton(), constraints); /* Set 
                                                          contraints 
                                          for "Quit game?" button   */
        // Add our widgets:

        add(objects.GetPaintBoardAndComputeNextGeneration());
        add(objects.GetGenNum());
        add(buttons.GetKeepGoingButton());
        add(buttons.GetEditGameButton());
        add(buttons.GetQuitGameButton());

       // Register event listeners:

        addMouseListener(this);      
        addMouseMotionListener(this);

        appletSize = null;  // Ready to garbage collect.
        }
        // Declarations of methods that must be over-ridden follow:

    public void mousePressed (MouseEvent e) {}  // Declare
    public void mouseReleased(MouseEvent e) {}  // these; we
    public void mouseExited  (MouseEvent e) {}  // don't use them
    public void mouseEntered (MouseEvent e) {}  // and give them  
    public void mouseDragged (MouseEvent e) {}  // null bodies.
    
    // Note: routine < mouseMoved(MouseEvent e) > defined below.

/*******************************************************************
    The "run" method contains the real guts of the applet, and
    deserves more attention than the short routines.
******************************************************************** */

   public void run()
   {
        /* Next handles questions for user when a game has ended. It takes
           a < this > pointer to have access to the < buttons > parameter
           and the parent frame. No-one else uses this class.
        */
        HandleGamesEnd handleGamesEnd = new HandleGamesEnd(objects);
       /* First paint everybody to the screen to avoid "not painted
          to the screen" errors the writer encountered using Linux. */
        String errorStr = "";
        try
        {
            // Religiously check input:
            
            if ((objects.GetGenNum()                             == null) ||
                (objects.GetPaintBoardAndComputeNextGeneration() == null) ||
                (buttons.GetKeepGoingButton()                    == null) ||
                (buttons.GetEditGameButton()                     == null) ||
                (buttons.GetQuitGameButton()                     == null))
                {
                    errorStr += (objects.GetGenNum() == null) ? "Gen Num null " : NULL_STRING;

                    errorStr += (objects.GetPaintBoardAndComputeNextGeneration() == null) ? 
                                     "PaintBoardAndComputeNextGeneration null " : NULL_STRING;

                    errorStr += (buttons.GetKeepGoingButton() == null) ? 
                                            "Keep going button null " : NULL_STRING;

                    errorStr += (buttons.GetEditGameButton() == null) ? 
                                            "Edit Game Button null " : NULL_STRING;

                    errorStr += (buttons.GetQuitGameButton() == null) ?
                                            "Quit Game Button null " : NULL_STRING;

                    throw new NullPointerException(errorStr);
                }
        // Paint the generation number.
            objects.GetGenNum().paint(offScreenGraphics);
                    objects.GetGenNum().                            repaint();
                    objects.GetPaintBoardAndComputeNextGeneration().repaint();
                    buttons.GetKeepGoingButton().                   repaint();
                    buttons.GetEditGameButton().                    repaint();
                    buttons.GetQuitGameButton().                    repaint();
                    greyOutScreen();
                    waitForPaint();

                }
                catch (NullPointerException e)
                {
                    String err = "Null pointer, top of < run() >, in < Life >?" + 
                                        e.toString() + "error string: " + errorStr;
                    error.ShowMessage(err, 
                                        OK);            // Button.
                }
        greyOutScreen();    // For good
        waitForPaint();     // measure.

        /* On the next: Everyone was working hunky-dory, then I tried a screen
           refresh. In short, screen locations were a mess. This saves "good"
           locations,
        */
        setLocationsInCaseOfScreenRefresh();

        /* Now we have set our components and painted ourself, tell
           the variables class < vars > where we are.
        */
        try
        {
            vars.SetAppletLocation(this.getLocationOnScreen());
        }
        catch (Exception e)
        {
            System.out.println("Could not set location on screen, < Life > ?!"
                               + e.toString());
        }

        /* Fudge explain: I couldn't get the blasted canvas to work
           just right, no matter what Java books I consulted. I resort to
           the next to force the canvas's (plural and possessive) size.

           Set sizes of components:
        */
        try
        {
            objects.GetPaintBoardAndComputeNextGeneration().setSize(
                                          vars.GetBoardWidth()
                                        + PIXELS_TO_SKIP_FROM_LEFT_SIDE_OF_BOARD, 
                                          vars.GetBoardHeight());

            objects.GetGenNum().setSize(4*GENERATION_NUMBER_FONT_SIZE,
                                        GENERATION_NUMBER_FONT_SIZE);
        }
        catch (Exception e)
        {
            String err = e.toString()+" Could not set size, < Life >?!";
            System.out.println(err);
            return;
        }

        /* One of the first things we must do is determine screen 
           locations. This is so when we paint no-one paints over 
           someone else, & in determining sizes.
        */
        pause(TIME_TO_WAIT_FOR_BUTTON_CLICK);
        objects.GetScreenLocations().
                          SetBoardWidthAndHeightAndComponentPositions(objects);

        /* Now we know where things are, we set default values of things
           like rows and columns.
        */
        objects.GetInitializations().SetDefaults(vars);
/*
        error.ShowMessage("" + buttons.GetKeepGoingButton().getSize(), OK);
        error.ShowMessage("" + buttons.GetEditGameButton().getSize(), OK);
        error.ShowMessage("" + buttons.GetQuitGameButton().getSize(), OK);
        error.ShowMessage("" + objects.GetGenNum().getSize(), OK);
*/
        // Several local variables follow:

        buttons.HideButtons();  /* Make the buttons disappear for now. They had
                                   to be visible to determine their locations.
                                */
        beforeFirstGame();
        
        greyOutScreen();
        /* Now for the main loop: this loops on whether the player 
           wishes to play. As soon as the user no longer
           wishes to  play, we get out.                     
        */

        MainLoop: while (playAgain)
        {
            HandleLoop mainLoop = handleFirstGame(handleGamesEnd);
            if (mainLoop == HandleLoop.BREAK_MAIN_LOOP)
            {
                break MainLoop;
            }
            else if (mainLoop == HandleLoop.CONTINUE_MAIN_LOOP)
            {
                continue MainLoop;
            }
            else if (mainLoop == HandleLoop.KEEP_GOING_MAIN_LOOP)
            {
                ; // Do nothing.  Keep going.
            }
            else
            {
                System.out.println("Something horrible has happened, value" +
                                   " of mainLoop = " + mainLoop);
            }
            /* Set a boolean that governs the game -- if it changes
               value (see test of the < while > loop directly below)
               it's over:
            */
            boolean keepGoing = true;

        /*  Why do we define the next two threads? 
        
            First: Note that between generations, we need to do two things:
               
                1) Compute next generation
                2) Wait for either a time delay or the
                   user to click the "Continue" button.

            If we don't use the thread (notably when the pixels
            per cell is small and there are lots of rows & columns,
            then the next generation computations get CPU-intensive),
            we would wait, say, one second, and wait to compute
            the next generation, and the user would wonder, "Why
            aren't things moving as fast as I input them to?" Or
            the user could wonder, "Why doesn't the next generation
            pop right up when I click the "Continue" button?

            Note this isn't perfect. If the user uses a time
            delay of close to zero seconds, there isn't much 
            we can do. But if there is time, we use it
            in computing the next generation and setting up the
            off-screen graphics to be ready to display it at
            the instant < waitForPaint() > is called.

            Note we initialize it to null. This is to shut up
            "may not have been initialized" errors in a try-catch
            clause below.

            On the "time to sleep" thread: we "pause" on a separate
            thread, and if in the middle if a "pause" somewhere, the
            user requests either to edit the game or quit, we simply
            stop the thread.
        */
            singleGenerationThread = null;
            timeToSleepThread      = null;

            /* Note the loop is named: "playASingleGame." Break statements are
               hence more understandable.
            */
            boolean firstGeneration = true; // First generation.
            keepGoing               = true; // Continue game?
            singleGenerationThread = new HandleASingleGeneration(vars, 
                                                                 objects, 
                                                                 offScreenGraphics);

            playASingleGame : while (keepGoing && !buttons.GetQuitButtonClicked())
            {
//                if (!firstPass)   /* Two reasons: Don't paint first generation
//                                     twice, and, this makes things work properly
//                                     under Windows NT.
//                                     
//                                    I hope ... need to test it at work.
//                                  */
//                {
//                    PaintTheBoardAndComputeNextGeneration(vars);
//                    firstPass = false;
//                } 
                if (!firstGeneration) // We have already painted first generation.
                {
                    waitForPaint();  // Note we repaint at top.
                }
                pause(TIME_TO_WAIT_FOR_PAINTING);
                buttons.SetEditGameButtonClicked(false);   // Set false
                buttons.SetQuitButtonClicked    (false);   // for good
                buttons.SetContinueButtonClicked(false);   // measure.

                /* Set buttons's cursors for this game. They may have
                   changed if we edited the board.
                */
                buttons.SetButtonsForThisGame(vars);

            // See above documentation on next object, a thread.
                /* On the next: If we wait for a time delay between generations,
                   we set a time delay. Otherwise, we are waiting for a button 
                   click, and set zero time.

                   But note:
                   
                */
                int delay;  // How long we wait. May be zero milliseconds -- see next.

            /* The next boolean decision is bothersome. I will at least 
               document the confusion.

                1) If we are waiting for a time delay we are on the first or second 
                   generation, and , we already waited once in routine 
                   < setInitialBoard >, and have already computed the second 
                   generation due to how class < PaintBoardAndComputeNextGeneration > 
                   works -- this was the pause to go from first to second generation.
                   If we just edited the board, don't wait. Don't repeat it. Fall
                   into the "else" clause. 

                3) If we just edited the board and wait for a time delay, set this 
                   wait.

                4) Or if it is first pass, and there is a time delay, AND
                   we clicked on "alive" cells, we haven't waited yet. We
                   did not do it in routine < setInitialBoard >. Do it now.
            */
                if (vars.GetWaitForTimeDelay() && 
                   (vars.GetGenerationNumber() > 2)  && 
                   !vars.GetJustEditedBoard()  ||

                   (firstGeneration            && 
                    vars.GetWaitForTimeDelay() &&
                    vars.GetClickLiveCellsViaMouse()))
                {
                    delay = vars.GetTimeBetweenGenerations();
                }
                else    // Set zero time. Thread will return immediately.
                {
                    delay = 0;
                }
                // But we're not done yet. We allocate time for painting;
                // deduct it or zero the time:

                delay = (delay <=TIME_TO_WAIT_FOR_PAINTING) ? 
                            0 : delay - TIME_TO_WAIT_FOR_PAINTING;

                timeToSleepThread = new Pause(delay);

        /*  Start the thread & wait for either a button click
            or a time delay.

            Note there are no problems with critical
            sections -- one piece of code is doing
            computations, the other is sleeping.
        */
                try
                {
                    if (vars.GetGenerationNumber() == 1)
                    {
                        singleGenerationThread.start();  // Sub-thread.
                    }
                    else
                    {
                      //  singleGenerationThread.resume(); // If suspended.
                        
                        singleGenerationThread.SetDoneWithCurrentGeneration(false);
                        singleGenerationThread.run();
                    }
                    timeToSleepThread.start();

                /* Now: if we are waiting for a button click, we must make
                   a decision.

                        1) If we are not on the first generation, and, we did
                           not just edit the board, wait for a button click.

                        2) "Else" clause is: it's either the first generation,
                           or we just edited the board. Either way, we just waited
                           for a button click. Fake it.
                */
                    if (!vars.GetWaitForTimeDelay())
                    {
                        if ((vars.GetGenerationNumber() > 2) && !vars.GetJustEditedBoard())
                        {
                            waitForButtonClick();
                        }
                        else
                        {
                            buttons.SetContinueButtonClicked(true);
                        }
                    }
                    vars.SetJustEditedBoard(false);    // Re-set in case it changed.

                     /* Now we wait for our two threads: while either is alive, AND,
                        the user has not pressed the "quit game" or "edit game" 
                        button, we wait.
                     */
                    waitForThreadsOrAStopOrder(timeToSleepThread,
                                               singleGenerationThread,
                                               vars);

                    // Paint the generation number.
                    objects.GetGenNum().paint(offScreenGraphics);

                }// End "try" clause.
                catch (ThreadDeath threadDead){ /* Do nothing */ }

                // If the user pressed the "quit" button, this supercedes all else.

                if (buttons.GetQuitButtonClicked()) // User wants out.
                {
                    break playASingleGame;
                }
            /* Thread's outcome? If thread finished naturally,
               next reflects the state of the board, i.e.,
               "keep going; all is well" or "quit, all cells dead or we
               are in a repeating pattern." If thread was interrupted 
               by the setting of < editGameButtonClicked >, it 
               doesn't matter; see first statement of next block. 
            */
                keepGoing = singleGenerationThread.KeepGoing();

                /* If we don't edit the game, and we don't quit,
                   we return to the top of the < playASingleGame > 
                   loop.

                   Note: next block has bothersome coding, violating the
                   if-the-else rule of coding, but the writer saw no nice
                   way out. So we do apple-and-oranges comparisons.
                */
                if (buttons.GetEditGameButtonClicked())   /* Has the user decided to 
                                                             edit the game?          */
                {
                    keepGoing = true;   /* What if everyone died? Or the pattern was
                                           found repeating? The user has decided to
                                           edit the game. This takes precedence.
                                        */
                    handleEditingOfGame(vars);  // Handles editing of board. Which see.

                    if (!buttons.GetQuitButtonClicked()) // User didn't quit?
                    {
                    /* Set buttons's cursors. These may have changed when we
                       set the board by mouse clicks. The passed boolean tells
                       the routine how to handle the "Continue" button.
                    */
                        buttons.SetButtonsForThisGame(vars);

                        /* Do NOT updated the board, as we do below in the next
                           block for the "Continue" and "Wait for time delay"
                           buttons's case. We now have a new board, and it lives
                           in < thisGeneration >. We will return to the top
                           of the < playASingleGame > loop, and then compute
                           the next generation.                               */
                    }
                    else    // User clicked "quit" button while editing.
                    {
                        break playASingleGame;  // End the current game.
                    }
                }
                /* On the next: If we are waiting for button clicks, and the
                   "Continue" button has been clicked, or, if we set a time
                   delay (now passed), we set current board to next generation.
                */
                else if ((buttons.GetContinueButtonClicked() || vars.GetWaitForTimeDelay()) && 
                          keepGoing)
                                        /* We are keeping the next generation in
                                           parameter < nextGeneration > as set in object 
                                           < singleGenerationThread >, not changing it.  */
                {
            /* Now set next generation in < oldBoards >.
               Note the modular arithmetic in next. Generations 
               divisible by < oldBoards.length > get the 0-index, 
               < oldBoards[0][][] >.
            */
                    objects.GetBoardUtilities().SetFirstToSecond(
                                             vars.GetOldBoards()[
                                            (vars.GetGenerationNumber()%vars.GetOldBoards().length)
                                                                ],
                                             vars.GetThisGeneration(),
                                             vars.GetRows(),
                                             vars.GetColumns());

                    vars.BumpGenerationNumber(); // Next generation.
                    /* Now set < thisGeneration > to < nextGeneration >, the next 
                       generation. We are NOT blowing away the next generation.
                    */
                    objects.GetBoardUtilities().SetFirstToSecond(vars.GetThisGeneration(), 
                                                              vars.GetNextGeneration(),
                                                              vars.GetRows(), 
                                                              vars.GetColumns());
                   
                    singleGenerationThread.SetDoneWithCurrentGeneration(false);
                //    singleGenerationThread.suspend(); // This thread's work is done for now.
                }
                // End bad apples-and-oranges coding.

                firstGeneration = false;    // No longer first generation by now.

                /* Note we paint at the top of < playASingleGame > loop.
                */
            }   // End < playASingleGame > loop.

            /* When we get here, the current game is over.

               Note that if the pattern repeats, we leave it on the screen.
               Otherwise we blow it away, "not interesting" -- everyone dead or
               the user requested a stop.
            */
                if (objects.GetRepeatPattern().GetPeriod() == PATTERN_DOES_NOT_REPEAT)
                {
                    greyOutScreen();       // Clean up the
                    waitForPaint();             // screen.
                }
                buttons.HideButtons();      // Make the buttons disappear for now.
                playAgain = handleGamesEnd.PlayAgain(singleGenerationThread,
                                                     numberOfGames);
                                                     
                singleGenerationThread = null;  // Get rid of these for the 
                timeToSleepThread      = null;  // sake of garbage collection.
                
                garbageCollect();           // Suggest to the JVM that we garbage collect.
         }  // End "while (playAgain)" loop.
            // When we get here, it means the user is playing no more games

         killApp();    // The last roundup.
    }                  // End routine  run()
   
// Done with main code; time for subroutines & a class at the end.

/*******************************************************************
    Nonsense that needs done before first game.  Shoved in subroutine
    for modularity.
******************************************************************** */
   private void beforeFirstGame()
   {
       /* Now give some initial information to the user. The next used
          object, < UI ui >, tells the user the rules and calls 
          another routine that asks for input of what the user wants, 
          i.e., things like how many rows and columns.
       */
       try
       {
            /* Next sets default values in all of our children. 
                This also instantiates boards.
            */
            objects.GetInitializations().InitializeEveryone(vars, objects);

            /* The next fires up a question, "Do you wish to see 
               the instructions?" If the answer is a "yes," the UI code in
               object < ui > presents the rules of the game.

               This is intentionally "invisible" to the main program.
            */
            objects.GetUi().AskIfUserWantsToSeeInstructionsOrQuit(vars);
            
            didUIRequestQuit(); // If a quit is requested, entire application
                                // is killed.  Road is no return.
           
            if (objects.GetUi().UserWantsToSeeInstructions())
            {
                // We show the user a few boards.

                showTheUserAFewBoards(vars);

                /* Show the rest of the instructions, a discussion of 
                  the UI presented in 
                  < ui.ShowUserInterfaceInstructions() >:
               */
                greyOutScreen();  // Clear all screen graphics.

                objects.GetUi().ShowUserInterfaceInstructions(vars); // Show
                                                                // instructions.
                // Same exact code as above follows, so short did not make
                // a subroutine:
                didUIRequestQuit(); // If a quit is requested, entire application
             }                     // is killed.  Road is no return.
       }
       catch (NullPointerException e)  // Pointer null?!?!
       {
           String errorStr = "objects = " + objects + "objects.GetUi() = " +
                                            objects.GetUi() +
                          "objects.GetInitializations() = " + 
                          objects.GetInitializations();
           error.ShowMessage(POINTER_NULL + " " + IN + " " +
                            "< Life run() >?!?! " + errorStr, OK);
       }
   }

/*******************************************************************
    Nonsense that needs done to get first game off the ground.
    Shoved in subroutine for modularity.
******************************************************************** */

   private HandleLoop handleFirstGame(HandleGamesEnd handleGamesEnd)
   {
            HandleLoop breakMainLoop = HandleLoop.KEEP_GOING_MAIN_LOOP;
            numberOfGames++;       // Keep track of which game we are on.
            vars.SetGenerationNumber(1); // Start generations at one.

            if ((firstGame) ||         // On first game, or ...
                (handleGamesEnd.GameChanged())) // Not first game, but changed
                                                // from last game.
            {
                firstGame = false;
                // Next returns < false > if we do not play, otherwise 
                // we simply keep going.
                
                if (!objects.GetUi().GetGameParametersScreen(vars)) /* Fires up
                                                                   the big UI */ 
                {                                   // that gets gameparameters. 
                     return HandleLoop.BREAK_MAIN_LOOP; // Get out.         
                }                                                  
            }   // End "if ((firstGame) ||  .... " block.
            /* The next routine hides a multiplicity of sins, using the
               values obtained in routine < getGameParameters >: making
               the boards, and initializing objects so they know things
               like how many rows and columns the board has, and number
               of pixels. It also nulls out the boards.
            */
            objects.GetInitializations().InitializeEveryone(vars, objects);

            /* Set the initial board. Next calls routine
               < PaintTheBoardAndComputeNextGeneration > to paint
               the initial board.
            */
            setInitialBoard(vars);

        /* If we set the initial board and the user did not request that
           we get out, we simply fall through. But if the user requested
           to get out, we ask, "Play again?"
        */
            if (buttons.GetQuitButtonClicked())  // User requested a "quit?"
            {
                greyOutScreen();                    // Get rid of any
                waitForPaint();                     // graphics on the screen.

                /* Note we pass a null parameter to the "Keep playing?" class. 
                   The parameter of type < HandleASingleGeneration > has not
                   been yet instantiated. We don't need it for this call.
                */

                playAgain = handleGamesEnd.PlayAgain(numberOfGames);
                
                // Done with "first game" code.  From here on out we have played
                // at least one.

                if (playAgain)
                {
                    buttons.SetQuitButtonClicked(false);   // Re-null it.
                    breakMainLoop = HandleLoop.CONTINUE_MAIN_LOOP;    // Re-start top
                }                                          // everything,
                                                           // top of loop
                else
                {
                    breakMainLoop = HandleLoop.BREAK_MAIN_LOOP;     // Get out entirely.
                }
            }   // End of block, "user never wanted this game in the first place."
            return breakMainLoop;
   }
/*******************************************************************
    Next sets the board at the start of a game. We define this for
    modularity so as to not clutter the main code.
******************************************************************** */

    private void setInitialBoard(Vars vars)
    {
        vars.SetGenerationNumber(1);
        // Paint the generation number.
        objects.GetGenNum().paint(offScreenGraphics);
            /* Now we set initial "alive" and "dead" cells on board.

                Why do we define the next boolean? We save old values, 
                as they are set as defaults in going from one game to
                another. So we use a temp boolean. Thing is, if the 
                user sets the board probalistically and then decides 
                to edit it, we need to run the next < while > loop
                again. We don't want to blow away the current value 
                of < clickLiveCellsViaMouse >, so set it in a temp 
                boolean.

                Bothersome coding, yes. But otherwise there might be a 
                subtle bug -- the value of < clickLiveCellsViaMouse > 
                could change, and the changed value would set as a 
                board default on next game's pass.
            */
        boolean clickOnCells = vars.GetClickLiveCellsViaMouse();

        /* Which buttons do we set? This needs two parameters to
            make its decision; see the routine
            < SetWhichButtonsAreVisibleBeforeSettingBoard > in
            class < HandleButtons > for more.
        */
        buttons.SetWhichButtonsAreVisibleBeforeSettingBoard(vars);
        setBoardLoop : while(true) // The loop goes until user quits.
        {
            buttons.SetEditGameButtonClicked(false);    // Null
            buttons.SetContinueButtonClicked(false);    // these
            buttons.SetQuitButtonClicked    (false);    // flags.

            if (clickOnCells)
            {
                setBoardByMouseClicks(vars, objects); // Decide board by clicking.
                break setBoardLoop;          // Get out.
            }
            else    // Decide game probalistically.
            {
                buttons.GetKeepGoingButton().setLabel(START_GAME);  // Change this button accordingly.
                objects.GetInitializations().Probalistic(vars.GetThisGeneration(), 
                                                    vars.GetProbability(), 
                                                    vars.GetRows(), vars.GetColumns());
                greyOutScreen();    // Grey out screen.

                    /* Now we have set the initial board, it's time to set up the 
                    off-screen graphics & show the current board, as delineated
                    in class
                    < setUpOffScreenGraphicsForPrintingBoard drawOffScreenGraphics >.
                    */
                PaintTheBoardAndComputeNextGeneration(objects);
                waitForPaint();

                /* On the next: If we wait for a time delay between generations,
                    we set it. Otherwise, we are waiting for a button click, and
                    set zero time.
                */
                Pause timeToSleepThread = new Pause(
                            vars.GetWaitForTimeDelay() ? vars.GetTimeBetweenGenerations() : 0);

                timeToSleepThread.start();   /* Start sleeping -- could be zero time;
                                                see above.
                                            */
                if (!vars.GetWaitForTimeDelay()) // Are we waiting for a button click?
                {
                    waitForButtonClick();
                }
                else    /* Note if we set time zero above, < timeToSleepThread.isAlive() >
                        will be < false > now or pretty fast.                    */
                {
                    while (timeToSleepThread.isAlive() &&   // Thread running?
                        !buttons.GetQuitButtonClicked() &&               // Didn't click
                        !buttons.GetEditGameButtonClicked())             // these buttons?
                    {
                        pause(TIME_TO_WAIT_FOR_THREADS);
                    }
                    timeToSleepThread.stop();   // Just in case this is still running.

                    /* If the time delay thread died and no buttons were clicked,
                    get out.
                    */
                    if (!buttons.GetQuitButtonClicked() && !buttons.GetEditGameButtonClicked())
                    {
                        break setBoardLoop;
                    }
                }
                /* By now there has been a time delay and / or a button click.
                   We have to handle all button possibilites.
                */
                if (buttons.GetContinueButtonClicked())  // It only makes sense to check for this if the
                {                           // the user is going from generation to
                    break setBoardLoop;     // generation via mouse clicks, but this check
                }                           // will cause no problems if there is a time delay.
                else if (buttons.GetQuitButtonClicked())
                {
                    timeToSleepThread.stop();   /* Stop the "sleep" thread,
                                                   if it is running.
                                                */
                    break setBoardLoop; // Get out.
                }
                else if (buttons.GetEditGameButtonClicked())  /* We are going through the 
                                            loop again. If we did it 
                probalistically at first, now we do it via mouse
                clicks. Otherwise the user would get a new
                probalistic setting.                         */
                {
                    timeToSleepThread.stop(); // Stop the "sleep" thread, if it is running.
                    clickOnCells = true;
                }
                // No more buttons to handle. The user simply waited for a timeout.
            }  // End "decide the game probalistically" block.
        }      // End "setBoardLoop : while(true)" loop.

        buttons.GetKeepGoingButton().setLabel(CONTINUE);  // Change this button accordingly.

        /* Set the first old board. We use the call to < vars.GetGenerationNumber() > for
           good measure; this will be one.
        */
        objects.GetBoardUtilities().SetFirstToSecond(
                                                vars.GetOldBoards()[vars.GetGenerationNumber()], // One.
                                                vars.GetNextGeneration(),
                                                vars.GetRows(),
                                                vars.GetColumns());
    }

/*******************************************************************
    Next handles the editing of the board. It primarily exists
    for modularity.
******************************************************************** */

    private void handleEditingOfGame(Vars vars)
    {
        /* This code tries to think ahead. We must backtrack.
           Generations are backed up one. All generations.
        */
        objects.GetBoardUtilities().SetFirstToSecond(vars.GetNextGeneration(), 
                                                  vars.GetThisGeneration(), 
                                                  vars.GetRows(), 
                                                  vars.GetColumns());

        objects.GetBoardUtilities().SetFirstToSecond(vars.GetThisGeneration(), 
                                                  vars.GetLastGeneration(), 
                                                  vars.GetRows(), 
                                                  vars.GetColumns());
        /* Blow away < oldBoards > entirely.

            Why? The board has changed from its "natural"
            pattern. For example, the user could edit a single
            cell due to die on the edge, away from what would be a
            repeating pattern. The cell dies; the rest of the
            pattern repeats, and the user is told that the pattern
            with the single cell due to die is repeating?
        */
        objects.GetInitializations().NullOutOldBoards(vars);

        // Now drop the generation number:

        vars.SetGenerationNumber(vars.GetGenerationNumber() - 1);

        // Now set by mouse clicks:

        setBoardByMouseClicks(vars, objects);
    }

/*******************************************************************
    Next sets the board by mouse clicks.

    Note the use of the < ManageBoardCoordinates boardCoordinates >.
    This takes care of managing board coordinates in one place, as
    class SetUpOffScreenGraphicsForPrintingBoard also uses board
    coordinates.
******************************************************************** */

    private void setBoardByMouseClicks(Vars vars, Objects objects)
    {
    if (buttons.GetQuitButtonClicked() || buttons.GetContinueButtonClicked())
                {  
                    return; // User wants out
                }
        // First get local copies of things we need.

        PaintBoardAndComputeNextGeneration paintBoardAndComputeNextGeneration =
                                    objects.GetPaintBoardAndComputeNextGeneration();
        ManageBoardCoordinates boardCoordinates = objects.GetBoardCoordinates();
        vars.SetEditingGame          (true);    // We are editing the game.
        buttons.SetContinueButtonClicked(false);   // Null these
        buttons.SetEditGameButtonClicked(false);   // for good
        buttons.SetQuitButtonClicked    (false);   // measure.
        if (vars.GetGenerationNumber() == 1)        // First generation?
        {
            buttons.GetKeepGoingButton().setLabel(START_GAME);  // Change this button accordingly.
        }
        else
        {
            buttons.GetKeepGoingButton().setLabel(QUIT_EDITING);  // Change this button accordingly.
        }
        /* We no longer need the "edit game" button -- we ARE editing
        the game. We must have the "Continue" button.
        */
        buttons.DeactivateEditGameButton();
                            /* Note: we need the "Continue" button. 
                            This may now have a "default" cursor,
                            so set it to an "active" cursor.
                            */
        buttons.ActivateKeepGoingButton();
        // Next are where the mouse is clicked. Local variables.

        int xVal = NOT_ON_BOARD, yVal = NOT_ON_BOARD;

        // Set the colors. All are same color now, and "about to come to life" is "dead."
        
        paintBoardAndComputeNextGeneration.setAliveColor(COLOR_ALIVE);
        paintBoardAndComputeNextGeneration.setSoonDeadColor(COLOR_ALIVE);
        paintBoardAndComputeNextGeneration.setAboutToComeToLifeColor(COLOR_DEAD);
        // Show the user the board:
        setBackground(COLOR_BACKGROUND);
        PaintTheBoardAndComputeNextGeneration(objects);
        waitForPaint();  // Paint board with a different color scheme.
        vars.SetMouseClicked(false);           // Set both of these
        buttons.SetContinueButtonClicked(false);  // for good measure.
        bigLoop: while ( (!buttons.GetContinueButtonClicked()) && ( !buttons.GetQuitButtonClicked()))
        {
            // We wait for a mouse click on the board.
            
            while (!vars.GetMouseClicked())
            {
                // We are waiting for the mouse to be clicked.
                if (buttons.GetQuitButtonClicked() || buttons.GetContinueButtonClicked())
                {
                    break bigLoop;  // Time to get out. Otherwise it is mouse
                }                   // input which we catch.
                 pause(50); // Sleep a short time -- nothing going on.
            }

            if (buttons.GetQuitButtonClicked() || buttons.GetContinueButtonClicked())
                { 
                    break bigLoop; // User wants out
                }
            // If we get here, we presume the mouse has been clicked.
            // Re-set it.
            vars.SetMouseClicked(false);
            if (buttons.GetQuitButtonClicked() || buttons.GetContinueButtonClicked())
            {
                break bigLoop; // User wants out
            }
            // Where on the board (board, not pixel coordinates) did the user click the mouse?

            Point where = boardCoordinates.PixelsToCoordinates(vars);
            xVal = (int) where.getX();                               // Point returns double,
            yVal = (int) where.getY();                               // requires cast.
            // Next question: where did the user click? Does it make 
            // sense as a cell? Was it on the board?
            
            if ((xVal == NOT_ON_BOARD) || (yVal == NOT_ON_BOARD))
            {
                ; // Do nothing.
            }
            else    // Value was on the board.
            {
                try // Be careful!
                {

                /* X-values go across. These are columns. Y-values go up and down.
                   These are rows. We usually refer arrays by things like 
                   "thisGeneration[x][y]," but the problem is obvious. This explains the 
                   seeming uncongruity of the "thisGeneration[yVal][xVal]" usage below.

                   Switch the cell, from "dead" to "alive" or vice-versa.  */        
                    {
                        vars.GetThisGeneration()[yVal][xVal] = 
                                    (vars.GetThisGeneration()[yVal][xVal] == 1) ? 0 : 1;
                    }
                }
                catch (ArrayIndexOutOfBoundsException e) // Array index out of bounds!?
                {
                    String errorStr =  ARRAY_BOUNDS_EXCEPTION + " " + IN + " " +
                                    " setBoardByMouseClicks: " + ROWS + " = " +
                                    vars.GetRows() + ", " + COLUMNS + " = " +
                                    vars.GetColumns() + ", xVal = " + xVal +
                                    ", " + AND + " " + " yVal = " + yVal + 
                                    ". " + ERROR_MESSAGE_COLON + " = " + 
                                    e.getMessage();
                    error.ShowMessage(errorStr, 
                                    OK);          // Button
                }
                /* Set the single pixel we change. Notably, after 
                   < paintBoard's > paint() routine is called, we
                   "default" to painting the entire board again.
                */
            paintBoardAndComputeNextGeneration.SetSingleCellToChange(xVal, yVal);
            // Now display the board as it is:
            setBackground(COLOR_BACKGROUND);
            PaintTheBoardAndComputeNextGeneration(objects); // Do this now ...
            waitForPaint();
            }                           // End of "else" clause.
        }                               // End "bigLoop"
        // When we get here we are done editing the board.
        // Re-set color scheme:

        paintBoardAndComputeNextGeneration.setAliveColor(COLOR_ALIVE);
        paintBoardAndComputeNextGeneration.setSoonDeadColor(COLOR_SOON_TO_DIE);
        paintBoardAndComputeNextGeneration.setAboutToComeToLifeColor(COLOR_ABOUT_TO_COME_TO_LIFE);

        vars.SetEditingGame(false);    // We are no longer editing the game. Get out.
        vars.SetJustEditedBoard(true); // But we did just edit the board. 

        buttons.GetKeepGoingButton().setLabel(CONTINUE);  // Re-set name of button.

        buttons.SetButtonsForThisGame(vars);  // Re-set all buttons to former values.

        waitForPaint();  // Show board.
    }

/*******************************************************************
    Next shows the user (who requests this) a few sample
    boards.
******************************************************************** */

/* This routine violates coding standards left and right via 
   the use of magic numbers.
*/
    private void showTheUserAFewBoards(Vars vars)
    {
        HandleASingleGeneration singleGenerationThread = null;
        Pause                   timeToSleepThread      = null;

        vars.SetGenerationNumber(1);  // For good measure.

        // Get a local copies of objects we use a lot:

        Initializations initializations = objects.GetInitializations();
        BoardUtilities boardUtilities = objects.GetBoardUtilities();
        int [][] thisGeneration = vars.GetThisGeneration();
        int[][] nextGeneration = vars.GetNextGeneration();
        int rows = vars.GetRows();
        int columns = vars.GetColumns();

        int i;                  // Loop variable.
        int rowVal, colVal;

        PopupWindow message = new PopupWindow(parentFrame, 
                                              objects.GetScreenLocations(),
                                              SAMPLE_BOARDS);

        if ((rows < MIN_DIMENSIONS_TO_DISPLAY_SAMPLE_BOARDS) || 
            (columns < MIN_DIMENSIONS_TO_DISPLAY_SAMPLE_BOARDS))
        {
            PopupWindow ms = new PopupWindow(parentFrame, 
                                             objects.GetScreenLocations(),
                                             BOARD_TOO_SMALL);

            ms.ShowMessage(BOARD_TOO_SMALL_TO_SHOW_SAMPLE_BOARDS, 
                           OK);                                 // Button
            return; // Board is too small to do anything, and we will 
                    // probably generate errors. Best just get out.
        }
    // We do things with both pointer and arrays. Use a try-catch clause.
    
        try
        {
            objects.GetInitializations().NullOutBoards(thisGeneration, nextGeneration);

            greyOutScreen();
            String [] stringArr = {OK, START_PLAYING, QUIT}; 
            message.ShowMessage(EXAMPLE_BOARDS_ONE_FOLLOW_SYMMETRY,
                                stringArr);   // Button.
            if ((message.WhichButtonWasPressed()).equals(START_PLAYING))
            {
                cleanUpAfterShowingBoards();
                return;
            }
            else if ((message.WhichButtonWasPressed()).equals(QUIT))
            {
                killApp(); 
            }

            // Set up the example:

            rowVal              = rows/2;
            colVal              = columns /2;
            thisGeneration[rowVal][colVal]       = 1; // This little routine
            thisGeneration[rowVal][colVal+1]     = 1; // initializes the
            thisGeneration[rowVal-1][colVal+2]   = 1; // board with a pattern.
            thisGeneration[rowVal-1][colVal-1]   = 1;
            thisGeneration[rowVal][colVal-1]     = 1; // The value one indicates an
            thisGeneration[rowVal+1][colVal]     = 1; // alive.

            for (i=1; i <= 35; i++) // A magic number, in violation of coding standards.
            {
                timeToSleepThread      = new Pause((int)(DEFAULT_SHORT_TIME_TO_PAUSE / i*i));
                singleGenerationThread = new HandleASingleGeneration(vars, 
                                                                     objects,
                                                                     offScreenGraphics);
                timeToSleepThread.start();
                singleGenerationThread.start();

                // Note buttons are turned off and no stop order may be issued.

                waitForThreadsOrAStopOrder(timeToSleepThread,
                                           singleGenerationThread,
                                           vars);

                // Now set thisGeneration to nextGeneration, the next generation.

                boardUtilities.SetFirstToSecond(thisGeneration, nextGeneration, rows, columns);
                setBackground(COLOR_BACKGROUND);
                waitForPaint();                                                                    // we go, hence "i*i"
                vars.BumpGenerationNumber();
            }
            greyOutScreen();
            waitForPaint();     // We have just cleared the board. Re-paint it.
            vars.SetGenerationNumber(1);
            objects.GetInitializations().NullOutBoards(thisGeneration, nextGeneration);

            message.ShowMessage(EXAMPLE_BOARDS_TWO_FOLLOW_REPEATING_PATTERNS,
                                stringArr);
            if ((message.WhichButtonWasPressed()).equals(START_PLAYING))
            {
                cleanUpAfterShowingBoards();
                return;
            }
            else if ((message.WhichButtonWasPressed()).equals(QUIT))
            {
                killApp(); 
            }                    

            // Set up second example:

            thisGeneration[1][3] = 1;    // Makes a pattern
            thisGeneration[2][3] = 1;    // that alternates
            thisGeneration[3][3] = 1;    // in two generations.

            int xBase = 6;
            int yBase = 6;
            thisGeneration[yBase]    [xBase]     = 1;
            thisGeneration[yBase + 1][xBase]     = 1;
            thisGeneration[yBase]    [xBase + 1] = 1;
            thisGeneration[yBase + 1][xBase + 1] = 1;

            rowVal = rows-5;
            colVal = columns/2;

            for (i = colVal; i<=colVal+2; i++)
            {
                thisGeneration[rowVal][i] = 1;
                thisGeneration[rowVal+5][i] = 1;
                thisGeneration[rowVal][i+6] = 1;
                thisGeneration[rowVal+5][i+6] = 1;
            }
            for (i = rowVal+2; i <= rowVal+4; i++)
            {
                thisGeneration[i][colVal- 2] = 1;
                thisGeneration[i][colVal+ 3] = 1;
                thisGeneration[i][colVal+ 5] = 1;
                thisGeneration[i][colVal+10] = 1;
            }
            for (i = 1; i <= 8; i++) // A magic number, in violation of coding standards.
            {
                timeToSleepThread      = new Pause((int)(DEFAULT_SHORT_TIME_TO_PAUSE / i*i));
                singleGenerationThread = new HandleASingleGeneration(vars, 
                                                                     objects,
                                                                     offScreenGraphics);
                timeToSleepThread.start();
                singleGenerationThread.start();

                // Note buttons are turned off and no stop order may be issued.

                waitForThreadsOrAStopOrder(timeToSleepThread,
                                           singleGenerationThread,
                                           vars);

                // Now set thisGeneration to nextGeneration, the next generation.

                boardUtilities.SetFirstToSecond(thisGeneration, nextGeneration, rows, columns);
                setBackground(COLOR_BACKGROUND);
                waitForPaint();                                                                    // we go, hence "i*i"
                vars.BumpGenerationNumber();
            }
            waitForPaint();     // We have just cleared the board. Re-paint it.
            vars.SetGenerationNumber(1);
            objects.GetInitializations().NullOutBoards(thisGeneration, nextGeneration);

            message.ShowMessage(EXAMPLE_BOARDS_THREE_FOLLOW_WALKERS,
                                stringArr);
            if ((message.WhichButtonWasPressed()).equals(START_PLAYING))
            {
                cleanUpAfterShowingBoards();
                return;
            }
            else if ((message.WhichButtonWasPressed()).equals(QUIT))
            {
                killApp(); 
            }                    
        // Set up the example:

            thisGeneration[3][1] = 1;
            thisGeneration[3][2] = 1;
            thisGeneration[3][3] = 1;
            thisGeneration[2][3] = 1;
            thisGeneration[1][2] = 1;

            for (i = 1 ; i <= 10; i++) // A magic number, in violation of coding standards.
            {
                timeToSleepThread      = new Pause(DEFAULT_SHORT_TIME_TO_PAUSE / i*i);
                singleGenerationThread = new HandleASingleGeneration(vars, 
                                                                     objects,
                                                                     offScreenGraphics);
                timeToSleepThread.start();
                singleGenerationThread.start();

                // Note buttons are turned off and no stop order may be issued.

                waitForThreadsOrAStopOrder(timeToSleepThread,
                                           singleGenerationThread,
                                           vars);

                // Now set thisGeneration to nextGeneration, the next generation.

                boardUtilities.SetFirstToSecond(thisGeneration, nextGeneration, rows, columns);
                setBackground(COLOR_BACKGROUND);
                waitForPaint();                                                                    // we go, hence "i*i"
                vars.BumpGenerationNumber();
            }
        }       // End "try" clause.
        catch (ArrayIndexOutOfBoundsException e)    // Array index out of bounds!?
        {
            String errorStr = e.getMessage();

            errorStr = errorStr + ARRAY_BOUNDS_EXCEPTION + 
                                  " < Life showTheUserAFewBoards >";
            error.ShowMessage(errorStr, 
                              OK);      // Button
        }
        catch (NullPointerException e)
        {
            error.ShowMessage(POINTER_NULL + ", < Life showTheUserAFewBoards >?!?!", 
                              OK);  // Button
        }
        cleanUpAfterShowingBoards();
    }

/* ******************************************************************
   ******************************************************************
    Done with "big" routines. We follow with the short routines.
*********************************************************************    
********************************************************************* */

/*******************************************************************
    The next handles the painting of our two canvases. Very short and
    simple.
******************************************************************** */

    private void PaintTheBoardAndComputeNextGeneration(Objects objects)
    {
        objects.GetGenNum().paint(offScreenGraphics); // Paint the generation number.
        objects.GetPaintBoardAndComputeNextGeneration().paint(offScreenGraphics); 
        // Does actual painting of the board.
    }

/*******************************************************************
    The next handles buttons.
******************************************************************** */

    public void actionPerformed(ActionEvent e)
    {
        // Nullify any previous action:
        buttons.SetContinueButtonClicked(false);
        buttons.SetEditGameButtonClicked(false);
        buttons.SetQuitButtonClicked(false);

        String buttonLabel = ((Button) e.getSource()).getLabel(); // Who was
                                                                  // punched?
        if(e.getSource() instanceof Button) // Had better be a button!
        {
            if (buttonLabel.equals(EDITGAME))
            {
                buttons.SetEditGameButtonClicked(true);
                StopThreads();
            }
            else if (buttonLabel.equals(QUIT_GAME))
            {
                buttons.SetQuitButtonClicked(true);
                StopThreads();
            }
            else if (buttonLabel.equals(CONTINUE) || 
                buttonLabel.equals(QUIT_EDITING)  ||
                buttonLabel.equals(START_GAME) )
            {
                buttons.SetContinueButtonClicked(true);
            }
            else
            {
                error.ShowMessage(UNRECOVERABLE_ERROR + " " +
                                  UNRECOGNIZED_BUTTON, 
                                  OK);                            // Button
            }
       }
       else
       {
            error.ShowMessage(UNRECOVERABLE_ERROR + " " +
                              INPUT_NOT_A_BUTTON + ".", 
                              OK);
       }
    }

/*******************************************************************
    Repeated code in *run* routine.  If UI user requests a "quit," kill
    entire application.
******************************************************************** */
private void didUIRequestQuit()
{
     if (objects.GetUi().Quit()) // Simply get out.
     {
         killApp();
     }
}

// Three paint-related routines follow: update, paint, and destroy.

/*******************************************************************
    Update routine follows.
******************************************************************** */

   public void update(Graphics g)
   {
        paint(g);
   }

/*******************************************************************
    Paint routine follows; this is standard Java.
******************************************************************** */    

   public void paint(Graphics g)
   {
        if (offScreenImage != null)
        {
            g.drawImage(offScreenImage, 0, 0, getBackground(),this);
        }
        synchronized(this) // No one else can mess with me now.
        {
            painted = true;
            notify();
        }
   }    // End paint routine.
    
/*******************************************************************
    The next gets rid of off-screen graphics. Clean-up.
******************************************************************** */    

    public void destroy()
    {
        offScreenGraphics.dispose();
    }    

/* ******************************************************************
    Next does nothing for a passed-in time. Short and brainless. Used
    when we don't need a threaded pause.
   ****************************************************************** */

   public void pause(int time)
   {
      try
      {
         { Thread.sleep(time); }  // Kill some time.
      }  
      catch (InterruptedException e)    // Should never, ever happen.
      {
        error.ShowMessage(INTERRUPTED_PAUSE,
                          OK);                    // Button
      }
   }

/*******************************************************************
        Next waits for threads or orders to stop.
*************************************************************** */

    private void waitForThreadsOrAStopOrder(Thread timeToSleepThread,
                                            HandleASingleGeneration singleGenerationThread,
                                            Vars vars)
    {
        try
        {
            while (!buttons.QuitOrEditButtonClicked() && /* If one of these buttons 
                                                            is clicked,  get out. */
                    (timeToSleepThread.isAlive() ||         // Still sleeping?
                    !singleGenerationThread.GetDoneWithCurrentGeneration())/* Waiting for next 
                                                                              generation to 
                                                                              be computed? */
                                                                          )    
            {
                pause(TIME_TO_WAIT_FOR_THREADS);  // Kill a little time.
            }
        }
        catch (ThreadDeath threadDead){ /* Do nothing */
        }
    }
/*******************************************************************
        Next stops all global threads.
*************************************************************** */
    private void StopThreads()
    {
        // Stop our children, if they are still running:
        if ((singleGenerationThread != null ) && (singleGenerationThread.isAlive()))
        {
            singleGenerationThread.stop();
        }
        if((timeToSleepThread != null) && (timeToSleepThread.isAlive()))
        {
            timeToSleepThread.stop();
        }
    }

/*******************************************************************
        Next builds Java constraints for GridBagLayouts. Short and brainless.
*************************************************************** */

   private void buildConstraints(GridBagConstraints gbc, int gx, int gy, 
                                 int gw, int gh, int wx, int wy, 
                                 int xPadding, int yPadding)
    {
        gbc.gridx       = gx;
        gbc.gridy       = gy;
        gbc.gridwidth   = gw;
        gbc.gridheight  = gh;
        gbc.weightx     = wx;
        gbc.weighty     = wy;
        gbc.ipadx       = xPadding;
        gbc.ipady       = yPadding;
    }

/* ******************************************************************
    Tells the main if the mouse has been clicked, and sets (x, y)
    coordinates of this in global variables.
********************************************************************* */  

    public void mouseClicked(MouseEvent e)
    {
        vars.SetMouseClicked(true);
        vars.SetMouseX(e.getX());// Where did user click mouse? Global variable.
        vars.SetMouseY(e.getY());// Where did user click mouse? Global variable.
    }
    
/*******************************************************************
    The next sets the cursor to "hand" in the following case: 
    
        1) we are editing the game (see the boolean test), and, 
        2) the cursor is in the board area. 
        
    Otherwise it is set to the "default" cursor.
******************************************************************** */

    public void mouseMoved(MouseEvent e) 
    {
        boolean varsNull = (vars != null);
        if (varsNull && vars.GetEditingGame())    // We only care about the 
                                                  // cursor if we are editing
        {                                         // the game

        // Next mess of boolean tests verify: is the cursor in the board area?

            if ((e.getX() > PIXELS_TO_SKIP_FROM_LEFT_SIDE_OF_BOARD) &&
                (e.getX() < PIXELS_TO_SKIP_FROM_LEFT_SIDE_OF_BOARD + 
                                vars.GetColumns()*vars.GetPixelsPerCell()) &&
                (e.getY() > PIXELS_TO_SKIP_FROM_TOP_AND_BOTTOM) &&
                (e.getY() < PIXELS_TO_SKIP_FROM_TOP_AND_BOTTOM + 
                                vars.GetRows()*vars.GetPixelsPerCell()))
            {
                setCursor(vars.GetHandCursor());
            }
            else
            {
                setCursor(vars.GetDefaultCursor());
            }
        }
        else
        {
            if (varsNull)
            {
                ; // Ignore it.
            }
        }
    }

/*******************************************************************
    Next waits for painting
******************************************************************** */

    private void waitForPaint()
    {
        painted = false;
        repaint();
        while (!painted)
        {
            try
            {
                pause(TIME_TO_WAIT_FOR_PAINTING);
            }
            catch (Exception e) {}
        }
    }

/*******************************************************************
    The next gets a parent frame for the main code.
******************************************************************** */

    public Frame getParentFrame()
    {
        Object anchorPoint = getParent();
            while (! (anchorPoint instanceof Frame))
            {
                anchorPoint = ((Component)anchorPoint).getParent();   
            }
        return ((Frame) anchorPoint);
    }

    private void setLocationsInCaseOfScreenRefresh()
    {
            // Default locations of widgets:

        int height = this.getSize().height;
        int offSet = (int) (height / 6);

        default_gen_num_location           = 
                    new Point(this.getSize().width - 
                            buttons.GetQuitGameButton().getSize().width,  height);

        default_keep_going_button_location = 
                    new Point(this.getSize().width - 
                            buttons.GetKeepGoingButton().getSize().width, height*2);

        default_edit_game_button_location  = 
                    new Point(this.getSize().width - 
                        buttons.GetEditGameButton().getSize().width, height*3);

        default_quit_game_button_location  = 
                    new Point(this.getSize().width - 
                        buttons.GetQuitGameButton().getSize().width, height*4);

        // The next sets are due to problems when re-loading the applet:

        vars.SetKeepGoingButtonLocation(default_keep_going_button_location);
        vars.SetQuitGameButtonLocation (default_quit_game_button_location);
        vars.SetEditGameButtonLocation (default_edit_game_button_location);
        vars.SetGenNumLocation         (default_gen_num_location);
    }

/*******************************************************************
    We wait for buttons to be pressed in so many 
    places, we have the following short routine to handle this.
******************************************************************** */    

    public void waitForButtonClick()
    {
        buttons.SetContinueButtonClicked(false);  // Set so we 
        buttons.SetEditGameButtonClicked(false);  // don't do
        buttons.SetQuitButtonClicked(false);  // anything naughty.
        while (!buttons.GetContinueButtonClicked() && 
               !buttons.GetEditGameButtonClicked() && 
               !buttons.GetQuitButtonClicked())
        {
            garbageCollect();
            pause(TIME_TO_WAIT_FOR_BUTTON_CLICK);  // Not long.
        }

    }

/*******************************************************************
    Next starts the thread. Short and brainless.
*************************************************************** */

    public void start()
    {
        if (runner == null) // Start the thread.
        {
            runner = new Thread(this);
            runner.start();
        }
    }
    
/*******************************************************************
    Next stops the thread. Short and brainless.
******************************************************************** */    
    
   public void stop()
   {
        if (runner != null)
        {
            runner.stop();
            runner = null;
        }
   }

/*******************************************************************
    Next gets rid of whatever is on the screen and greys it out.
******************************************************************** */

    private void greyOutScreen()
    {
        try
        {
            offScreenGraphics.clearRect(0,0, vars.GetAppletWidth(), vars.GetAppletHeight());
            offScreenGraphics.setColor(COLOR_BACKGROUND);                // Gray background.
            offScreenGraphics.fillRect(0,0, vars.GetAppletWidth(), vars.GetAppletHeight());
            waitForPaint();
        }
        catch (NullPointerException e)
        {
            String errorStr = "";
            errorStr += (vars == null) ? "vars null ? " : NULL_STRING;
            errorStr += (offScreenGraphics == null) ? "offScreenGraphics null ? " : NULL_STRING;

            System.out.println(e.toString() + " " + errorStr);
        }
    }
    private void cleanUpAfterShowingBoards()
    {
        pause(DEFAULT_SHORT_TIME_TO_PAUSE);
        objects.GetInitializations().NullOutBoards(vars.GetThisGeneration(), vars.GetNextGeneration());
        vars.SetGenerationNumber(1);
        greyOutScreen();
        garbageCollect();
    }
    private void killApp()
    {
        greyOutScreen(); 
        if (buttons != null)
        {
            buttons.HideButtons(); 
        }                      // Clean
        waitForPaint();        // screen.
        System.exit(0);        // The last roundup.
        garbageCollect();
    }
/*******************************************************************
    Next suggests to the JVM that we garbage collect, called at
    strategic times when this makes sense.  No guarantee it will 
    be called.
******************************************************************** */

    private void garbageCollect()
    {
        Runtime rt = Runtime.getRuntime();
        rt.gc();
    }
}