C:\upload\java\Life\source\java\HandleASingleGeneration.java
/*******************************************************************
    The next class < HandleASingleGeneration >, is a separate
    thread that does calculations while the game is either:

        1) Waiting for a button click, or
        2) Waiting for a time delay to expire.

    Aside from computing the next generation, painting the current
    generation and the generation number, it also does several things
    which must happen every generation:
    
        1) Find if anyone is still alive,
        2) Find if we are in a repeating pattern,
        3) Sets a boolean that communicates to our caller,
           "keep going?", depending upon the previous two, and
        4) Sets a string saying why we don't keep going, should
           this be the case, which is communicated back to our
           caller.
******************************************************************** */
 
import java.awt.*;

final class HandleASingleGeneration extends    Thread         // A thread!
                                    implements Constants,     // Holds program constants
                                               Strings        // Hold program strings
{
    private PopupWindow error;                  // For exceptions.

    private boolean keepGoing;                  // Is perhaps everyone dead, or are we in
                                                // a repeating pattern?
    private boolean doneWithCurrentGeneration;  // By name.
    private String  messageWhenTheGameIsOver;    /* Communicate this to patron
                                            if game is over. Contains a string
                                            saying why the game ended. */
// All further parameters are local copies of various game parameters,
// to speed up this time-consuming thread.
    Vars vars;
    
    private GenerationNumberCanvas genNum;      // Paints the generation number
    private BoardUtilities boardUtils;          // Various board routines
    private RepeatPattern repeat;               // Is the pattern repeating?

                                        /* Next does the real dirty work:
                                           paints current board and computes
                                           the next generation.
                                        */
    private PaintBoardAndComputeNextGeneration paintBoardAndComputeNextGeneration;

    private Graphics offScreenGraphics;         // What we paint to.
    
    private int rows;                           // Size of playing board -- rows
    private int columns;                        // Size of playing board -- columns

/*******************************************************************
    Constuctor follows:
******************************************************************** */

    HandleASingleGeneration(Vars vars, Objects objects, Graphics offScreenGraphics)
    {
        String errorString = ((vars != null)    && 
                              (objects != null) && 
                              (offScreenGraphics != null)) ? 
                             NULL_STRING : "vars = " + vars +
                             " objects = " + objects +
                             " offScreenGraphics = " + offScreenGraphics;
        if (!errorString.equals(NULL_STRING))
        {
            System.out.println("Error, null pointer, HandleASingleGeneration " + errorString);
            return;
        }
        this.vars = vars;
        doneWithCurrentGeneration = false;
        /* We make local copies of all parameters we need to
           increase speed of this time-consuming class.

           Note we don't use < vars > outside the constructor.
        */
        this.paintBoardAndComputeNextGeneration =
                               objects.GetPaintBoardAndComputeNextGeneration();

        this.genNum            = objects.GetGenNum();
        this.boardUtils        = objects.GetBoardUtilities();
        this.repeat            = objects.GetRepeatPattern();
        this.rows              = vars.GetRows();
        this.columns           = vars.GetColumns();
        this.offScreenGraphics = offScreenGraphics;

        error = new PopupWindow(vars.GetParentFrame(),
                                objects.GetScreenLocations(), 
                                ERROR_WINDOW_NAME);
            
        keepGoing = true;   /* Local parameter returned to caller
                               telling us if we keep going. Assume
                               for now that all is well & we continue.
                            */
        messageWhenTheGameIsOver = "";  // Null out for good measure.
    }

/*******************************************************************
    Routine < run() > follows:
******************************************************************** */

    public void run()
    {
      //  while(true)
        {
            if (!doneWithCurrentGeneration)
            {
                doJob(); // Defined next.
            }
            doneWithCurrentGeneration = true;
        /*    setPriority(MAX_PRIORITY);
            try
            {
                { Thread.sleep(1); }  // Kill some time.
            }  
            catch (InterruptedException e)    // Should never, never happen.
            {
                error.ShowMessage(INTERRUPTED_PAUSE,
                                OK);                    // Button
            }*/ 
        }
    }   // End < run() >
 
/*******************************************************************
    Routine < keepGoing() > follows. Tells caller if we 
    keep going.
******************************************************************** */

private final void doJob()
{
    // Paint the generation number. This is fed generation
    // number, as it needs no more parameters.

  genNum.paint(offScreenGraphics); // Paint the generation number.
        
    /*  Note next call is "big" and time-consuming.  We cram all the work
        of painting the board and computing the next generation into one
        call, as it is more efficient.  Both of these:

            1) Loop through entire board, and
            2) Call the AliveInNext() routine,

        so we put them together.
    */

    paintBoardAndComputeNextGeneration.paint(offScreenGraphics);
    // Is anyone alive? Handle "Everyone dead" case first (easier).

    if (!boardUtils.Alive(vars.GetNextGeneration(), rows, columns))  // Everyone is dead.
    {
        keepGoing = false;      // All dead.
 
        // Tell the user via a pop-up window
        messageWhenTheGameIsOver = ALL_CELLS_ARE_DEAD;
    }
    else   // Someone is alive.
    {
        // But wait. What if we are in a repeating pattern? 
        // Time to get out.

        if(repeat.DoesThePatternRepeat(vars.GetOldBoards(),
                                        vars.GetThisGeneration(),
                                        vars.GetGenerationNumber(),
                                        rows,
                                        columns))
        {                       // If we land in this block, the pattern repeats.
            keepGoing = false;
            int period = repeat.GetPeriod();    // Get pattern's period.
            if (period == PATTERN_DOES_NOT_REPEAT)
            {
                error.ShowMessage(PERIOD_NOT_PROPERLY_SET + 
                                    "< HandleASingleGeneration : run() >", 
                                    OK); // Button.
            }
            if (period == 1)    // Repeats every 
                                // generation.
            {
                messageWhenTheGameIsOver = PATTERN_REPEATS_EVERY_GENERATION;
            }
            else    // Plural -- repeats in two or more generations
            {
                messageWhenTheGameIsOver =  THIS_PATTERN_REPEATS_EVERY + " " +
                                            period + " " + GENERATIONS;
            }
        }
        else   // Someone is alive, and the pattern doesn't repeat.
        {
            keepGoing = true;   // Doesn't repeat. Keep going.
        }
    }   // End "else" clause, "someone is alive" code.
}

    protected final boolean KeepGoing()
    {
        return keepGoing;
    }

/*******************************************************************
    If pattern repeats, or if everyone is dead, send a string to the 
    caller, such as "This pattern repeats every generation without 
    change," or, "This pattern repeats every two generations," or,
    "Everyone dead."
******************************************************************** */

    protected final String GetGameEndString()
    {
        return messageWhenTheGameIsOver;
    }
    public final boolean GetDoneWithCurrentGeneration()
    {
        return doneWithCurrentGeneration;
    }
    public final void SetDoneWithCurrentGeneration(boolean tf) // True or false.
    {
        doneWithCurrentGeneration = tf;
    }
}       // End class < handleASingleGeneration >.