C:\upload\java\Life\source\java\PaintBoardAndComputeNextGeneration.java
/*******************************************************************
    This class takes care of the canvas on which the board lives.

    It also takes care of computing the next generation. Both of these:

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

    so we put them together.
    
    As a prcis, when we are done, we have done two things:

        1) Computed what the board will look like in the next generation
        2) Painted the current generation.
******************************************************************** */

import java.awt.*;

final class PaintBoardAndComputeNextGeneration extends Canvas implements Constants,
                                                                   Strings
{
    private Vars vars;
    private BoardUtilities boardUtils;      // Uses these to determine who
                                            // will live & die in the
                                            // next generation.

    private ManageBoardCoordinates boardCoordinates;// This class manages
                                                    // board coordinates.

    private PopupWindow error;          // In case something goes wrong
    private int xVal, yVal; /* Sometime the caller only sets one cell, as
                               only one cell of the board has changed. We
                               do not waste CPU cycles repainting everyone.
                            */
    private boolean paintOneCell;   // Do we color only one cell?

    /* Three colors: Things alive who will live at least one 
       generation, things soon to die, and things soon to come to life.
    */
    private Color aliveColor, soonToDieColor, soonToComeToLife, deadColor;

    private boolean trueSizeKnown;  // Does this Canvas class know how big it is?

    private int [][] thisGeneration, nextGeneration; // Array which the board lives in. Local copy.

    private Dimension size;     // How big are we? Lives in this parameter.
    private Point location;

/*******************************************************************
    Constructor follows:
******************************************************************** */

    PaintBoardAndComputeNextGeneration(Frame parentFrame,     // Holds variables.
                                       Objects objects,
                                       ScreenLocations screenLocations,
                                       int w, int h)  /* Initial guess at my size. Will 
                                                         change.                      */
    {
        String errorString = ((parentFrame != null)    && 
                              (objects != null) && 
                              (screenLocations != null)) ? 
                             NULL_STRING : "parentFrame = " + parentFrame +
                             " objects = " + objects +
                             " screenLocations = " + screenLocations;
        if (!errorString.equals(NULL_STRING))
        {
            System.out.println("Error, null pointer, PaintBoardAndComputeNextGeneration " 
                              + errorString);
            return;
        }
        vars = null;    // Can't do things without this parameter.
        
        error = new PopupWindow(parentFrame, screenLocations, 
                                ERROR_WINDOW_NAME);// In case of an error.

        // Set initial size. Fix later:

        size = new Dimension(w, h);
        location = new Point(0, 0);
 
        /* Next handles board coordinates. We tell it the number 
           of rows & columns as soon as we know.
        */
        boardCoordinates = objects.GetBoardCoordinates();

        /* Next is general board utilities things like,
           "is this  cell alive in the next generation?" 
        */
        boardUtils = objects.GetBoardUtilities();

        // We set several class variables:

        aliveColor          = COLOR_ALIVE;
        soonToDieColor      = COLOR_SOON_TO_DIE;
        soonToComeToLife    = COLOR_DEAD;
        deadColor           = COLOR_DEAD;

        // We don't know how big we are yet:
        
        trueSizeKnown   = false;
        paintOneCell    = false;    // Assume we paint the entire board.

        xVal = GARBAGE_VALUE;
        yVal = GARBAGE_VALUE;
        }

/*******************************************************************
    Over-ride next for good measure.
******************************************************************** */

   public void update(Graphics g) 
   {
         super.paint(g);
   }
   /*******************************************************************
    Obvious by code: get local copy of *vars*.
******************************************************************** */
   protected void SetVars(Vars vars)
   {
       this.vars = vars;
   }

/*******************************************************************
    The < paint(Graphics g) > routine follows.
    
    NOTE: This routine does two things in one fell swoop: it paints
    the board, AND, computes the next generation. As both of these
    actions
    
        1) Loop through entire board
        2) Call the AliveInNext() routine,

    the writer decided to incorporate them for efficiency of code.
******************************************************************** */

    public void paint(Graphics g)
    {
        /* 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 position.    
        */
        setLocation(0, PIXELS_TO_SKIP_FROM_TOP_AND_BOTTOM);

        thisGeneration = vars.GetThisGeneration();  // Sometime between
        nextGeneration = vars.GetNextGeneration();  // games arrays change.

        /* We are very, very careful. Perhaps we have not been
           fed our true size, or a parameter is garbage. Best
           be safe. Do nothing if something isn't right.
        */

        boolean showBoard = trueSizeKnown && (thisGeneration != null) && 
                            (nextGeneration != null) && (g != null) && (vars != null);

        if (showBoard)  /* If we don't know our true size, or a
                           parameter is garbage, do nothing.      */
        {
            int pixelsPerCell = vars.GetPixelsPerCell();
            if (paintOneCell) // Sometimes we only paint one cell. Don't waste
                              // CPU time painting the whole board if this is so.
            {
                
                handleOneCell(yVal, xVal, g, pixelsPerCell);
                   /* Always set next, so the patron has to
                      call < SetSingleCellToChange > whenever
                      a single cell is changed. This way the code
                      always knows when only a single cell is
                      changed.
                   */
                paintOneCell = false;       // These
                xVal = GARBAGE_VALUE;       // must
                yVal = GARBAGE_VALUE;       // be re-set!
            }
            else    // We're painting the entire board.
            {
                int rows =    vars.GetRows();
                int columns = vars.GetColumns();
                int i = 0; // Loop variables.
                int j = 0; // Set to zero or the try-catch
                           // clause gets unhappy.

                // Clear things:

                g.clearRect(getLocation().x, getLocation().y, 
                            getSize().width, getSize().height);
                g.setColor(COLOR_BACKGROUND);
                g.fillRect(getLocation().x, getLocation().y, 
                            getSize().width, getSize().height); 

                // Now paint the current board and compute the next generation.

                for (i = 1; i <= rows; i++)
                {
                    for (j = 1; j <= columns; j++)
                    {                            
                        handleOneCell(i, j, g, pixelsPerCell);
                    }   // End j-loop
                }       // End i-loop
            }
        }
        else    // Parameter < showBoard > is false; something is
        {       // not right, so ...
            ;   // Do nothing.
        }
    }       // End < paint() > routine.
 
 /*******************************************************************
    Next routine < handleOneCell > colors one cell of the board at
    indices (i, j).
    
    Note:  some of this code is not as "graceful" as it could perhaps
    be.  Because this gets called so much (rows * columns, each 
    generation), I have axed "prettiness" for speed.
******************************************************************** */

    private final void handleOneCell(int i, int j, Graphics g, int pixelsPerCell)
    {
        /* Painting one cell is dicey. As xVal and yVal are set to "garbage"
           values between calls (i.e, they must always be re-set), if we are
           painting a single cell, we are ultra-careful.
        */
/*        if (paintOneCell && ((i == GARBAGE_VALUE) || (j == GARBAGE_VALUE)))
        {
            error.ShowMessage(GARBAGE_VALUES_OF_I_OR_J + 
                              " < handleOneCell PaintBoardAndComputeNextGeneration.",
                              OK);                      // Button.
        }
  */    /*  try
        {*/
            if (boardUtils.AliveInNext(thisGeneration /* Next generation
                                                         depends upon
                                                         this one! */, 
                                                         i, j /* And what cell
                                                                 we are at. */))
            {
                nextGeneration[i][j] = 1;   // Cell is alive in the next generation.
                if (thisGeneration[i][j] == 1)
                    g.setColor(aliveColor);
                else                              // Currently dead, about to.
                    g.setColor(soonToComeToLife); // to life.
            }
            else
            {
                nextGeneration[i][j] = 0;   // Cell is dead in the next generation.
                if (thisGeneration[i][j] == 1)
                    g.setColor(soonToDieColor);
                else
                    g.setColor(COLOR_DEAD);
            }
            // Now draw the cell:

            Point where = boardCoordinates.boardValuesToPixels(j, i, pixelsPerCell);
            int yValue = (int) where.getY();
            int xValue = (int) where.getX();
            
            g.fillRect(xValue,
                       yValue,
                       pixelsPerCell - 1,  // Scale down a 
                                           // little --
                       pixelsPerCell - 1); // makes things look 
                                           // better
/*        }
        catch (ArrayIndexOutOfBoundsException e) // Array index out 
                                                 // of bounds!?
        {
            String errorStr = e.getMessage();

            errorStr = errorStr + " Array bounds exception in " +
                                " routine " +
                            " computeOffScreenGraphicsForPrintingBoard: " +
                            "rows = " + rows + ", columns = " + columns +
                            ", i = " + i + ", and j = " + j;
            error.ShowMessage(errorStr, OK);
        }*/
    }
 
/*******************************************************************
    What if we color only one cell? Next takes care of setting the
    cell via globals < xVal > and < yVal >.
******************************************************************** */

    public void SetSingleCellToChange(int xVal, int yVal)
    { 
        if ((yVal < 1) || (yVal > vars.GetRows()) ||      // Input bad? We cannot
            (xVal < 1) || (xVal > vars.GetColumns()))     // interpret this.
        {
            error.ShowMessage(UNRECOVERABLE_ERROR +
                                " < SetSingleCellToChange : PaintBoardAndComputeNextGeneration >, " +
                                "xVal = " + xVal + ", yVal = " + yVal +
                                ", rows" + vars.GetRows() + ", " + AND + " columns = " + 
                                vars.GetColumns() + ". " + WE_CANNOT_INTERPRET_THIS + ".",
                                OK);                                 // Button.
            paintOneCell = false;   // Set false for good measure. Nonsense!
        }
        else // Input good.
        {
            paintOneCell = true;    /* This is called when we set one cell of
                                       the board. The < paint() > routine needs
                                       to know. This is set < false > again at
                                       the bottom of < paint() > -- this routine
                                       must be called by patron every time we only
                                       set one cell.
                                    */
            this.xVal = xVal;   // Set fed
            this.yVal = yVal;   // parameters.
        }
    } 
 
/*******************************************************************
    Over-ridden routines that follow take care of dimension problems.
    Note how < setSize > sets a boolean telling the code, "I know how
    big I am."
******************************************************************** */
 
    public Dimension getSize()  // Tell caller our size. Over-ridden.
    {
        return getMinimumSize();
    }
    public Dimension getMinimumSize()   // Tell caller our min size. 
    {                                   // Over-ridden.
        return size;
    }
    public Dimension getPreferredSize()   // Tell caller our max size.
    {                                     // Over-ridden.
        return getMinimumSize();
    }

/*******************************************************************
    Next sets a boolean telling the code, "I know how big I am."
******************************************************************** */

    public void setSize(int width, int height) /* Set our size. 
                                                  Over-ridden.  */
    {
        size = new Dimension(width, height);
        trueSizeKnown = true;               // That boolean. The main code knows
    }                                       // that our size has been set.
    
/* ********************************************************************* 
        The next three routines are short communication routines: calling
        program tells us colors of live & dead cells.
   ********************************************************************* */

    protected final void setAliveColor(Color aliveColor) // What color is an
    {                                               // "alive?"
        this.aliveColor = aliveColor;
    }
    protected final void setSoonDeadColor(Color soonToDieColor) // What color is
    {                                                 // "dead?"
        this.soonToDieColor = soonToDieColor;
    }
     // What color is a
     // "soon-to-be-alive?"
    protected final void setAboutToComeToLifeColor(Color soonToComeToLife)
    {
        this.soonToComeToLife = soonToComeToLife;
    }
}           // End < PaintBoardAndComputeNextGeneration > class.