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

• For this project, you may choose to work with one other student who is currently enrolled in EECS 183.
• Although you are welcome to work alone if you wish, we encourage you to consider partnering up. If you would like a partner but don’t know anyone in the class, we encourage you to use the Search for Teammates post on Piazza if you want to find someone! Please make sure to mark your search as Done once you’ve found a partner.
• As a further reminder, a partnership is defined as two people. You are encouraged to help each other and discuss the project in English (or in some other human language), but don’t share project code with anyone but your partner.
• To register a partnership on the autograder, go to the autograder link for the project and select “Send group invitation”. Then, add your partner to the group by entering their email when prompted. They will receive a confirmation after registration, and must accept the invitation before the partnership can submit. You must choose whether or not to register for a group on the autograder before you can submit. If you select the option to work alone, you will not be able to work with a partner later in the project. If a partnership needs to be changed after you register, you may submit an admin request.
• The partnership will be treated as one student for the purpose of the autograder, and you will not receive additional submits beyond the given ten submits per day.
• If you decide to work with a partner, be sure to review the guidelines for working with a partner.
• If you choose to use late days and you are working in a partnership, review this document for how late days will be charged against each 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:

• Give or receive help in understanding course concepts covered in lecture or lab.
• Practice and study with other students to prepare for assessments or exams.
• Consult with other students to better understand project specifications.
• Discuss general design principles or ideas as they relate to projects.
• Help others understand compiler errors or how to debug parts of their code.

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:

• Submitting others’ work as your own.
• Copying or deriving portions of your code from others’ solutions.
• Collaborating to write your code so that your solutions are identifiably similar.
• Sharing your code with others to use as a resource when writing their code.
• Receiving help from others to write your code.
• Sharing test cases with others if they are turned in as part of your solution.
• Sharing your code in any way, including making it publicly available in any form (e.g. a public GitHub repository or personal website).

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:

• Q: This will quit the game
• S: This will save the game
• Enter a move: This will advance the game forward one turn

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:

• There are 10 Floors, numbered 0 (bottom) to 9 (top)
• There are 3 Elevators, numbered 0 (leftmost) to 2 (rightmost)
• In the current state, Elevator 0 is servicing a request and is on its way down to Floor 2 (the target floor is listed above the E, which stands for elevator)
• Similarly, Elevator 2 is servicing a request and is on its way up to Floor 9
• Elevator 1 is not servicing a request this turn, and so the user can input a Move for it if they desired. See the Move page for more details on what types of Moves the user can input.
• Currently, there are active requests on Floors 1, 2, 3, and 7. These are requests indicating that the people on the Floor want to go up (note the U on Floors 1, 2, and 7), or down (D on Floors 3 and 7). Note that it is possible to have people wanting to go in opposite directions.
• The os each indicate a Person. So, there is 1 Person waiting on Floor 1, 8 on Floor 2, and 4 on Floors 3 and 7.
• The number above each Person’s head refers to their angerLevel. See the Person page for more info on what this means.

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:

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:

• Before Thanksgiving break: finish Project 4 and study for Assessment 3.
• November 30 (after Thanksgiving break): Start coding the project, make first submission to autograder as a team, even if submitting only the starter code.
• December 4: All classes completed. Integrate classes into one application and make sure the combined code compiles on autograder.
• December 8, 3pm: Make final submission; because there are no late days, make sure to give yourself a large buffer in case things do not work as expected! Final due time is 11:59pm.