(In C++ language please)Write a simulation program of the lines at a grocery sto
ID: 3690882 • Letter: #
Question
(In C++ language please)Write a simulation program of the lines at a grocery store. The program will be similar to the car wash simulation, except that there are multiple queues instead of one. You might use a vector of queues to simulate the lines. Assume that there are five cashier lines at the grocery store. Customers enter randomly to check out, and then enter the shortest line. If the lines are equal, then the first available line is chosen. Each transaction takes a random amount of time to complete.
For additional work, expand the grocery line program to allow shoppers to:
Avoid a line if al lines are a certain length
Leave a line if they have waited beyond a certain line
Check if another line is shorter at specified time intervals
Switch lines if another line is shorter
Explanation / Answer
Simulation.h
#pragma once
#include <iostream>
#include <ctime>
using namespace std;
#include "Customer.h"
#include "Timer.h"
#include "DynamicQueue.h"
const int NUM_CATEGORIES = 5;
class Simulation {
public:
//default constructor
Simulation() {
avgCustomerServiceTime = 0;
avgCustomerWaitingTime = 0;
avgCashierIdleTime = 0;
totalServiceTime = 0;
totalCustomerWaitingTime = 0;
totalCashierIdleTime = 0;
totalNumberOfCustomers = 0;
customersRemaining = 0;
servicePercent = new int[NUM_CATEGORIES];
allCashiers = new dynamic_queue<Customer>[numCashiers];
//get inputs for simulation
cout << "Please enter the average arrival rate of customers in number per minute: " << endl;
cin >> arrivalRate;
cout << "Please enter the number of registers: " << endl;
cin >> numCashiers;
//create the correct number of cashiers
for(int i = 0; i < numCashiers; i++) {
allCashiers[i] = *new dynamic_queue<Customer>;
}
cout << "Please enter the length of time to run the simulation in minutes: " << endl;
cin >> lengthOfSimulation;
//cout << "Please enter the distribution of customer service times: " << endl;
int percent = 0;
int sum = 0;
for (int i = 0; i < NUM_CATEGORIES; i++) {
//cout << " <= " << (i + 1) << " min. ";
//cin >> percent;
//servicePercent[i] = percent;
//sum += percent;
//cout << "sum: " << sum << endl;
servicePercent[i] = 20 + sum;
sum += 20;
}
//check to make sure the inputs add up to 100
while (sum != 100) {
cout << "Invalid distribution. Must add up to 100 %" << endl;
cout << "old sum was: " << sum << endl;
sum = 0;
for (int i = 0; i < NUM_CATEGORIES; i++) {
cout << " <= " << i + 1 << " min. "; cin >> percent;
servicePercent[i] = percent;
sum += percent;
cout << "sum: " << sum << endl;
}
}
//set the countdown timer
myTimer.set(lengthOfSimulation);
//intialize random number generator
long seed = long(time(0));
srand(seed);
}
//destructor
//deletes all dynamically created elements of allCashiers[]
//deletes dynamically created member arrays
~Simulation() {
for (int i = 0; i < numCashiers - 1; i++) {
delete &allCashiers[i];
}
delete [] allCashiers;
delete [] servicePercent;
}
//this function is the 'brains' of the simulation. It computes and processes customers and cashiers for the runtime specified.
void run() {
while (myTimer.timeRemaining() > 0) {
//go through each cashier and run the service function which will check
//if their customer is ready to check out and do so if able
for (int i = 0; i < numCashiers; i++) {
if (!allCashiers[i].isEmpty()) {
int busyTimeLeft = allCashiers[i].getHead().getServiceTime();
service(busyTimeLeft, i);
}
else {
totalCashierIdleTime++;
}
}
checkForNewCustomer();
myTimer.tick();
}
cout << " Not accepting any more customers -- service remaining customers in line" << endl;
for (int i = 0; i < numCashiers; i++) {
while (!allCashiers[i].isEmpty()) {
int busyTimeLeft = allCashiers[i].getHead().getServiceTime();
service(busyTimeLeft, i);
}
}
display(cout);
}
//function is passed the remaining service time of the customer in the front of the line
// as well as the cashier the customer is in line for
void service(int& busyTimeRemaining, int cashier) {
if (busyTimeRemaining > 0) { //the head customer still has more service time to process
busyTimeRemaining--;
allCashiers[cashier].getHead().setServiceTime(busyTimeRemaining);
//add waiting time of the customers in line to the total
totalCustomerWaitingTime += allCashiers[cashier].getSize() - 1;
return;
}
else {
//check to see if this cashier are nonempty and if they are have each on
if (!allCashiers[cashier].isEmpty()) { //there is a customer ready to check out
int arrivalTime = allCashiers[cashier].getHead().getArrivalTime();
allCashiers[cashier].dequeue(); //cash out head customer
if (!allCashiers[cashier].isEmpty()) {
Customer nextCust = allCashiers[cashier].getHead();
busyTimeRemaining = nextCust.getServiceTime();
}
customersRemaining--;
}
}
}
//This function checks for and adds customers to the smallest line of a cashier
void checkForNewCustomer() {
//activates new customer procedure for each arrival per minute. Case1: arrivalRate > 1
for (int i = 0; i < arrivalRate; i++) {
//a new customer is ready to get in line, create random service time
int r = rand() % 100;
int serviceTime = 0;
int culmServiceTime = servicePercent[serviceTime];
while (r > culmServiceTime) {
culmServiceTime += servicePercent[serviceTime];
serviceTime++;
}
totalServiceTime += serviceTime + 1;
//create a new customer and add it to the smallest line at a cashier
Customer newCust(myTimer, serviceTime + 1);
totalNumberOfCustomers++;
customersRemaining++;
int min = 9999999;
int smallestLine = 0;
for (int i = 0; i < numCashiers; i++) {
if (allCashiers[i].getSize() < min) {
min = allCashiers[i].getSize();
smallestLine = i;
}
}
allCashiers[smallestLine].enqueue(newCust);
}
if (arrivalRate < 1) { //Case 2: arrivalRate < 1
//random number between 0 and 99
int x = rand() % 100;
//calculates the probability that a customer has arrived
if (x < 100 * arrivalRate) {
//a new customer is ready to get in line, create random service time
int r = rand() % 100;
int serviceTime = 0;
int culmServiceTime = servicePercent[serviceTime];
while (r > culmServiceTime) {
culmServiceTime += servicePercent[serviceTime];
serviceTime++;
}
totalServiceTime += serviceTime + 1;
//create a new customer and add it to the smallest line at a cashier
Customer newCust(myTimer, serviceTime + 1);
totalNumberOfCustomers++;
customersRemaining++;
int min = 9999999;
int smallestLine = 0;
for (int i = 0; i < numCashiers; i++) {
if (allCashiers[i].getSize() < min) {
min = allCashiers[i].getSize();
smallestLine = i;
}
}
allCashiers[smallestLine].enqueue(newCust);
}
}
}
//Displays the average customer service and wait time as well as the average cashier idle time
void display(ostream &out) {
//cout << totalNumberOfCustomers;
cout << " total number of customers :" << totalNumberOfCustomers << endl;
cout << " totalservice time: " << totalServiceTime << endl;
cout << " total customer waiting time: " << totalCustomerWaitingTime << endl;
cout << " total cashier idle time: " << totalCashierIdleTime << endl;
avgCustomerServiceTime = (double) totalServiceTime / totalNumberOfCustomers;
avgCustomerWaitingTime = (double)totalCustomerWaitingTime / totalNumberOfCustomers;
avgCashierIdleTime = (double)totalCashierIdleTime / numCashiers;
cout << " The average customer service time was: " << avgCustomerServiceTime << " minutes";
cout << " The average customer waiting time was: " << avgCustomerWaitingTime << " minutes";
cout << " The average cashier idle time was: " << avgCashierIdleTime << " minutes";
}
private:
//inputs
int lengthOfSimulation;
double arrivalRate;
int * servicePercent;
//tracking variables
int totalServiceTime;
int totalCustomerWaitingTime;
int totalCashierIdleTime;
int totalNumberOfCustomers;
int customersRemaining;
//outputs
double avgCustomerServiceTime;
double avgCustomerWaitingTime;
double avgCashierIdleTime;
//countdown timer
Timer myTimer;
//Number of cashiers, set at runtime
int numCashiers;
//array of queues that house customers
dynamic_queue<Customer> * allCashiers;
};
Customer.h
#pragma once
#include <iostream>
#include "Timer.h"
using namespace std;
class Customer {
public:
//default constructor
Customer(){
timeOfArrival = serviceTime = 0;
}
//specificconstructor
Customer(const Timer &T, int serviceTime) {
//record the customer's time of arrival
timeOfArrival = T.timeRemaining();
//set the service time
this->serviceTime = serviceTime;
}
//copy constructor
Customer(const Customer ©Cust) {
timeOfArrival = copyCust.timeOfArrival;
serviceTime = copyCust.serviceTime;
}
//returns the arrival time
int getArrivalTime() {
return timeOfArrival;
}
//returns a reference to the serviceTime
int& getServiceTime() {
return serviceTime;
}
//sets the service time
void setServiceTime(int time) {
serviceTime = time;
}
//decreases the serviceTime by 1
void decrementServicetime() {
//return serviceTime - 1;
serviceTime--;
}
//displays the object's variables
void display(ostream &out) {
out << "Arrival Time: " << timeOfArrival << endl;
out << "Service Time: " << serviceTime << endl;
}
//sets this object to the RHS one
const Customer& operator=(const Customer &RHS) {
if (this == &RHS) return *this;
this->timeOfArrival = RHS.timeOfArrival;
this->serviceTime = RHS.serviceTime;
return *this;
}
private:
//member variables
int timeOfArrival;
int serviceTime;
};
DynamicQueue.h
#pragma once
#include <iostream>
using namespace std;
template <class QueueElement>
class dynamic_queue {
public:
//default constructor
dynamic_queue(int capacity = 10) {
itail = 0;
ihead = 0;
initial_capacity = 10;
array_capacity = capacity;
array_size = 0;
myArray = new QueueElement[initial_capacity];
}
//copy constructor
dynamic_queue(const dynamic_queue ©Queue) {
array_capacity = copyQueue.array_capacity;
array_size = copyQueue.array_size;
myArray = new QueueElement[array_capacity];
for (int i = 0; i < array_capacity; i++) {
myArray[i] = copyQueue.myArray[i];
}
ihead = copyQueue.ihead;
itail = copyQueue.itail;
}
//default destructor
~dynamic_queue() {
for (int i = 0; i < array_capacity; i++) {
delete &myArray[i];
}
delete[] myArray;
}
//returns a reference to the head element of the queue
QueueElement& getHead() {
if (array_size != 0) {
return myArray[ihead % array_capacity];
}
else {
throw new exception("Queue is Empty");
}
}
//returns a reference to the tail element
QueueElement& getTail() {
if (array_size != 0) {
return myArray[itail % array_capacity];
}
else {
throw new exception("Queue is Empty");
}
}
//method to return the size of the dynamic array
int getSize() const {
return array_size;
}
//returns a boolean staing whether the dynamic array is empty or not
bool isEmpty() const {
if (array_size == 0) {
return true;
}
else {
return false;
}
}
//checks if queue is full
bool isFull() {
if (getSize() == array_capacity) return true;
else return false;
}
/*-----------------------------------------------------------------------
isFull
Precondition: none
Postcondition: returns a boolean value true if the queue is full, false otherwise
-----------------------------------------------------------------------*/
//creates a new array with double the capacity of the current array and copy each element into the new array
void increaseSize() {
QueueElement * newArray;
newArray = new QueueElement[getCapacity() * 2];
//copy each element of the old array
int temp = ihead;
for (int i = 0; i < getSize(); i++) {
newArray[i] = myArray[temp];
temp = (temp + 1) % array_capacity;
}
//program works with the delete commented out as well as only inutting arrival rate < #registers
//delete[] myArray;
//point myArray variable to the newly created array
myArray = newArray;
delete[] newArray;
array_capacity *= 2;
ihead = 0;
itail = array_size - 1;
}
/*-----------------------------------------------------------------------
increase size
Precondition: queue is full
Postcondition: doubles the capacity of the current array as a new array and copies all of its elements to a new array
-----------------------------------------------------------------------*/
//creates a new array with half the capacity of the current array and copy each element into the new array
void decreaseSize() {
initial_capacity = 10;
//cannot reduce the capacity of the array to below the intial capacity
if ((array_capacity / 2) < initial_capacity) {
return;
}
QueueElement * newArray;
newArray = new QueueElement[array_capacity / 2];
//copy each element of the old array
int temp = ihead;
for (int i = 0; i < getSize(); i++) {
cout << "size of current array: " << getSize() << endl;
cout << "i" << i << endl;
newArray[i] = myArray[temp];
temp = (temp + 1) % array_capacity;
}
//program works with the delete commented out as well as only inutting arrival rate < #registers
//delete[] myArray;
//point myArray variable to the newly created array
myArray = newArray;
delete[] newArray;
array_capacity /= 2;
ihead = 0;
itail = array_size - 1;
}
/*-----------------------------------------------------------------------
decreaseSize
Precondition: array is equal or less than 1/4 full
Postcondition: copies all of the array elements into a new array of 1/2 the capacity
-----------------------------------------------------------------------*/
//returns the capacity of the dynamic array as an int
int getCapacity() {
return array_capacity;
}
/*-----------------------------------------------------------------------
getCapacity
Precondition: none
Postcondition: returns an int of the array's capacity
-----------------------------------------------------------------------*/
//displays each 'active' element of the array (i.e. ignores elements that are actually in the array, but are not in the queue)
void display(ostream &out) const {
cout << endl << "The current contents of the list are: " << endl << endl;
if (array_size == 0) {
cout << "Queue is empty" << endl;
return;
}
for (int i = 0; i < getSize(); i++) {
cout << myArray[(i + ihead) % array_capacity] << endl;
}
}
/*-----------------------------------------------------------------------
display
Precondition: the stream to print to
Postcondition: displays all the elements of the queue
-----------------------------------------------------------------------*/
//increments the head tracker to 'remove' the oldest queue element
void dequeue() {
if (isEmpty()) {
throw new exception("Queue is empty");
}
ihead = (ihead + 1) % array_capacity;
array_size--;
//make sure the size of the array can never be less than 0
if (array_size <= 0) array_size = 0;
if (getSize() <= (.25 * array_capacity)) {
decreaseSize();
}
}
/*-----------------------------------------------------------------------
Default Constructor
Precondition: none
Postcondition: increments the head tracker, essentially 'removing' the head element
-----------------------------------------------------------------------*/
//adds a new element at the tail of the queue
void enqueue(const QueueElement &value) {
if (isFull() != true) {
if (isEmpty() == true) {
myArray[itail] = value;
}
else {
itail = (itail + 1) % array_capacity;
myArray[itail] = value;
}
array_size++;
}
else {
increaseSize();
enqueue(value);
}
}
/*-----------------------------------------------------------------------
enqueue
Precondition: the element to be added to the array
Postcondition: A element of any type is added to the tail of the array
-----------------------------------------------------------------------*/
//switches all the member variables of a to b and vice versa
bool swap(dynamic_queue &a, dynamic_queue &b) {
if (a.myArray != b.myArray) {
dynamic_queue<QueueElement> temp;
temp = a;
a = b;
b = temp;
return true;
}
else {
return false;
}
}
/*-----------------------------------------------------------------------
swap
Precondition: a dynamic_queue
Postcondition: A swaps all the variables of the passed in queue with the local queue
-----------------------------------------------------------------------*/
//Empties the queue and resizes it to the intial capacity
void clear() {
delete[] myArray;
QueueElement * newArray;
newArray = new QueueElement[initial_capacity];
myArray = newArray;
array_size = 0;
itail = 0;
ihead = 0;
}
/*-----------------------------------------------------------------------
clear
Precondition: none
Postcondition: resets all the elements of the queue and intializes it back to its intial capacity
-----------------------------------------------------------------------*/
//assigns the right queue's contents to the left queue
const dynamic_queue& operator=(const dynamic_queue &RHS) {
if (this->myArray == RHS.myArray) return *this;
array_capacity = RHS.array_capacity;
array_size = RHS.array_size;
myArray = new QueueElement[array_capacity];
for (int i = 0; i < array_capacity; i++) {
myArray[i] = RHS.myArray[i];
}
ihead = RHS.ihead;
itail = RHS.itail;
return *this;
}
/*-----------------------------------------------------------------------
operator =
Precondition: a dynamic_queue
Postcondition: the LHS queue now has all the variables and queue elements of the HRS queue
-----------------------------------------------------------------------*/
friend ostream& operator<< <> (ostream&, const dynamic_queue<dynamic_queue>&) {}
private:
/***** Data Members *****/
int ihead;
int itail;
int initial_capacity; // initial capacity of array
int array_capacity; // current capacity of the array
int array_size; // current size of queue stored in array
QueueElement *myArray; // pointer to dynamically allocated array
};
Timer.h
#pragma once
#include <cassert>
using namespace std;
class Timer {
public:
//default constructor
Timer(int initTime = 0) {
assert(initTime >= 0);
minutes = initTime;
}
//sets minutes to the passed value
void set(int minutes) {
assert(minutes >= 0);
this->minutes = minutes;
}
//'advances' one minute of time
void tick() {
minutes--;
}
//returns the number of minutes remaining in the simulation
int timeRemaining() const {
return minutes;
}
private:
int minutes;
};
main.cpp
#pragma once
#include "Timer.h"
#include "Customer.h"
#include "Simulation.h"
#include <iostream>
using namespace std;
void runSim() {
//run the simulation
Simulation sim;
sim.run();
cin.ignore();
cin.ignore();
cin.ignore();
exit(0);
}
void runQueueTest() {
//test dynamic queue class
dynamic_queue<int> queue1;
queue1.enqueue(1);
queue1.enqueue(2);
queue1.enqueue(3);
queue1.enqueue(4);
queue1.enqueue(5);
queue1.enqueue(6);
queue1.enqueue(7);
queue1.dequeue();
queue1.dequeue();
queue1.dequeue();
queue1.enqueue(8);
queue1.enqueue(9);
queue1.enqueue(10);
cout << "queue should have the elements: 4 5 6 7 8 9 10" << endl;
queue1.display(cout);
queue1.dequeue();
queue1.dequeue();
queue1.dequeue();
queue1.dequeue();
queue1.dequeue();
queue1.dequeue();
queue1.dequeue();
cout << " queue should now be empty " << endl;
queue1.display(cout);
queue1.clear();
cout << " adding some more elements" << endl;
queue1.enqueue(1);
queue1.enqueue(2);
queue1.enqueue(3);
cout << " queue should have the elements: 1 2 3" << endl;
queue1.display(cout);
cout << "head and tail: " << queue1.getHead() << " " << queue1.getTail() << endl;
cin.ignore();
cin.ignore();
cin.ignore();
exit(0);
}
int main() {
int input = 0;
cout << "Would you like to test the dynamic queue or run the grocery store simulation? (1 for queue, 2 for simulation)" << endl;
cin >> input;
if (input == 1) {
runQueueTest();
}
if (input == 2) {
runSim();
}
return 0;
}
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.