| 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 >.