CPSC 124 (Fall 1998): Lab 4
Parameters and Events


WELCOME TO THE THIRD LAB for Computer Science 124: Introductory Programming, Fall 1998. This lab reveals the full meaning of the line, "static public void main(String[] args)", that begins every main() routine. In the process, you'll get a preview of exceptions and how they can be used to write robust programs. In the second part of a lab, you will work with an applet that responds to keyboard events. You will write a subroutine that says how the applet should react when the user presses certain keys. You'll also use subroutines to draw the frames of an animated arcade-style game.

As usual, you will find a set of exercises at the end of this lab. You should turn in your answers to the exercises in class on the Monday following the lab. If you work with a partner in the lab, you and your partner have the option of turning in separate reports, or turning in one report with both your names.

Before you do anything else in the lab, you should copy the files that you'll need into your own account. You can do this with the command

cp  -r  /home/cs124/lab4  ~

After copying the files, you should change your working directory with the command

cd  lab4


Outline of the Lab:


Command Line Arguments

When a subroutine needs information from the outside world, it usually gets that information in parameters. The caller of the subroutine provides actual parameters that contain information to be used by the subroutine. In an independent application, the main() routine is called by the system when you run the program. The main() routine has a parameter of type String[]. The type String[] represents an array of Strings. An array of Strings is a numbered list of strings. Arrays are covered in Chapter 7 of the text, but here is all you need to know for this lab:

The Strings that are passed to the main() routine come from the command that you give to the computer to run the program. These strings are called command-line arguments. ("Argument" is another word for parameter.) When you type in the command to run the program, you can add extra words after the name of the program. These extra words are the command line arguments, which are passed to the main program as the array of Strings. For example, if you run a program named "echo" with the command

          java echo first second third

then in the main() routine, args.length will be 3, args[0] will be the string "first", args[1] will be "second", and args[2] will be "third". Here is an echo program that will print all its command line arguments to standard output:

          public class echo {
             public static void main(String args[]) {
                if (args.length == 0) {
                   System.out.println("(No command line arguments)");
                }
                for (int i = 0; i < args.length; i++) {
                   System.out.println(args[i]);
                }
             }
          }

The source code for this program is in your lab4 folder in the file echo.java. There is also a compiled version in echo.class. Try running this program with command lines, such as:

         java echo first second third
         java echo
         java echo now is the winter of our discontent

Make sure that you understand how the program works!


A Calc program with a Preview of Exceptions

For your first exercise of the lab, you will write a program that can perform the arithmetic operations +, -, x, /, and % on a pair of integers. (Since the UNIX operating system treats the "*" character in a special way when it occurs on the command line, you should use an "x" to represent multiplication, instead of a *.) The name of the program is calc. The data for the program will be typed on the command line, in a form such as:

             java calc 35 + 83
             java calc 873 % 22
             java calc 1234 x 5678

Therefore, inside the main() routine, args[1] is one of the strings "+", "-", "x", "/", or "%". This argument tells you which operation to perform. The numbers for the operations are in the strings args[0] and args[2]. Unfortunately, a string is not a number, so you have to convert each of the number strings to an int variable. Java provides the subroutine Integer.parseInt(String) to do this. Thus, you can say:

             int firstNum;
             firstNum = Integer.parseInt(args[0]);

to get the value of the first operand. You can do the same for the second number. This makes it fairly easy to write a calc program that will give the correct answers -- provided that you assume that the user inputs valid data when he runs the program!

Your assignment, though, is not just to write a program that will work when the user provides valid data. In addition to this, if the user gives invalid data, the computer should detect the fact that the data is invalid, and it should output an appropriate error message.

Your lab4 folder contains a compiled version of a calc program that does everything that it is supposed to. Try the program with various command lines containing both valid and invalid data. For invalid data, you can try, for example,

          java calc
          java calc 1 + 2 + 3
          java calc first second third
          java calc 34 / 0
          java calc 16 plus 27
          java calc x + y

When you write your program, it should behave pretty much like this one. One warning: Since args[1] is a string, make sure that you use the equals method to test it for equality, not the == operator. For example, you can say "if (args[1].equals("+")) ...".


