UMBC, CMSC202 Computer Science II, Spring 2007

Project 2: Amazing Race

Due Dates

Design Document: Sunday, March 4, 2007, 11:59pm + 59 seconds

Final Project: Sunday, March 11, 2007, 11:59pm + 59 seconds



The objective of this project is to practice designing C++ classes following the principles of object-oriented programming.

^Return to top

Warning to Procrastinators

This is a thinking project. It will take more time to think about the project than to code. This does not imply that coding will not take a significant amount of time. Indeed, poorly-designed projects will take much longer to code (and debug) than a well-designed project. You will need the first week of this two week project to come up with a good design!

^Return to top


For this project you will be designing C++ classes to simulate remote control cars operating in a race course. The race course is simply a two-dimensional grid. The cars start out in the top row and attempt to reach the bottom-left corner. This is not a straight shot because the race course is littered with obstacles. The first car to reach the bottom left corner of the grid wins.

The remote control cars being simulated have no sensors and limited fuel capacity. You can only command the cars to move in one of four directions (up, down, left and right). The car keeps moving in that direction until it either 1) runs out of fuel, 2) reaches the edge of the race course, and 3) crashes into an obstacle or another car.

^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.

In Project 1, the classes were designed for you. You implemented some member functions and wrote the main program that used the classes. In this project, the situation is somewhat reversed. The main program is given to you and the design of the actual classes is up to you. You do not have complete freedom, however, since your classes must work with the given main program.

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

Requirements for the Car class

The Car class must support the following methods: // Move in this direction until you can't void ZoomLeft() ; void ZoomRight() ; void ZoomUp() ; void ZoomDown() ; // Other Member Functions Position GetPosition() const ; unsigned int GetFuelLevel() const ;

