Project 2: Parking lot manager

UC Irvine - Fall ‘22 - ICS 45C

Read everything before you start!
Updates will be listed here:

  • added note saying you don’t need to check for invalid parameters;
  • expanded example on check price command;
  • fixed autograder for take spot when current row is full, and added an example in the command description;
  • added a hint for defining the array size.

Sections

Due date

This project is due at 10PM PT on Friday of week 5 (2022-10-28). You have a 15-minute buffer for any technical issues and can use your extra days if needed.

Context

Your last event was a success! You ordered just the right amount of pizza. There was a small problem though, people didn’t know where to park and how much they should pay for it.

So your help was requested again, and now you need to help with managing the parking lot. You’ll tell people where to park and calculate how much they should be charged.

What you have to do

You will create a program to manage a parking lot. The parking lot consists of 4 rows of 6 spots each, so a total of 24 spots. Your program will help manage open spots, calculate prices, and keep track of a few statistics.

Your program should have a main function that interacts with the user through standard input/output. Your program should show a menu, as defined below, and accept commands the user wants to perform. You should read entire lines from the input. (see string notes)

Although other functions are not required in this project, they might be very helpful!

Greeting

You will start with a greeting for the user:

----------
Hello! Welcome to the parking lot manager.
I'll help you find a spot!
----------

Then, you will show a menu so the user knows that commands are available.

----------
|  MENU  |
----------
Please use one of the following commands:
  - (CT) check time
  - (AT) advance time
  - (SS) show spots
  - (TS) take spot
  - (CP) check price
  - (LS) leave spot
  - (CS) check stats
  - (EX) exit the program

What each command does will be defined in the next sections. After executing each command, except EXit, you should print the menu again and ask for a new command.

Some of the commands have parameters following them, so you might need to tokenize the line (see string notes). The maximum number of parameters across all commands is 3. All commands will be given in a single line, with any parameters separated by a single space.

The commands below are mentioned in the order you should probably implement them, and test cases will test your code assuming such order. For example, to complete command 2 (CT), you should have completed command 1 (EX). You’re free to implement them in a different order, just be mindful of the test cases.

Invalid commands

You should warn the user about any invalid commands, and print the menu again to get a new command. For example:

** GREETING **

** MENU **
[INPUT] XYZ
Sorry, that command is invalid.

** MENU **

Where ** GREETING ** shows where you should print the greeting we defined above, ** MENU ** illustrate where you print the entire menu message, and [INPUT] denotes that the user typed that line.

This notation will be used in the rest of the command examples.

Note: it is safe to assume parameters will be well formed. Only commands might be invalid, but if you receive a command AT, you can expect its parameters to be 1 or two valid numbers.

Command 1: EXit

  • Parameters: this command does not take any parameters.
  • Functionality: you should print Goodbye! and exit the program.

Example usage:

** GREETING **

** MENU **
[INPUT] EX
Goodbye!

Command 2: Check Time

  • Parameters: this command does not take any parameters.
  • Functionality: you should print the how long the parking lot has been open in minutes, with the following message:
We have been open for [MIN] minutes!

To simplify everything, you don’t need to show dates/hours, you can only store the minutes which will be modified by the next command.

The time should start at 0 when your program starts.

Example usage:

** GREETING **

** MENU **
[INPUT] CT
We have been open for 0 minutes!

** MENU **
[INPUT] EX
Goodbye!

Command 3: Advance Time

  • Parameters: one or two parameters. If one parameter, it means minutes, if two parameter, first one is hours, second one is minutes.
  • Functionality: this command will advance the time by the given parameters.

Example usage:

** GREETING **

** MENU **
[INPUT] CT
We have been open for 0 minutes!

** MENU **
[INPUT] AT 30

** MENU **
[INPUT] CT
We have been open for 30 minutes!

** MENU **
[INPUT] AT 1 20

** MENU **
[INPUT] CT
We have been open for 110 minutes!

** MENU **
[INPUT] EX
Goodbye!

