fp-elevators

EECS 183 Final Project: Elevators

November 20: There are several changes to the final project you need to be aware of. See Piazza for more details.

To reduce the amount of work in this project, you no longer need to implement any functions in Game.cpp. If you wish to play your game, see the page for Game.cpp for stub implementations you can insert into the starter code.

Project Due Tuesday, December 8, 2020, 11:59 pm Eastern

Elevators is a project that dabbles in Game Design, Artificial Intelligence, and designing real-world systems. Using C++, you will complete an implementation for a game in which the player operates 3 elevators in a busy building, making decisions and servicing requests to keep the people inside the building as happy as possible.

You will implement the core gameplay of the Elevator game. The high-level architecture of the project will be provided to you, and you will ensure that each piece that you build works correctly and fits together into one cohesive experience.

Here are the pages of this specification, for quick reference while you are coding the project:

We recommend reading through the information on this page and following the links to these pages as you come across them in the below sections.

Final Project Logistics

Teamwork

You will not longer work on this project with your assigned lab team. If you started the project with your lab team, you may share any work you completed as a team before 5pm Eastern on November 18. After that time, you may only share code with your partner.

Starter Files

You can download the starter files here. If you cloned starter code from Github or downloaded it during Lab 9, you do not need to download it another time.

When starting your Elevator project, you need to set your project up in a working directory, so that you can read from and write to files. You can follow the steps from Project 4 to set this up.

Submission and Grading

The autograder can be found here.

You and your partner will receive 10 submits each day and your best overall submission counts as your score. You need to submit all .cpp files in order for the project to compile, even if some of the .cpp files are unchanged from the starter files.

There is no extra credit and no late days for this project. No submissions will be accepted past the deadline. There is no way that we are able to extend the deadline past the posted due date, since it is the last day of class.

Correctness is worth 70 points towards your course grade. Style will not be graded for this project. Your test cases will not be submitted to the autograder or graded, but writing comprehensive tests will be essential for doing well on the project.

Working with a Partner

You may optionally choose to use git to collaborate with your partner. If you do so, make sure that your repository is private, since public repositories are accessible by anyone on the Internet. If anyone in the future copies your code, you and your partner will be referred to the Honor Council.

Collaboration Policy

We want students to learn from and with each other, and we encourage you to collaborate. We also want to encourage you to reach out and get help when you need it. You are encouraged to:

To clarify the last item, you are permitted to look at another student’s code to help them understand what is going on with their code. You are not allowed to tell them what to write for their code, and you are not allowed to copy their work to use in your own solution. If you are at all unsure whether your collaboration is allowed, please contact the course staff via the admin form before you do anything. We will help you determine if what you’re thinking of doing is in the spirit of collaboration for EECS 183.

The following are considered Honor Code violations:

The full collaboration policy can be found in the syllabus.

Overview

Gameplay

The elevators game allows the player to control elevators in a building with the goal of delivering the most people to their desired destination floors while minimizing the wait times (measured in anger levels) of those people.

The main objects that we deal with in the elevator system are as follows. We have 1 Building object. That Building has 10 Floors and 3 Elevators. Each Floor can have up to 10 Persons waiting for an elevator. (See Utility.h for the game parameters.)

A new game begins with all elevators on floor 0 not servicing any requests. During each turn, if there is a new event (i.e. a new person appearing), they will appear in the building on the appropriate floor. While they wait for the Player to send an elevator to their floor to pick them up, they will slowly get angrier (a valid angerLevel ranges from 0 through MAX_ANGER - 1) until this value hits MAX_ANGER and they explode. See the Person section for more info. Each explosion negatively affects the player’s score for the game, which is calculated based on how quickly they can service the people’s requests. The game will continue until either the player lets too many players explode or until they have processed and survived all the events in the game.in file.

Throughout the game, we measure time in ticks (or turns). You can think of a single tick, just as you would think of a second, minute, or any other standard unit of time. During each tick, the most up-to-date information about the game will be presented to the user, and they will have the option to react by entering a move.

The Building::tick() function will update the time and call the tick() function of each of the Floors and Elevators. The Floor::tick() function will then call the tick() function of each of Persons waiting for an elevator on that floor. The below diagram helps explain how the tick() functions will be used to carry out updates throughout the game.

There are 2 streams of information that the game will process while running: 1) A game.in file that contains all of the future events that will appear in the game. 2) The user’s inputs determining how the elevators will move.

The game.in file is essentially a long list of timestamped events. You can find a detailed guide to the format and syntax of the game.in on the Reading and Writing page here. Each event will correspond to a new person appearing on a floor, and it is the Game’s responsibility to process these events as they happen and reflect this new information to the user via the Game’s interface.

With this information, the user will able to see what the current state of the Building looks like, and will be able to determine what they should command the elevators to do to respond to these incoming events.

