UMBC, CMSC202 Computer Science II, Spring 2007

Project 4: Derived Races

Due Dates

Design Document: Sunday, April 15, 2007, 11:59pm + 59 seconds

Final Project: Sunday, April 22, 2007, 11:59pm + 59 seconds



The objective of this project is to practice writing C++ code using class derivation and virtual member functions.

^Return to top


For this project, you will revisit the Car and RaceCourse classes from Project 2. You will redesign your classes from Project 2 with class derivation in mind. This will require several changes in the interface for these two classes. We want to increase the complexity of the objects in the race, however, we do not want to increase the complexity of the RaceCourse class. Thus, we will require the RaceCourse class to know very little about the race which will allow the RaceCourse class to concentrate on maintaining the positions of the objects. This will be accomplished using an inheritance hierarchy.

All of the objects in a RaceCourse will be derived from an abstract base class called Thing (see Thing.h). Cars are simply Things that move; Walls are Things that do not move. Your RaceCourse class will keep track of Things using pointers. By means of virtual member functions, the RaceCourse will allow specialized interaction between the objects without having to "understand" the interaction. (Note: since each Thing has a row and column, the Position class from Project 2 has been eliminated.)

For example, the Thing class has a pure virtual function called DrawMe() which returns a char. The PrettyPrintCourse() member function in Racecourse will use DrawMe() to print out the race course. This will allow us to derive different types of Cars or Things without re-writing PrettyPrintCourse().

One complication we have added is a penalty for cars that bump into another car. When this happens the bumper (the Car that moved) will lose 5 units of fuel and the bumpee (the stationary Car) will gain 5 units of fuel. This fuel deduction will not be handled by RaceCourse. Instead, RaceCourse will call the virtual function encounter() (in the Thing class) to handle the fuel transfer:

virtual void encounter (Car *ptr) ; In such a situation, the encounter() member function is invoked using a pointer to the bumpee. Since encounter() is virtual, the derived class member function is called. Note that RaceCourse does not need to understand the rules here, it should always call the encounter() function when one Thing bumps into another. The fact that there is no penalty for bumping into a wall is handled by the fact that the encounter() function of Wall doesn't charge the bumper any fuel. (Note that encounter is passed a Car pointer since we can assume that all moving objects are Cars or derived from Car).

Similarly, a RaceCourse no longer needs to worry about a Car winning by reaching the bottom left corner. This will be accomplished by placing a Goal object at bottom left corner (or any place in the race course). When a car bumps into a Goal, the Goal object declares a winner and stops the race. This will allow us to design race courses with goals placed in different locations, or even race courses with several goals, without changing the code for RaceCourse.

^Return to top


Note: you must also complete and submit a design document 1 week prior to the due date of the final project. See the Design Document section.

Your main assignment is to design and implement four C++ classes: Car, RaceCourse, PitStop and RandomCar. These are partially specified below.

Requirements for the Car class

The Car class must support the following methods: // Constructors Car() ; Car(unsigned int row, unsigned int col, char label, unsigned int fuel) ; // Moving virtual void ZoomLeft() ; virtual void ZoomRight() ; virtual void ZoomUp() ; virtual void ZoomDown() ; // Crash management void encounter(Car *ptr) ; // Fuel management unsigned int GetFuelLevel() const ; void SetFuelLevel(unsigned int f) ; void IncFuelLevel(unsigned int inc) ; void DecFuelLevel(unsigned int dec) ; // Race Course stuff virtual char DrawMe() const ;

The requirements for each function is documented in the skeleton header file Car.h.

Requirements for the RaceCourse class

The RaceCourse class must support the following methods: RaceCourse() ; RaceCourse(unsigned int r, unsigned int c) ; bool AddThings(const vector<Thing *>& T) ; unsigned int GetNumOfRows() const ; unsigned int GetNumOfCols() const ; void StartRace() ; void StopRace() ; RaceStatus GetRaceStatus() ; void PrettyPrintCourse() ; There are fewer requirements on RaceCourse compared to Project 2. The requirements for each function is documented in the skeleton header file RaceCourse.h.

There is no longer a limit on the number of rows or columns that a race course has. You will need to use dynamically allocated storage to handle this. Whether you use vectors or two-dimensional arrays is up to you. Similarly, there is no limit on the number of Cars (although the client must determine what labels to use).

