CPSC 124, Winter 1998
Sample Answers to Lab 5


This page contains sample answers to the exercises from Lab #5 in CPSC 124: Introductory Programming, Winter 1998. See the information page for that course for more information.


Exercise 1: The original program could be modified as follows, so that all computation and recording of data is done in the StatCalc object:

        public class SimpleStatsRevised {

           // This program reads a set of positive numbers from the user.
           // It then prints out several statistics about the numbers
           // that were entered.
           //    Note that all the computations are done by an object
           // belonging to the class StatCalc.  This class is defined
           // in a separate file, StatCalc.java.
           //
           // David Eck


          public static void main(String[] args) {

             Console console = new Console();  // console for I/O with user

             double num;        // one number entered bythe user

             StatCalc stats;    // object that will keep track of statistics
                                // for all the numbers entered

             stats = new StatCalc();  // create the object

             console.putln("This program will compute various statistics");
             console.putln("for a set of positive numbers that you enter.");
             console.putln("Enter your data, one number on each line.");
             console.putln("To end, enter any number less than or equal to zero:");
             console.putln();

             do {  // read and process one number
                 console.put("? ");
                 num = console.getlnDouble();
                 if (num > 0)   // add positive numbers to dataset
                     stats.enter(num);
             } while (num > 0);

             if (stats.getCount() == 0) {
                console.putln("OK, so you don't have any data.  Goodbye.");
                console.close();
                return;  // end program by returning from main() routine
             }

               // Get the statistics from the StatCalc object, and report them
               // to the user.

             console.putln();
             console.putln("Here are some statistics about your numbers:");
             console.putln();
             console.putln("Number of data entries: " + stats.getCount() );
             console.putln("         Average value: " + stats.getMean() );
             console.putln("    Standard Deviation: " + stats.getStandardDeviation() );
             console.putln("         Maximum value: " + stats.getMaximum() );
             console.putln("         Minimum value: " + stats.getMinimum() );
             console.putln();
             console.close();

          }  // end main();

        }  // end of class SimpleStatsRevised


Exercise 2: The new version of the statistics program, using the StatCalc object, is easier to read than the original version. This is partly because it is shorter and simpler. A lot of the details of the calculation have been moved from the main program into the StatCalc class. Furthermore, tasks are performed in the main program by calling subroutines with meaningful names, such as stats.enter(num). This makes it easier for the reader to follow what the program is doing.

A second advantage comes from the fact that the program has been divided into two parts, each with its own responsibilities. The main program is responsible for doing input and output, but it calls upon that StatCalc object to do the statistical calculations. The StatCalc class can be designed, written, and tested in isolation. This has to be done only once, and then the class will be available for any program that has to do the same kind of statistical computations.

For a program this short, it's possible to bang out a decent program without writing a separate class to do the calculations. Using classes involves some extra overhead that you might be tempted to avoid. However, for larger programs, it becomes very difficult to keep things straight in a single, huge main program. Classes can help reduce the total amount of complexity and the total work involved. Even in this example, that fact that the class can be reused probably makes it worth writing.


