In this assignment you write a program where smileys run a race and, at race's end, shows statistics about the racers' running times. The assignment gives you practice with simple uses of ArrayLists and LinkedLists, and additional practice with boolean expressions, if statments, loops, inheritance and polymorphism, and nested structures.
You may pair program for this assignment, or work alone. Make this decision before you begin work on the assignment. Once you make the decision, it stands for the duration of the assignment. If you choose to pair program, you must work with the same partner for the assignment's duration.
This program begins with smiley racers, on 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; these racers then begin moving to the right. When a smiley hits the right wall, it's completed a lap. The smiley then reverses direction (so that it is facing left), its speed is adjusted (as discussed below), and it heads for the left wall. When it hits the left wall, again the profile and direction are reversed, the speed is again adjusted, and the racer heads for the right wall; another lap has been completed. As the race is run, the number of laps a smiley has completed so far is displayed next to its name.
When a racer completes the race—that is, runs the number of laps that constitue a race—the smiley stops. When all racers finish the race, the "stats" box at the bottom of the window shows the name and time of the fastest racer, the name and time of the slowest racer, and the average of all the racers' times.
The program then stops; the window remains open so 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, the program still shuts down.)
All your work is done in the RacingGroup, RacingSmiley and RacingAnimation classes. Now that you know about interfaces, we use them to specify and document the public methods that are required for these classes; we also provide additional documentation via comments. Be sure the the classes you write implement these interfaces explicitly (via the appropriate phrase in the class' header).
We've also provided several classes in compiled form; for those that have public methods and constants you may need, we've included text files describing them. Note that SmileyFace and SmileyFacePart as the same as they were in Lab 2; we explain why below. The graphics coding for this program is much more involved than for previous assignments, so we provide that code to you as already-compiled class files—BasicFrame, BasicDisplay, RacingFrame and RacingDisplay.
Some additional technical details:
Each smiley racer is a animated face with additional characteristics—a name, the name's display color, and about the racer as it is racing, such as which lap it is on, which direction it is moving, and whether it has finished the race. So, the SmileyRacer class is extended from the SmileyAnimation class.
What race information we decided to have in SmileyRacer brings up an important issue encountered when designing classes: Which class has the responsibility to keep detailed information, and make needed information available to other classes, when that information is intimately tied to two classes? For example, should the SmileyRacer keep track of whether a racer has finished the race? After all, whether a racer has crossed the finish line is a property of that racer. Or, rather, is it the racing class that should keep track of which racers have finished and which not? After all, a race needs to know which of its participants are still running, and which have completed, the race. In the last two assignments, we placed these "joint" responsibilities primarily with the animation class; in this assignment, we place them with the racers. Why? One can argue that either approach is better than the other, and we wanted to give you a chance to see, and have a chance to write code using, both approaches, to give you insight into the ramifications of doing it each way.
Thus, to construct a racer, you first construct a smiley face, and set its attributes as needed. You then pass this smiley face into the smiley racer constructor, along with the racer's name and name color. The constructor will use the smiley face's attributes to set the same attributes in the smiley racer.
You can also pass an exisiting smiley racer into the smiley racer constructor (along with a new name and color for it). This works because a smiley racer is an animated smiley (albeit one with additional characteristics).
To avoid having to write new methods to make the smiley appear in profile, make use of a couple of tricks:
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; instead, have the racer constructor translate them there—whenever feasible, it is best to have the program handle tasks, like this one, that would be tedious for a user of the class.
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 a second; the 1/24th of a second would be a tick. The duration of a tick is set in the RacingAnimation class.
The racer's base speed is in units of pixels per tick, and is determined when the racer is constructed. Also randomly determined 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 (it peaks early) or it increases its speed the same amount each lap (it paces itself and gradually pushes harder). Of course, when decreasing its speed, it cannot go to zero and still finish the race, so the racer must move at least 1 pixel per tick. The fastest a racer can go is double its starting speed.
It is possible for two or more racers to run the race in the same numbers of ticks; that is, there can be ties. To simplify stats computations, if there is a tie for the fastest runner, you can declare any of those tied racers as the fastest; the same applies for identifying the slowest ("good sport") racer. (The computation and display logic to list all the fastest and/or slowest racers in the case of ties is fairly complex, and beyond what is needed to practice the concepts this lab covers.)
Be particularly careful that, once a racer has finished the race, it does not move. A common error is for the racer to have finished, but to be moved one more time before the program knows not to move it further. The result is often a racer facing the wrong way at the finish, and/or not touching the finish line—and that's an error!
Your program should work for zero racers. All that happens is that, when the progam is run, the stats screen immediately displays a message that there was no race, and it does not display any statistics. 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 is large, and the racer’s names may go outside the smiley’s face; that is acceptable.
As before, all the class and Java source files you need have been placed into an Eclipse project and zipped into an archive; download Lab4.zip to get it. Using the same procedure that you followed previously, import this project into your Eclipse workspace.
Do remember to test your program incrementally, as described in Assignment 2; it will very likely save you a lot of time and frustration!
...and also remember that style matters: you can lose points for poor style, in particular for poorly structured code and for a lack of, or poorly done, comments.
Zip up your project folder into the file SmileysAtTheRaces.zip, and turn it in via Checkmate.