Note that there is no longer a STALEMATE condition, since a Car that has run out of fuel might regain some when other Cars bump into it. The RaceCourse starts at WAITING, proceeds to STARTED when StartRace() is called and the FINISHED when StopRace() is called.

Note that AddThings() is oblivious of what it is adding. The objects might be Cars, Walls, Goals, ... The Things to be added are given as a const reference vector of Thing pointers. Memory must be allocated for the objects that these pointers point to in the main program. This memory allocation is done outside of the RaceCourse. It is the responsibility of the code that uses RaceCourse to deallocate. RaceCourse only does shallow copying.

Note: AddThings() can be called multiple times when the RaceCourse is in WAITING status. However, after the race has STARTED, no further calls to AddThings() is allowed.

Requirements for the PitStop class

Design and implement a class derived from Thing that represents a refueling stop in the race. When a car bumps into a PitStop, its fuel level is increased by 25 units.

Requirements for the RandomCar class

Design and implement a RandomCar class derived from Car. A RandomCar randomly chooses one of the four directions to Zoom. Look at the documentation for "lrand48()" by typing "man lrand48()" on Gl. You should set the random seed using "srand48()" in the constructor for a RandomCar.

A Main Program

Write a main program that adds a few RandomCars and a few PitStops in a RaceCourse.

^Return to top


^Return to top

Implementation Notes

  1. The following files are provided for you: These files are also available on the GL file system in the directory: /afs/

  2. Your implementation of Car and RaceCourse must be compatible with the main program and ScriptedCar class provided.

  3. Bumping: if a Car only has enough fuel to get to the position next to a Thing, it is not considered to have bumped into that thing. In order to bump into something, the Car must have enough fuel to reach the position of the Thing itself. In either case, the Car is placed in the position adjacent to the Thing, but the encounter() function is only invoked in the second case.

  4. In Project 2, GetCar() used a Car index number. There is no longer a concept of a Car index number. The main program creates the Car and passes a pointer (inside a vector) to the RaceCourse.

  5. Recall that a car should not be allowed to move if 1) it is out of fuel, 2) the race has not yet started, 3) the race has finished.

  6. If your Project 2 did not work and cannot be salvaged, you are permitted to use Prof. Chang's version of Project 2 as a starting point. Send email to him for instructions. [ The Project 2 files are now posted: Car.h, Car.cpp, RaceCourse.h, RaceCourse.cpp, and design.txt. ]

^Return to top

Design Document

You must submit written responses to these questions by Sunday, April 15, 11:59:59pm. Late submissions are not accepted for design documents.

Answer the following questions using complete English sentences. As usual, grammar and spelling counts. If you remember CUPS = "Capitalization, Usage, Punctuation and Spelling" from elementary school, they certainly apply here.

  1. In Project 2, you probably did not represent objects in your race course as pointers. How will the grid of the race course represented now? How will you retrieve the pointer to the "bumpee"?

  2. A Thing object stores its position in its data members m_row and m_col. The race course also stores pointers to Things that can be retrieved given the position. Thus, the position of a Thing is stored in two different places. When could you check that these two pieces of information are consistent?

  3. Will you have any appendant (non-inherited) data members in Car? If not, where is the fuel level stored? If so, should these members be public, private or protected? Why?

What/how to submit for your design document:

^Return to top


One main program is provided for you. Additional ones will be available later in the week. [New test programs are now available. -R.] These programs are fairly complicated and are not the ones you want to use at first. You are strongly encouraged to test your programs incrementally, as you write your implementation.

Warning: When your project is graded, it will also be tested with additional main programs. So, having a project that works with these programs is not a 100% guarantee. Your project must also satisfy the requirements specified above.

^Return to top

Submitting in your program

Remember to submit the design document the first week!

Use the UNIX submit command to turn in your project. The project name for Project 4 is 'proj4'. So, the Unix command will look like:

submit cs202 proj4 ... where ... is a list of files you wish to submit.

You should submit the following files. Please follow the spelling and capitalization for these files exactly. It allows us to use a script to compile your programs.

Note: We will assume that your project will compile using: g++ -Wall -ansi *.cpp If this is not the case, submit a makefile.

^Return to top

[CSEE] | [CMSC202] | [Spring '07 CMSC202]             Last Modified: 9 Apr 2007