Command 4: Show Spots

  • Parameters: one parameter, with a value of O, T, or A. You can assume it’ll be only one of those characters.
  • Functionality: this command lists the spots that are Open, Taken, or All of them, with the spots separated by their rows.

When your program starts, all spots should be open.

Example usage:

** GREETING **

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

** MENU **
[INPUT] SS T
Taken spots:
Row 1:
Row 2:
Row 3:
Row 4:

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

Taken spots:
Row 1:
Row 2:
Row 3:
Row 4:

** MENU **
[INPUT] EX
Goodbye!

Command 5: Take Spot

  • Parameters: three parameters, the row number, the spot number in that row, and the vehicle plate. You can assume there are no spaces in the plate number.
  • Functionality: this command tries to take a spot for this vehicle, and let the user know where/if it parked.

If the spot is already taken, you should try to park the vehicle on the next one in increasing order of spot number (i.e., go down current row, then check next row starting from the beginning and so on). If there are no “bigger” spots available, you should tell the user you couldn’t do it.

If the car was parked, you should print Parked PLATE_NUM in spot SPOT_NUM.. If there were no spots, you should print Sorry, you've passed all the open spots already!.

IMPORTANT: the numbers you receive as parameters are the row number and the spot number in that row. So you might receive something like 2 4, which would indicate row 2, 4th spot -> spot #10 overall.

Hint: you should probably figure out how to save the current time when a spot is taken, it’ll come in handy when you’re working on the next command.

Example usage 1 (open spot):

** GREETING **

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

Taken spots:
Row 1:
Row 2:
Row 3:
Row 4:

** MENU **
[INPUT] TS 3 5 ABC123
Parked ABC123 in spot 17.

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 18
Row 4: 19 20 21 22 23 24

Taken spots:
Row 1:
Row 2:
Row 3: 17
Row 4:


** MENU **
[INPUT] EX
Goodbye!

Example usage 2 (spot taken, next available):

** GREETING **

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

** MENU **
[INPUT] TS 4 5 ABC123
Parked ABC123 in spot 23.

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 24

** MENU **
[INPUT] TS 4 5 ABC456
Parked ABC456 in spot 24.

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22

** MENU **
[INPUT] EX
Goodbye!

Example usage 3 (spot taken, go to the first spot of the next row):

** GREETING **

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

** MENU **
[INPUT] TS 3 6 ABC123
Parked ABC123 in spot 18.

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17
Row 4: 19 20 21 22 23 24

Taken spots:
Row 1:
Row 2:
Row 3: 18
Row 4:

** MENU **
[INPUT] TS 3 6 ABC456
Parked ABC456 in spot 19.

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17
Row 4: 20 21 22 23 24

Taken spots:
Row 1:
Row 2:
Row 3: 18
Row 4: 19

** MENU **
[INPUT] EX
Goodbye!

Example usage 4 (spot taken, no available spots):

** GREETING **

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

** MENU **
[INPUT] TS 4 6 ABC123


** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23

** MENU **
[INPUT] TS 4 6 ABC456
Sorry, you've passed all the open spots already!

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23

** MENU **
[INPUT] EX
Goodbye!

Command 6: Check Price

  • Parameters: one or two parameters. If one parameter, it indicates the plate of a vehicle that is currently parked. If two parameters, it indicates the row and spot number in that row.
  • Functionality: this command calculates how much is due by the vehicle.

If you received one parameter, you can assume there is always one vehicle with the given plate. If you received two parameters, you can assume the row/spot is always taken.

IMPORTANT: the numbers you receive as parameters are the row number and the spot number in that row. So you might receive something like 2 4, which would indicate row 2, 4th spot -> spot #10 overall.

This command calculates how much a vehicle should pay. The pay structure is as follows:

$10 per each hour, and you should calculate the proportional price for partial hours.
For example:

  • 70 minutes would be $11
  • 30 minutes would be $5
  • 15 minutes would be $2
  • 12 minutes would be $2
  • 10 minutes would be $1
  • 5 minutes would be free

Notice we always round down and don’t use cents.