These functions should do the obvious thing. The "zoom" functions move the car in the specified direction until it runs in to something, either a wall or a car. GetPosition() returns the current position of the car. The type Position is defined in a header file given to you: proj2.h --- it is a simple data-only class (really a struct) that holds a row and column number. Finally, GetFuelLevel(() should return the current fuel level.

Note that when a car moves, its fuel level goes down by 1 unit for each row or column traversed. If a car runs out of fuel, it is stuck forever.

Requirements for the RaceCourse class

The RaceCourse class must support the following methods: // Constructor with sizes, number of cars and positions // of the obstacles. RaceCourse(unsigned int rows, unsigned int cols, unsigned int cars, const vector<Position>& obstacles) ; // return pointer to Car number i. Car * GetCar(unsigned int i) ; // RaceCourse stats. unsigned int GetNumOfCars() const ; unsigned int GetNumOfRows() const ; unsigned int GetNumOfCols() const ; void StartRace() ; RaceStatus GetRaceStatus() ; // const or non-const unsigned int GetWinner() ; // const or non-const // Use # for edges and obstacles, digits for car numbers, // and . for a blank space. See sample output. void PrettyPrintCourse() ; // const or non-const Change: You can designate GetRaceStatus(), GetWinner() and PrettyPrintCourse() as const or non-const as it fits your design.

Initially, the cars are all positioned in the top row. Car # 1 should in the leftmost column, followed by Car #2, Car #3, ... The number of cars must not exceed the number of columns. Each car starts with the same amount of fuel, specified in the constant InitialFuelLevel that is defined in proj2.h.

The the status of the race course can be one of four values

The status is represented as an enumeration type RaceStatus defined in proj2.h. The status of the race is reported by the GetStatus() method. If the race has finished, then GetWinner() reports the winning car. The method StartRace() must be invoked by main() before it starts moving cars around. When StartRace() is called, the status of the race course should change to STARTED. This is also an opportunity for the RaceCourse object to do any "housekeeping" before the race begins (if any such housekeeping is needed).

The RaceCourse object must maintain a certain level of internal consistency. For example, two things (cars and obstacles) should not be allowed to occupy the same position. Similarly, cars should not be allowed to drive off the course (this will require some cooperation with the Car class).

Many questions about the requirements for the Car and RaceCourse objects can be answered by looking through the main programs supplied. (See Testing section.) The requirements define the interfaces between the main program and the Car class and between the main program and the RaceCourse class. The interface between the Car class and the RaceCourse class has not been specified. This part is left for you to design.

^Return to top


^Return to top

Implementation Notes

  1. You will certainly need to define other data members and methods for the Car and RaceCourse classes. For example, the constructors for the Car class are not specified. You will need to figure out the function prototype of the constructor that suits the needs of your design.

  2. We don't want to do dynamic memory allocation just yet, So, proj2.h has some constants we need. const unsigned int MaxCars=9 ; const unsigned int MaxRows=50 ; const unsigned int MaxCols=20 ;

  3. The pointers returned by GetCar() must be valid for the lifetime of the race course. If you use a vector to hold the Car, you must make sure that this vector does not get resized. If the vector is resized, the Car objects will be copied, which invalidates the pointers previously returned by GetCar. The recommendation is that you use an array of Car objects with MaxCars items.

  4. The main program will use the GetCar() function to retrieve a pointer to a Car(). There is a reason for this mechanism that will make more sense after we cover polymorphism. The main program will then ask the car to move by invoking a Car method, such as: CarPtr1->ZoomDown() ; This is equivalent to (*CarPtr1).ZoomDown() just as in C for pointers to structs. In order for the Car to ZoomDown, it will certainly need to consult the RaceCourse it is in. How does the Car know which RaceCourse to use???

    When a RaceCourse is constructed, it also initializes the specified number of Cars. The RaceCourse must place a pointer to itself in a Car data member. In C++ the keyword this used in a member function means "pointer to the current object". Thus, the RaceCourse constructor must store its own this pointer in each Car object it initializes.

  5. Try not to use friends.

  6. If you find yourself writing methods for Car that must access a lot of RaceCourse data members or vice versa, then it is a sign that your objects are poorly designed. Projects with poorly designed objects will receive lower grades.

  7. If you use the vector container class, you need to have the "using namespace std ;" directive.

  8. Beware of recursively including header files. The Car class needs to know something about the RaceCourse class and vice versa. Sometimes all you need is a forward class declaration: class RaceCourse ; This just tells the compiler that RaceCourse is a class. For example, this enough to declare pointers to RaceCourse.

  9. We will start counting the rows and columns with index 1. This is so you can store "obstacles" around the perimeter of the race course to form a wall. (Highly recommended.)

  10. Similarly, counting Car numbers from 1 is convenient, since it lets us use 0 to represent an empty space in the race course. Also, GetWinner() can return 0, when the race has not yet finished.

  11. 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.

  12. Whatever method you choose to represent the grid of the race course, remember to initialize it properly.

^Return to top

Design Document

Thinking about object-oriented programming can be difficult and takes practice. The primary objective of this project is to give you practice thinking. The questions below are good starting points for you to think about your design.

You must submit written responses to these questions by Sunday, March 4, 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 your design, how is the grid of the race course represented? What are the advantages of this representation?

  2. In your design, where is the position of a car stored? in the Car object? or in the RaceCourse object? or both?

  3. In your design, where is the fuel level of a car stored? How is it updated after a car moves?

  4. Suppose the main program asks Car #1 to ZoomDown(). How does Car #1 know how far to move? Presumably a RaceCourse method must be invoked. What is the syntax of such an invocation from a Car member function?

  5. In your design, how is the STALEMATE race status determined?

What/how to submit for your design document:

^Return to top


You are provided with 3 main programs listed below. Your design and implementation of the Car and RaceCourse classes must compile and run with these 3 programs without any modification.

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.

You must also create and submit your own test program. Part of your grade depends on this. You should show that you have fully exercised your implementations of the Car and RaceCourse classes. Note: It is acceptable to modify one the main programs given below, but you must use a very different set of obstacles and car movements.

Note: You will also need proj2.h (do not modify this file).

^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 2 is 'proj2'. So, the Unix command will look like:

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

You should submit the following files:

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: 4 Mar 2007 07:49:15 EST