fp-elevators
Reach AI
Overview
So far you’ve been deep in the trenches of implementing a functional game that interacts with a user. Now, it’s time to pivot and think as the user of this game. Specifically, what kind of decisions should you make as a player of this game to get the best performance from the elevators?
NOTE: This part of the specification is tentative and subject to change up until the due date of the Core.
First Steps
Play through the game, and for each move you make, ask yourself why you decided to do the thing you did. What kind of rules come to mind?
Understanding the Metrics
What does it mean to be the “best” elevator? To answer this question, we will resort to defining a SatisfactionIndex
. Make sure to read through and understand what each of these values represent. If you had to play the game trying to get the best possible values for these, what would you do?
The AI Move Framework
Among the functionality we’ve built for you, we’ve created the files AI.cpp
and AI.h
, which are provided with the same information that is provided to the Player via the terminal and should create valid Move
s. For the reach, you will be responsible for implementing the functions in AI.cpp
in such a way that gets good performance. More concretely, we will evaluate 2 things:
- Validity: Your AI should only produce valid moves (from
getAIMoveString
) and valid pickup lists (fromgetAIPickupList
). - Performance: Your AI should try and optimize the metrics in the
SatisfactionIndex
on certain game files. It is up to you as to what benchmark you’d like to optimize!
Implementation Considerations
You are encouraged to devise helper functions to aid you in writing the functions in AI.cpp
; you can add these directly to AI.cpp
when you submit. You are also permitted to include any libraries present in the C++11 standard template library, provided that you don’t have to modify your build process to get them to work. Do not edit AI.h. We should be able to run your code immediately when we make a project in XCode or Visual Studio.
Testing your AI
As always, it is imperative to test your code well. Elevators reach is different from the other 183 projects in that your grade is determined by performance for AI.cpp
. So, now your tests are not only concerned with correctness, but also with benchmarking the power of your AI. You should be constantly testing whether your AI performs well on different inputs.
There are two ways to test your AI:
- When running your implementation for the Core, select either Load saved game (once you have completed the function
Game::playGame
) or Start new game. Then enter 2 for Watch AI play. As you play the game, when you are prompted to Enter move: or Choices: for a pickup list, just press enter. Your AI should provide the move or pickup list. - Submit your AI to the autograder.
Input Files
A description of input files and how to use them are found on this page: Input Files
Submitting
You will submit your files to the autograder for the Reach. You will submit AI.cpp
to the autograder.
Grading
Your AI, the functions in AI.cpp
, will be graded by the performance of your AI with a variety of input events:
- We will compile your AI.cpp file with the staff implementation for the Core. Your AI will not be tested with your solution files for the Core.
- We will execute your AI repeatedly with different game input files. Game input files will be a long list of timestamped events, similar to what is shown in
game.in
andsave.in
found in the starter files. - The input files will be of differing difficulty, for example by varying the number of events and starting
angerLevel
s. - The input files will have different patterns. Examples are:
- A larger potion of
Person
s entering the bottom/lower floors with a higher target floor. These tests are labeled “Morning” on the autograder. - Many
Person
s with a lower target floor. These tests are labeled “Evening” on the autograder. - Or a random mix. These tests are labeled “Random” on the autograder.
- A larger potion of
- The performance of your AI will be measured using a subset of the metrics in
SatisfactionIndex
, recorded at the end of each game. The final values will be compared to the passing thresholds determined by staff. The autograder will show you which test cases you pass and which you do not, along with yourSatisfactionIndex
metrics, for each test.
A Note
This section may seem fairly open-ended, and you may feel slightly confused about what your AI is responsible for doing. This is by design. Often times, real-world “specs” are vague about a lot of implementation details. It becomes the responsibility of the programmer to think about the problem and decide on what’s best for the project. Think! Discuss with your groupmates! Think some more! Try things! Fail! Try again! Have fun!
Functions
The functions in AI.h
are not part of a class.
You will be writing the implementations for the following functions:
getAIMoveString
(Difficulty: ★★★★☆)getAIPickupList
(Difficulty: ★★★★★)
getAIMoveString
/*
* Requires: buildingState is a valid state representing the current building
* Modifies: Nothing
* Effects: Returns a string that represents the decision the AI makes
* given the current state of the building, which it reads
* from buildingState.
* The string should share the exact format as a
* human player's move input.
*/
string getAIMoveString(const BuildingState& buildingState);
This function should determine the next move when playing the game.
const BuildingState& buildingState
parameter is a BuildingState object. YourgetAIMoveString
function can use the public member functions to check the current state of the building to determine what moves to make.string
return value will be a valid move command string, such as"e1f4"
or"e1p"
, as determined by this function.
getAIPickupList
/*
* Requires: buildingState is a valid state representing the current building
* move is a pickup move that was generated by getAIMoveString()
* floorToPickup represents the floor the pickup move occurred.
* Modifies: Nothing
* Effects: Returns a string representing which people indices
* should be picked up. The string should share the exact format
* as a human player's pickup list input.
*/
string getAIPickupList(const Move& move, const BuildingState& buildingState, const Floor& floorToPickup);
This function should determine the pickup list based on the move and state of the building and floor.
move
is a string representing the move, such as"e1p"
.const BuildingState& buildingState
parameter is a BuildingState object. SeeAI.cpp
(Reach) for additional information about BuildingState.const Floor& floorToPickup
parameter is a Floor object. YourgetAIPickupList
function can use the public member functions to check the current state of the Floor (i.e., Person instances waiting to be picked up) to determine what pickup list would be optimal.string
return value will be a valid pickup list string, such as"012"
or"2689"
, as determined by this function. Because there are a maximum of 10 people per floor, every index will be a single digit.
An example pickupList
: "0135"
“I choose the people at indices 0, 1, 3, and 5 to pickup”
A pickupList
is valid if it meets the following conditions:
- There are no duplicate indices present in
pickupList
- Each element of
pickupList
is a non-negative digit - The length of the
pickupList
is less than or equal to the capacity of an elevator - The maximum value pointed to by an index of
pickupList
must be strictly less than the number of people on the floor pointed to bypickupFloorNum
- Each person represented by an index in
pickupList
must be going in the same direction relative topickupFloorNum