However, we have a promotion where after 5h they get 1h free.
For example:

  • 300 minutes would be $50
  • anything between 301 and 365 minutes would also be $50
    • minutes from 301 to 360 would be free because of the promotion;
    • minutes from 361 to 365 would be free because of our rounding down. They still count to the price, but not enough to add 1 to the total. At 366 we would count 306 “paying minutes” and that would finally get to $51.
  • 370 minutes would be $51
  • 420 minutes would be $60

This cannot be repeated! So if they stay 12h, they only get 1 free hour and would pay $110.

Once you have the value, you should print:

Vehicle PLATE_NUM has been in SPOT_NUM for MINUTES minutes.
It owes $AMOUNT_OWED at the moment.

Example usage:

** GREETING **

** MENU **
[INPUT] CT
We have been open for 0 minutes!

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

** MENU **
[INPUT] TS 4 5 ABC123
Parked ABC123 in spot 23.

** MENU **
[INPUT] SS T
Open spots:
Row 1:
Row 2:
Row 3:
Row 4: 23

** MENU **
[INPUT] AT 30

** MENU **
[INPUT] CP 4 5
Vehicle ABC123 has been in 23 for 30 minutes.
It owes $5 at the moment.

** MENU **
[INPUT] AT 30

** MENU **
[INPUT] CP ABC123
Vehicle ABC123 has been in 23 for 60 minutes.
It owes $10 at the moment.

** MENU **
[INPUT] AT 4 0

** MENU **
[INPUT] CP 4 5
Vehicle ABC123 has been in 23 for 300 minutes.
It owes $50 at the moment.

** MENU **
[INPUT] AT 30

** MENU **
[INPUT] CP ABC123
Vehicle ABC123 has been in 23 for 330 minutes.
It owes $50 at the moment.

** MENU **
[INPUT] AT 30

** MENU **
[INPUT] CP ABC123
Vehicle ABC123 has been in 23 for 360 minutes.
It owes $50 at the moment.

** MENU **
[INPUT] AT 30

** MENU **
[INPUT] CP ABC123
Vehicle ABC123 has been in 23 for 390 minutes.
It owes $55 at the moment.

** MENU **
[INPUT] AT 30 0

** MENU **
[INPUT] CP ABC123
Vehicle ABC123 has been in 23 for 2190 minutes.
It owes $355 at the moment.

** MENU **
[INPUT] EX
Goodbye!

Command 7: Leave Spot

  • Parameters: one or two parameters. If one parameter, it indicates the plate of a vehicle that is currently parked. If two parameters, it indicates the row and spot number.
  • Functionality: this command vacates the desired spot. If a plate is given, you should look through the spots to find it.

If you received one parameter, you can assume there is always one vehicle with the given plate. If you received two parameters, you can assume the row/spot is always taken.

IMPORTANT: the numbers you receive as parameters are the row number and the spot number in that row. So you might receive something like 2 4, which would indicate row 2, 4th spot -> spot #10 overall.

This command clears the specified spot and charges the vehicle whatever they should pay. After clearing the spot, you should print:

Vehicle PLATE_NUM left spot SPOT_NUM.
It was parked there for MINUTES minutes and paid $AMOUNT_PAID.

Example usage 1 (row and spot):

** GREETING **

** MENU **
[INPUT] CT
We have been open for 0 minutes!

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

** MENU **
[INPUT] TS 4 5 ABC123
Parked ABC123 in spot 23.

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 24

** MENU **
[INPUT] AT 30

** MENU **
[INPUT] LS 4 5
Vehicle ABC123 left spot 23.
It was parked there for 30 minutes and paid $5.

** MENU **
[INPUT] SS O
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

** MENU **
[INPUT] EX
Goodbye!

Example usage 2 (plate):

** GREETING **

** MENU **
[INPUT] AT 10

** MENU **
[INPUT] CT
We have been open for 10 minutes!

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

Taken spots:
Row 1:
Row 2:
Row 3:
Row 4:

** MENU **
[INPUT] TS 3 5 ABC123
Parked ABC123 in spot 17.

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 18
Row 4: 19 20 21 22 23 24

Taken spots:
Row 1:
Row 2:
Row 3: 17
Row 4:

** MENU **
[INPUT] AT 1 30

** MENU **
[INPUT] LS ABC123
Vehicle ABC123 left spot 17.
It was parked there for 90 minutes and paid $15.

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 23 24

Taken spots:
Row 1:
Row 2:
Row 3:
Row 4:

** MENU **
[INPUT] EX
Goodbye!

Command 8: Check Stats

  • Parameters: no parameters.
  • Functionality: this command prints the total number of vehicles that have parked, the number of vehicles currently parked, the total amount of money received so far, and the average price vehicles have paid.

You should use this message:

Total vehicles parked: TOTAL_PARKED
Vehicles currently parked: CURRENTLY_PARKED
Total amount charged: $TOTAL_CHARGED
Average charge per vehicle: $AVERAGE_CHARGE

Note that:

  1. total vehicles that have parked means vehicles that have taken a spot successfully, if they tried to park and couldn’t, they don’t count;
  2. number of vehicles currently parked means the vehicles that have taken a spot but have not left yet;
  3. total amount of money received means the sum of prices for vehicles that have left;
  4. average price vehicles have paid equals the total money received split by the vehicles that have left (i.e., have parked but not currently parked); you should round this value down!

Hints:

  • To calculate (1), revisit your code for TS;
  • To calculate (2), revisit your code for TS and LS;
  • To calculate (3), revisit your code for LS;
  • To calculate (4), use value of (3) and the difference between all vehicles that have parked and the ones that are currently parked. Be careful with a division by zero here!

Sample usage:

** GREETING **

** MENU **
[INPUT] TS 4 5 ABC123
Parked ABC123 in spot 23.

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22 24

Taken spots:
Row 1:
Row 2:
Row 3:
Row 4: 23

** MENU **
[INPUT] CS
Total vehicles parked: 1
Vehicles currently parked: 1
Total amount charged: $0
Average charge per vehicle: $0

** MENU **
[INPUT] AT 50 0

** MENU **
[INPUT] TS 4 5 ABC456
Parked ABC456 in spot 24.

** MENU **
[INPUT] AT 30 7

** MENU **
[INPUT] SS A
Open spots:
Row 1: 1 2 3 4 5 6
Row 2: 7 8 9 10 11 12
Row 3: 13 14 15 16 17 18
Row 4: 19 20 21 22

Taken spots:
Row 1:
Row 2:
Row 3:
Row 4: 23 24

** MENU **
[INPUT] CS
Total vehicles parked: 2
Vehicles currently parked: 2
Total amount charged: $0
Average charge per vehicle: $0

** MENU **
[INPUT] CP ABC123
Vehicle ABC123 has been in 23 for 4807 minutes.
It owes $791 at the moment.

** MENU **
[INPUT] CP ABC456
Vehicle ABC456 has been in 24 for 1807 minutes.
It owes $291 at the moment.

** MENU **
[INPUT] LS 4 6
Vehicle ABC456 left spot 24.
It was parked there for 1807 minutes and paid $291.

** MENU **
[INPUT] CS
Total vehicles parked: 2
Vehicles currently parked: 1
Total amount charged: $291
Average charge per vehicle: $291

** MENU **
[INPUT] LS ABC123
Vehicle ABC123 left spot 23.
It was parked there for 4807 minutes and paid $791.

** MENU **
[INPUT] CS
Total vehicles parked: 2
Vehicles currently parked: 0
Total amount charged: $1082
Average charge per vehicle: $541

** MENU **
[INPUT] EX
Goodbye!

Project Hints and Tips

There are some command-specific hints too, double check you didn’t miss those in the instructions above.

1) 2D-array

To store a two-dimensional value, you don’t need a two-dimensional array!

Assuming your 2D array is [N][M] sized, and you want to access [i][j], you could create a 1D array of size [N * M] and access [i * M + j].

For example, if you want a grid of 2x3, it is the same as a one-dimension array of 6 spots. Position [0][0] would be position [0], then, on the next row, position [1][1] would be position [4].

To make it more visual, this array:

0 1 2
3 4 5

Could be stored like this:

0 1 2 3 4 5

That being said, you can create a 2D array if you want. You just add all dimensions in the variable declaration:

int array[2][3];
array[1][2] = 5;

2) string functions

You might find these resources useful:

By the way, you can have an array of strings ;)

*IMPORTANT*: if you’re using code from somewhere that’s not yours (including adapting something like the stackoverflow answer linked above), you should have a reference to the place you found it!

3) remember to clear variables

When you’re tokenizing the user command, make sure you clear values. For example, if you just received AT 2 3 (advancing the time by 2h03m), and the next command is CP 0 (checking the price for vehicle with plate 0), you don’t want to mix them up and actually look for the price of spot 0 3.

4) use functions if you’re comfortable

Seriously! Although helper functions are not required in this project, they can be very helpful. For example, you could have a function that finds a vehicle for you depending if you have the row/spot or plate number; that would help in a couple of commands.

5) run code without typing input

This project has pretty verbose inputs and outputs, and for a few of the commands you need to run other commands to setup everything before you can actually test it. So it can get kinda boring/tiring to type the same thing over and over again.

To debug with a single set of inputs quickly, you should gather all your input into a file. For example, I’ve copied only the input from the last example from command 8 below:

TS 4 5 ABC123
SS A
CS
AT 50 0
TS 4 5 ABC456
AT 30 7
SS A
CS
CP ABC123
CP ABC456
LS 4 6
CS
LS ABC123
CS
EX

Now, we create a text file that only has this content. I like to use .in as an extension, to indicate input. As an example, you can download this sample file here: check_stats_input.in

Now, once you have this file and your compiled binary, instead of just running it like ./project2 (or .\project2.exe on Windows), you can use an input redirect to tell the computer your code should read from that file. So you’d end up with this ./project2 < check_stats_input.in
Running that command, your code should process all those commands, one by one, just as if you had typed them. This can be extremely helpful if you’re debugging a single thing and need to set up everything else before that, e.g., CS or LS commands in this project.

6) hard-coding array sizes

To define an array of some size and loop over it, you could do something like we did in lecture. Use a define to create a constant that the compiler accepts as a size.

For example:

#include <iostream>

#define ARRAY_SIZE 10

using namespace std;

int main() {
  int values[ARRAY_SIZE];
  for (int i=0; i < ARRAY_SIZE; i++) {
    values[i] = i;
    cout << "values[" << i << "]: " << values[i] << '\n';
  }
  return 0;
}

Doing it this way is better than hard-coding the size, in this case 10, in a lot of places.
If you just use int values[10], then if you want to change the size later on, you’d have to find every place you used the literal 10.

By using #define ARRAY_SIZE 10 and ARRAY_SIZE anywhere you need, if you want to change the size later, you’d only need to modify the define line.

Like we discussed in lecture, what #define ARRAY_SIZE 10 does is it creates a compile-time constant, which means that when you compile your code, the compiler finds all occurrences of ARRAY_SIZE and replaces it with 10.

Submission

Your code should be named parking_lot_manager.cpp. If you need a starter file, you can click here. You should submit your solution on gradescope: https://www.gradescope.com/courses/443728/assignments/2341229/ You can submit it as many times as you want; just remember that gradescope might not give you instant feedback.

Your code will be checked for compilation (e.g., warnings), style, and functionality issues. Compilation and style checks will be completely open, so you know what needs to be changed. Functionality tests will be a mix of open and hidden ones. You should be able to debug your code based on the open ones. For this project, all functionality tests use standard IO (cin/cout) to communicate with your code and assume everything is inside main.

Sample runs

Go back up and check the command descriptions, all those examples are valid runs!
Just replace:

** GREETING **

with:

----------
Hello! Welcome to the parking lot manager.
I'll help you find a spot!
----------

and replace:

** MENU **

with:

----------
|  MENU  |
----------
Please use one of the following commands:
  - (CT) check time
  - (AT) advance time
  - (SS) show spots
  - (TS) take spot
  - (CP) check price
  - (LS) leave spot
  - (CS) check stats
  - (EX) exit the program