One problem you will run into is how to check whether args[0] and args[2] are legal integers. If args[0] is not a legal integer, then when the compute tries to execute "firstNum = Integer.parseInt(args[0]);", the program will crash because of a so-called NumberFormatException. Fortunately, Java provides a neat way of dealing gracefully with such exceptions. In Java, you can "try" to do some statements and "catch" any error that occurs while the statement is being executed. You can then respond to the error any way you like. For example, here is a "try...catch" statement for converting args[0] to an int safely:

          try {
             firstNum = Integer.parseInt(args[0]);
          }
          catch (NumberFormatException e) {
             System.out.println("Error: The first argument, " + args[0] + ", is not a legal number.");
             return;  // end the program by returning from the main() routine
          }

If args[0] is a legal number, then the computer skips the catch part and goes on to the rest of the program. However, if args[0] is not a legal number, then a NumberFormatException occurs and the catch part is executed. In this case, an appropriate error message is printed and the program ends gracefully, instead of crashing. (The variable "e" in the catch part is an object that carries information about the error that has occurred. In this case, I just ignore the value of e.) Of course, you would handle args[2] in the same way.

Exceptions will be covered in more detail in Section 8.1 of the text.


Responding to Keyboard Events

In a graphical user interface, the user generates events by using the mouse and keyboard. A GUI program can respond to these events by defining subroutines that are called by the system when an event occurs. An applet also has to tell the system that it wants to "listen" for such events, but in this lab that part is already done for you, so all you have to do is fill in the appropriate subroutine.

The applet that you will work with is called SubKiller. The complete version of this applet is an arcade-style game that the user controls by pressing the arrow keys on the keyboard. You can try out the game on a separate page. You can also run it from your lab4 directory, using the command "appletviewer SubKillerComplete.html". Note that the applet doesn't do anything until you click the mouse on it. This is a signal to the operating system that you want your key press events to go to the applet.

A starter version of the applet can be found in the file SubKiller.java in the lab4 directory. You can run this version with the command "appletviewer SubKiller.html". In this starter version, the submarine is already programmed to move back and forth and change direction at random times. It can also explode. To make it explode, hit the up-arrow key. The boat is also in the applet, but it doesn't do anything.

Your first task is to edit the SubKiller.java so that the user can make the boat move by pressing the left-arrow key and the right-arrow key. All you have to do is change the value of boatCenterX when the user presses one of these keys. Then, when the next frame of the animation is drawn, the boat will be displayed in its new position. Do this by rewriting the definition of the method:

             synchronized public void keyPressed(KeyEvent evt)

This is the method that the system calls when the user presses a key. The parameter, evt, contains information about the key that was pressed. In particular, evt.getKeyCode() returns a code number for the key that was pressed. For this applet, you are interested in the arrow keys, which have code numbers given by the constants KeyEvent.VK_UP, KeyEvent.VK_DOWN, KeyEvent.VK_LEFT, and KeyEvent.VK_RIGHT.

You should read the current version of keyPressed() to see how the up-arrow key is used to make the submarine explode. (In the final version of the game, you want to get rid of this feature.) You should add commands to the keyPressed() routine that will subtract 15 from boatCenterX if the user presses the left-arrow key, and will add 15 to boatCenterX if the user presses the right-arrow key. Then compile the SubKiller.java file and do "appletviewer SubKiller.html" again to see that your changes worked.


A Simple Arcade Game

In the previous lab, you saw how several objects can move around independently in an animation. You just need member variables to keep track of the state of each object. In the SubKiller game, for example, there are several variables for the submarine: subCenterX and subCenterY keep track of the position of the position of the submarine; since the sub can be moving either to the left or to the right, there is a boolean-valued member variable subIsMovingLeft to keep track of the direction; since the sub can be either moving or exploding, there is a boolean-valued variable subIsExploding to keep track of which of these states it is in; finally, when the sub is exploding, it is necessary to keep track of how far the explosion has progressed, so there is a variable named explosionFrameNumber to keep track of the number of frames since the explosion began. The sub is a rather complicated feature of the applet, which is one reason why this part of the applet was already done for you.