Exercise 3: Here is a modified version of the JumpingSquare applet. The changes that were made from the original version of the applet are marked with (*****).

    /* 
        This applet displays a red square that jumps around the screen.
        The user tries to click on it.  The number of times the user hits
        the square and the number of times the user misses it are counted.
        The number of hits and misses are displayed.  The elapsed time,
        in seconds, since the applet started is also displayed.
    */

    import java.awt.*;     // Make classes from the packages java.awt and
    import java.applet.*;  //        java.applet available for use in this applet.


    public class JumpingSquare extends Applet implements Runnable {

       Thread runner = null;   // A separat thread to execute the applet's run() method
                               //   The null value indicats that it has not yet been created.

       int threadDelay = 25;   // The length of time, in milliseconds, that the thread will
                               //   "sleep" between its active periods.

       int topOfSquare;        // The location of the top-left corner of the red square.
       int leftOfSquare;

       long startTime;         // Time read from the system clock when the thread starts.
       long elapsedTime = -1;  // Time, in seconds, since the thread started running.
                               //   The -1 value indicates that it has not yet started.
                               //   This is used in the paint() method to avoid displaying
                               //   information that has not yet been computed.

       int hits;     // number of times user has clicked on the square (*****)
       int misses;   // number of times user clicked without hitting the square (*****)
       

       public void init() {
            // This method is called when the applet is first created, to give
            // it a chance to do any necesary initialization.  Here, I just set
            // the applets background color.
          setBackground(Color.lightGray);
       }


       public void paint(Graphics g) {
            // This method is called whenever the applet needs to be redrawn.
            // The graphics object, g, can be used to draw in the applet.
            // Here the the square and the elapsed time is displayed, but
            // only if elapsedTime has been changed from its initial value of -1.
          if (elapsedTime >= 0) {
            g.setColor(Color.red);
            g.fillRect(leftOfSquare, topOfSquare, 50, 50);
            g.setColor(Color.black);
            g.drawString("Elapsed time: " + elapsedTime + " seconds", 5, 15);
            g.drawString("Hits  = " + hits, 5, 28);      // (*****)
            g.drawString("Misses = " + misses, 5, 41);   // (*****)
          }
       }


       void doJump() {
             // This is a subroutine that I have provided to set a random location
             // for the square.  This just sets the variables topOfSquare and
             // leftOfSqaure; repaint() should be called to make sure that the
             // changes become visible.
          int appletWidth = size().width;
          int appletHeight = size().height;
          topOfSquare = (int)( (appletHeight - 50)*Math.random() );
          leftOfSquare = (int)( (appletWidth - 50)*Math.random() );
       }


       public boolean mouseDown(Event evt, int x, int y) {
             // This method is called when the user has clicked the mouse at
             // the point (x,y) in the applet.  This method checks whether
             // or not the user has clicked in the red square, and it updates
             // the values of the instance variables hits and misses appropriately.
             // Then the square jumps to a new location. (*****)
          if ( x > leftOfSquare && x < leftOfSquare + 50 && 
                      y > topOfSquare && y < topOfSquare + 50 )
             hits++;  
          else       
             misses++;  
          doJump();
          repaint();
          return true;  // (required to tell the system that the mouse click
                        //  has been processed)
       }


       public void start() {
            // This method is called when the applet first starts running.
            // (It might also be called if the applet is stopped and restarted.)
            // Here, the thread named runner is created and started running.
          if (runner == null || !runner.isAlive()) {
             runner = new Thread(this);
             runner.start();
          }
       }


       public void stop() {
            // This method is called when the applet first starts running.
            // (It might also be called if the applet is stopped and restarted.)
            // Here, the thread named runner is stopped, and runner is set to
            // null as a signal that a new thread must be created if the applet
            // is ever restarted.
          if (runner != null && runner.isAlive()) {
             runner.stop();
             runner = null;
          }
       }


       public void run() {

          startTime = System.currentTimeMillis();  // Record time when thread starts running.

          elapsedTime = 0;  // Time since thread started is zero seconds.

          doJump();   // Set random location for square.  
          repaint();  // Tell system that applet should be redrawn.

          hits = 0;   // start number of hits and misses at zero (*****)
          misses = 0;

          while (true) {  // Loop forever, i.e. until thread is stopped

             try { Thread.sleep(threadDelay); }  // Funny sytax to make the thread
             catch (InterruptedException e) { }  //    sleep for >= threadDelay milliseconds.
                                                 //    This is essential so that other
                                                 //    threads have a chance to execute.

             boolean needsRepaint = false;  // Applet needs to be repainted if
                                            // the square jumps or if the time changes.
                                            // This variable is set to true if
                                            // a call to repaint is needed. (*****)

             if (Math.random() < 0.1) {  // Make the square jump, with a probability
                doJump();                // of 10%.  (*****)
                needsRepaint = true;
             }

             // After thread wakes up, compute elapsed time since thread started.
             // To avoid unnecessary repainting, check if the number of seconds
             // elapsed has actually changed.  If so, applet needs to be repainted.
             long newElapsedTime = (System.currentTimeMillis() - startTime) / 1000;
             if (newElapsedTime != elapsedTime) {
                elapsedTime = newElapsedTime;
                needsRepaint = true;
             }

             if (needsRepaint)  // If display needs to be changed, call repaint()  (*****)
                repaint();

          }

       } // end of run()


    } // end of class JumpingSqaure


David Eck, 16 February 1998