Purpose
This assignment asks you to write a program in which smileys run a race and computes statistics about their running times. You'll get practice with simple uses of ArrayLists, and additional practice with boolean expressions, if statements, loops, and nested structures.
Program behavior and general requirements
This programs begins with smiley racers lined up along the left edge of the graphics display, facing right; we see them in profile. They each have a name displayed, in color, in the middle of their faces, so we can root for our favorite.
The race begins when the user presses the Go! button; the racers then begin moving to the right. When they hit the right wall, they've completed a lap. (You'll see the number of laps completed by each smiley next to its name.) They reverse direction, so that they're facing left, and their speed is adjusted as discussed below; they then head for the left wall. When a racer hits the left wall, again, the profile and direction are reversed, the speed is adjusted, and the racer heads for the right wall; another lap has been completed.
When a racer completes the race — the is, runs the number of laps that constitute a race — the smiley stops. When all racers finish the race, an area near the bottom of the window shows statistics:
- The name and time of the fastest racer
- The name and time of the slowest racer
- The average time
Just above the statistics is a title introducing them.
The program then stops, though the window remains open so that the user can read the statistics. The user clicks on the close box to close the window and end the program; if the close box is clicked while the race is still running, it still shuts down the program.
Technical details
For this assignment, we've again helped you get started by providing a significant amount of code and lots of comments and documentation. All of your work will be done in the SmileyAnimation and SmileyRacer classes. We've provided several classes in compiled form; three of them (SmileyFace, SmileyFacePart, and SmileyDisplay) have public methods and constants that you may need, so we've included text files describing each of them. (Note that SmileyFace and SmileyFacePart as the same as they were in Lab Assignment 2.)
These files have been collected into an Eclipse project and zipped into an archive called 21Lab3.zip. Using the same procedure that you followed in the last assignment, import this project into your Eclipse workspace.
Some additional technical details:
- Each smiley racer is a smiley face with additional characteristics; each has all the attributes of a smiley face, plus its name, the name's display color, and information to track its status while it races, such as how many laps it has completed, which direction it is moving, and whether it has finished the race. So, the SmileyRacer class is extended from the SmileyFace class; it automatically has all of the characteristics — all the fields, constants, and methods — of the SmileyFace class. We then added additional fields, constants, and methods necessary to turn the smiley face into a racer. The upshot of this is that all of the public methods available to manipulate or access smiley faces and their face parts are available for manipulating and accessing smiley racers and their face parts. You will not see these methods explicitly listed in the SmileyRacer class, but they are a part of it.
- Thus, to construct a racer, you first construct a SmileyFace and set its attributes as needed (see below). You then pass this SmileyFace into the SmileyRacer constructor, along with the racer's name and name color; the constructor will use the SmileyFace's attributes to set the same attributes in the SmileyRacer.
- You can also pass an existing SmileyRacer into the SmileyRacer constructor (along with a new name and color for it). This works because a SmileyRacer is a SmileyFace (albeit one with additional characteristics), so the constructor will treat it as a SmileyFace.
- To avoid having to write new methods to make the smiley appear in profile, there are a couple of tricks that you can make use of:
- To start, make the left eye the same color as the face and the right eye a different color; switch those colors each time a wall is hit. (Think about it — it does work!)
- Place the mouth on the smiley so that the x-coordinate of its center is about the same as the x-coordinate of the rightmost point of the smiley face; make it the same color as the display's background color, which is given by the constant SmileyDisplay.BACKGROUND_COLOR. This will make the smiley appear to have an open mouth. Shift the mouth to the other side of the face each time a wall is hit.
- Position your smileys so that, when they move left to right and right to left, they will not collide. You do not have to worry about constructing smiley faces so that, when the race starts, their left sides touch the left-hand side of the race track; the SmileyRacer constructor will translate them there — we don't force the user to construct faces this precisely.
- We measure time in ticks. A tick is just an arbitrary time unit that corresponds roughly to the time between one frame of animation and the next, kind of like saying "24 frames per second" means that the time between one frame of film and the next is 1/24th of second; in that case, the 1/24th of a second would be a tick. The duration of a tick is set by a constant in the SmileyAnimation class.
- The racer's base speed is in units of pixels per tick, and is determined randomly when the racer is constructed. Also determined randomly at that time is the racer's racing strategy. A racer can run the race at a constant speed, or it can decrease its speed the same amount each lap (i.e., it peaks early) or it increases its speed the same amount each lap (i.e., it paces itself and gradually pushes harder). Of course, when decreases its speed, it cannot go to zero and still finish the race, so the racer must move at least one pixel per tick. The fastest a racer can go is double its starting speed.
- Your program should work for zero racers. All that happens in this case is that the statistics screen immediately displays a message that there was no race. In particular, do not display any statistics for a non-existent race! Your program should also handle a large number of relatively small-sized racers, at least in the range of 10 to 20. The animation may slow down when the number of racers gets large, and the racer's names may go outside the smiley's face; this is acceptable.
Some hints and tips
Do not change any public method signatures or constants. It's also best if you do not change any of the private information, either; that way, you won't have to rethink your work when you take the lab exam.
You can add private fields, constants, and methods to "help" the methods we provided.
You should not need to import any libraries, but you may do so if they are needed to complete your work.
Remember to test your program incrementally, as described in Lab Assignment 2 (and as we talked about in class); it will very likely save you a lot of time and frustration.
About Lab Exam 3
Lab Exam 3 will be very similar, but perhaps not identical, to the program you have been asked to write for this exercise. The lab exam will ask you to implement one or more of the following methods from the SmileyAnimation or SmileyRacer classes:
- The SmileyAnimation constructor
- animate
- allRacersFinished
- computeRaceStatistics
- computeFastestRunner
- computeSlowestRunner
- computeAverageTime
- The SmileyRacer constructor
- finishedRace
- raceForOneTick
- moveForwardOnePixel
- reverseProfile
- hitSomething
- Adapted by Alex Thornton to emphasize the use of Eclipse, Summer 2009.
- Originally written by Norm Jacobson, October 2006 - September 2008.