Your next task is to add another object to the animation: the bomb (or depth charge), which is dropped by the boat to try to kill the sub. Make a section of the applet to contain the instance variables and methods that have to do with the bomb (similar to the sections for the boat and the submarine). You will need initBomb() and doBombFrame() methods, and these methods will have to be called in the applet's doInitialize() and drawFrame() methods. (Using subroutines in this way helps to keep the applet code organized, and it helps prevent individual methods such as drawFrame() from becoming too complicated.)

The bomb has two possible states: It can be attached to the boat or not. You will need a boolean variable to keep track of which state it is in. Program the keyPressed() method so that when the user hits the down-arrow key, the value of this variable is changed to show that the bomb is no longer attached to the boat.

You also need variables to keep track of bombCenterX and bombCenterY. In the doBombFrame() method, if the bomb is attached, then bombCenterX and bombCenterY should be set so that the bomb is attached to the bottom of the boat. Get the correct value of bombCenterX from boatCenterX.

However, if the bomb is not attached, then it is falling and might hit the sub. First, check if the bomb has hit the sub. If so, then the sub should start exploding (and the state of the bomb can go back to being attached to the boat). Second, if the bomb has fallen off the bottom of the drawing area, then the bomb has missed the boat (and its state can go back to being attached to the boat). If neither of these has happened, then you should add 10 to bombCenterY so that the bomb moves down a bit from one frame to the next.

To check whether the bomb has hit the sub, you just need to check whether the center of the bomb is close enough to the center of the sub, in both the horizontal and vertical directions. An easy way to do this is a test like "if (Math.abs(bombCenterX - subCenterX) <= 36 && Math.abs(bombCenterY - subCenterY) <= 21)". The numbers that are used in this test would depend on the sizes of the submarine and bomb. If this test is true, you should set subIsExploding to true to make the sub start exploding

In any case, don't forget to actually draw the bomb!

Again, you should compile your program and test it.


There are two more small additions that you will need to make to complete the game. First, the applet should keep track of the number of times that the bomb has hit the sub and the number of times that it has missed. To do this, you need two instance variables, hits and misses. In the doBombFrame() method, when the bomb hits the sub, you should add one to hits, and when the bomb falls off the bottom of the drawing area, you should add one to misses. The values of hits and misses should be displayed in the top left corner of the applet, under the message that gives the elapsed time. You can draw this message in the drawFrame() method.

The other addition is to play two more sounds at appropriate times. The applet already plays a sound when the sub explodes. When the user drops the bomb, you should play the sound tap2.au with the subroutine call statement "play(getCodeBase(),"tap2.au");". If the bomb falls off the drawing area, you should play the sound click2.au with the subroutine call statement "play(getCodeBase(),"click2.au");". The three sound files used by the completed applet are in your lab4 directory. To work in the applet, they must be in the same directory with the applet class file.


Once you have a working SubKiller game, publish it in your account on the Web. You have to copy six files to your www directory. You need the three sound files (swish.au, tap2.au, and click2.au), SubKiller.html, SubKiller.class, and KeyboardAnimationApplet.class. (The last of these is necessary because SubKiller.class depends on it.) Add a link from your home page to SubKiller.html. To do this, add a line such as

         <p>Try my <a href="SubKiller.html">SubKiller game</a>!</p>

to your index.html file. The words "SubKiller game" will appear on the Web page as a link to the file SubKiller.html. Clicking on the link will take the user to your exciting, action-filled game.


Exercises to Turn in

Exercise 1. (10 points) Turn in a printout of your "calc" program. Make sure that your program checks for all possible error conditions and gives appropriate responses. In particular: It should check for number format exceptions as described above. It should also check for the proper number of command line arguments, and it should check that the second command line argument is, in fact, one of the operators +, -, *, /, or %. Finally, it should check for division by zero.

Exercise 2. (15 points) Turn in a print out of your completed SubKiller game. Also, post your applet on the Web and tell me the URL where I can find it.

Exercise 3. (5 points) Write a short essay explaining how subroutines can be used to help in the design of complex programs. As an example, discuss how subroutines were used in the SubKiller applet.


[ Lab Index | Online Notes ]