CS 51 Test Program #1
Due: Friday, March 7, 2008, at 4 PM

A test program is a laboratory that you complete on your own, without the help of others. It is a form of take-home exam. You may consult your text, your notes, your lab work, or our on-line examples and web pages, but use of any other source for code is forbidden. You may not discuss these problems with anyone aside from the course instructor. You may only ask the TA's for help with hardware problems or difficulties in retrieving your program from a disk or network.

Complete each of the following problems, documenting your code well. You are encouraged to reuse the code from your labs or our class examples. Submit your code in the usual way by dragging it into the Dropoff folder. Please do not submit three separate folders. Instead, place the folders for all three of your complete programs into one folder, make sure that your name appears in the title of the main folder and each of the subfolders, and then place the main folder in our dropoff folder.

Problem 1: SkiBall

Some of you have probably played the carnival game SkeeBall, which has been around since 1909. This is a game where you roll a ball down an alley and over a "skee-jump" so that the ball flies in the air for a few feet before landing in the target area. In the target area are several circular containers into which the ball can fall. Generally getting the ball into smaller containers results in more points being scored. For this program, you are to write a program that is somewhat simpler. We will call it SkiBall to reflect the greater simplicity and to avoid copyright problems.

A demo version should appear below if your web browser supports Java.



The class that you will write will draw a somewhat simplified SkiBall court:

The idea is for the player to shoot the ball into one of the circles to obtain a score. The top small circle is worth 50 points. The small middle circle is worth 30 points. The circle around that is worth 20 points, while the biggest circle is worth 10 points. Obviously the player should get the highest score of all the circles it is contained in. Thus if the ball goes into the small middle circle then the score should be 30 points, even though it is also contained in the two circles containing that one.

When the player presses the mouse button down somewhere behind the foul line, a ball is drawn on the foul line, centered at the same x coordinate as the mouse position (i.e., the ball is drawn directly above the current mouse position). A line is drawn from the center of the ball to the current mouse position. When the mouse is dragged, the end point of the line follows (the start remains attached to the ball, which does not move). You should think of the line as a slingshot or pool cue that will be used to determine in what direction and what distance the ball will move when released.

When the mouse is released, the ball moves from the foul line to its final resting place in a single move - there is no animation necessary. To determine the final resting place of the ball, measure the difference in the x coordinates between the start and end position of the line. Do the same for the y coordinates. The final position of the ball is determined by moving it 4 times as far in the opposite direction in each of the x and y coordinates.

For example suppose the ball is sitting on the foul line at (300,500) and the mouse is at (325, 600) when the mouse button is released. The difference in the x-coordinates is 25, while the difference in y-coordinates is 100. The final resting place of the ball will then be 100 (= 4 * 25) units to the left of its starting position and 400 (= 4 * 100) units above its starting position. Thus its final coordinates will be (200,100), a point along the straight line showing on the screen when the ball is released. The score earned by a ball is determined by where its center is after the shot.

You may leave the balls on the screen after they are shot. Always indicate the score obtained from the last shot. No totals are required.

The diameters of the circles should be 25, 50, 100, and 150, while the center of the concentric circles should be at (200,200). The foul line should be drawn with a y-coordinate of 500. We have set up the window so that is is 400 pixels wide and 700 pixels high.

Problem 2: Snowman

The first VisibleImage used in this course was a snow man. Keeping with this theme, we would like you to implement a program where you construct a simple "snowman" figure out of objectdraw primitives that you can drag around the canvas. The twist is that your snowman "melts" (really just shrinks) as he is dragged toward the bottom of the canvas (the "south"), but grows when he is dragged toward the top (the "north"). Just for fun, your snowman will be dragged around on top of a map of the United States.

A running version of the program we hope you produce is provided below (if your browser handles applets correctly):



Your snowman should consist of two snowballs: a body and a head. The head should be centered on top of the body, and should have a radius equal to one half that of the body.

As your snowman is dragged around the canvas, its total height should be adjusted so that it is always equal to one half the distance from the top of the snowman's head to the bottom of the canvas. Your snowman should be created initially in the center of the canvas in the x direction, and at the top of the canvas in the y direction (right over the northern plains, which seems to be an appropriate birthplace for a snowman). The dragging in this program is a bit unusual, since the object you are dragging is changing in size. It is possible that the place on the snowman where you originally "grabbed" it will no longer be part of the snowman after it has resized. Your program should exhibit this behavior, which you might think of as having the part of the snowman that you were holding onto melt in your hands. The window is 600 pixels wide and 330 pixels high. You will want to be extra careful with how you resize your snowman. Objectdraw objects resize themselves by keeping the upper left corner fixed. However, if you do that for your snowman, it will result in an unnatural dragging - your snowman may appear to drift to the left even if you drag him straight down. You should resize your snowman by keeping a fixed point at his "neck" where the head and body meet. This will mean a resize operation that is supposed to shrink your snowman will result in the head moving down and to the right, and the body moving to the right.

We're sure you could do the math to figure out what to move where. We encourage you to think through it, but since that's not the point of this program, here are some hints on how to adjust your snowman's size and position when it is supposed to change from a height of height to a height of newHeight. The value heightDiff below is height - newHeight (which is a positive value for shrink operations, negaive for expand).

To complete this program, you will need to write two classes: a DragASnowMan class that extends WindowController and a SnowMan class that draws and operates on the snowman.

Problem 3: Stopwatch

Your last test program will be a simple program that simulates a stopwatch. When the program starts, the screen displays instructions and the time of "0:00". When the user clicks the first time, the stopwatch starts running, displaying the elapsed time in seconds and minutes. When the user clicks a second time, the stopwatch halts, showing the final elapsed time on the screen.

If the user clicks a third time then the stopwatch starts again at "0:00" and runs until the user clicks a fourth time. It behaves similarly with further clicks.

A running version of the program should be visible below if your browser handles applets correctly:



I suggest that the Text item displaying the time be created in the Stopwatch class (the one that extends WindowController). The active object class, ClockClass, is responsible for controlling what is displayed on that Text item, but does not create it. When the user clicks a second time, the ClockClass item should stop running. If there are further clicks then new ClockClass objects are created, but they all use the same Text item to display the current time.

The invocation of System.currentTimeMillis() returns the time in milliseconds. You can convert to seconds by performing an integer divide by 1000. Similarly you can conver the milliseconds to minutes by dividing by 60000. I'll let you figure out how to get the seconds to reset to 0 after passing 59.

The demo shown in the on-line version does a bit more than is required. The second display always shows two digits, even if it is only, say, 5 seconds after the minute. One point extra credit can be obtained by getting it to always show two digits for seconds.

Grading Point Allocations

Value

Feature
Style (16 pts for each of 3 programs)
2 pts. use of boolean conditions
2 pts. ifs/whiles
2 pts. appropriate vble (instance/local, public/private)
2 pts. Descriptive comments
2 pts. Good names
2 pts. Good use of constants
2 pts. Appropriate formatting
2 pts. Parameters used appropriately
Correctness (16 pts for each of 3 programs)
SkiBall
Drawing the screen initially
Ball drawn on the line when mouse pressed
"Cue stick" line drawn to aim ball
Ball is launched to correct location
Scores awarded and displayed correctly
Snowman
Drawing a snowman
Dragging the snowman
Resizing the snowman correctly
Timer
Putting directions and "0:00" in window
Starting timer to show time continuously
Stopping timer on second click so shows elapsed time
Getting timer to restart on odd clicks
Saying pop when breaks
Miscellaneous (4 pts total)
Extra Credit (4 pts maximum)