At any point, the user can save the game as well. This will write the game’s current state into another file (called save.in) that can be loaded up even after quitting the game. The contents of the save-file will look identical to game.in: it will save the current location of all the elevators, the current scoring info, the current time, current people, and the remaining events. This way, we can start back up where we left off after we load a game.

To summarize all possible options, when a player is presented with the game interface, they can enter:

Game Interface

Every turn of the game, the Player will be prompted with the information about the building below:

   -------
   | | | |
9  | | | |
   -------
   | | | |
8  | | | |
   -------
   | | | | U 4   3   1   2
7  | | | | D o   o   o   o
   -------
   | | | |
6  | | | |
   -------
   |2| | |
5  |E| | |
   -------
   | | |9|
4  | | |E|
   -------
   | | | |  3   0   0   3
3  | |E| |D o   o   o   o
   -------
   | | | |U 4   3   2   1   2   1   0   0
2  | | | |  o   o   o   o   o   o   o   o
   -------
   | | | |U 2
1  | | | |  o
   -------
   | | | |
0  | | | |
   -------
    0 1 2

To decode this:

Should the user input a Pickup Move on a Floor, they will be prompted with the following menu:

Select People to Load by Index
All people must be going in same direction!
               O    O    O    O    O    O    O    O    O    O
              -|-  -|-  -|-  -|-  -|-  -|-  -|-  -|-  -|-  -|-
               |    |    |    |    |    |    |    |    |    |
              / \  / \  / \  / \  / \  / \  / \  / \  / \  / \
INDEX:         0    1    2    3    4    5    6    7    8    9
ANGER:         3    2    4    2    2    0    1    1    4    4
TARGET FLOOR:  8    1    0    1    2    1    0    8    1    9

Here, they can enter a string of indexes ("024" for example) to pick up the people at those indices, provided they all want to travel in the same direction. The details of this move can be found on the Move page.

Code Organization

In order to tackle this fairly large project, we have given you starter code that breaks down the Game into classes that will interact with each other. It will be your responsibility to complete the implementation of each of these classes. A diagram of all the classes involved in the project as well as a high-level schematic of how they interact is pictured below.

Starter Code

We have provided you with starter code for all of the classes mentioned above, and some of them have been written for you. It is imperative that you do not change any of these implementations - doing so may lead to a zero on the project.

Utility.h Explanation: This header file contains all of the Global Constants you should be using throughout the project. Make sure to look over Utility.h to see what these values are. Think about where you want to use these values and ensure you are using them.

We have also linked in all the libraries that we think you need to complete this project. Should you feel the need to use another library, we have compiled a list of other acceptable libraries that you can #include in your .cpp files to help you. Please note that these are NOT necessary to complete the CORE.

If a library is not listed here, you CANNOT include it in your .cpp files.

sstream
cmath

Specifications for .cpp files

As mentioned above, you will be implementing several key functions in each of the following classes. The order we’ve linked them here is a preferred order to tackle the functions, but keep in mind each class has its own difficulty ratings associated with each function you implement. You can find that information on each class’s page, linked below:

  1. Person.cpp
  2. Elevator.cpp
  3. Floor.cpp
  4. Move.cpp
  5. Building.cpp
  6. Game.cpp

Testing

It will be your responsibility to thoroughly test your own functions and ensure they are working correctly. The best way to go about this is to do something called unit testing. This will involve creating a test function in test.cpp for each class, in which you would create objects for the type you are testing, and ensuring that it works correctly. For example, a unit test for Person.cpp would look something like this.

#include <iostream>
#include "Person.h"
#include "Utility.h"
using namespace std;

void person_test();

void start_tests() {
   person_tests();
}

void person_test() {
    //initialize a person with targetFloor 5, anger 5
    Person p("0f0t5a5");

    cout << p.getTargetFloor() << " " << p.getAngerLevel() << " Expected 5 5" << endl;

    //simulate time being a multiple of TICKS_PER_ANGER_INCREASE
    bool exploded = p.tick(TICKS_PER_ANGER_INCREASE);

    cout << exploded << " Expected 0" << endl;

    cout << p.getTargetFloor() << " " << p.getAngerLevel() << " Expected 5 6" << endl;

    //simulate time not being a multiple
    p.tick(TICKS_PER_ANGER_INCREASE - 1);

    //no change
    cout << p.getTargetFloor() << " " << p.getAngerLevel() << " Expected 5 6" << endl;

    p.tick(TICKS_PER_ANGER_INCREASE); //7 after

    p.tick(TICKS_PER_ANGER_INCREASE); //8 after

    p.tick(TICKS_PER_ANGER_INCREASE); //9 after

    exploded = p.tick(TICKS_PER_ANGER_INCREASE);

    cout << exploded << " Expected 1" << endl;
}

While we will not be grading your test cases, to ensure correctness of your implementations, write your own tests for all the functions you implement.

Suggested Timeline

If you follow this timeline, you should be on track to complete the project on time: