Week 15: Final Project - Supermarket Queue Simulator
This commit is contained in:
parent
114813c691
commit
01cb312028
6
week-15/CMakeLists.txt
Normal file
6
week-15/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(week-15)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
add_executable(week-15 main.cpp)
|
360
week-15/main.cpp
Normal file
360
week-15/main.cpp
Normal file
@ -0,0 +1,360 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Champlain College SDEV-345-81
|
||||
*
|
||||
* C++ Week 15 Final Project - (2020/12/13)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Code must be object oriented
|
||||
* Code must be thoroughly commented
|
||||
* The project shall use the queue data structure learned in the course.
|
||||
* Do not use the queue library.
|
||||
*
|
||||
* A supermarket has 9 cashiers. Customers arrive and leave at random time intervals.
|
||||
* Use 0-5 seconds for this project. Make sure the customers arrive faster than they depart
|
||||
* so that the queues fill up. The goal of the program is to put the next arriving customer
|
||||
* in the shortest queue out of the 9 cashier queues. Your program will need to loop infinitely
|
||||
* to simulate the passing of a certain amount of time. I suggest looping the program every second
|
||||
* and clearing the screen and displaying all queues. Use a simple "for loop" as a delay.
|
||||
* Also use asterisks (*) to represent customers.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Written by Llewellyn van der Merwe <llewellyn.vandermerw@mymail.champlain.edu>, October 2020
|
||||
* Copyright (C) 2020. All Rights Reserved
|
||||
* License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// Adaptation to the code found at
|
||||
// Week 6: Lecture 4 - Queue
|
||||
// Demonstrates queue implemented as linked list
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//////// The Link Class /////////////////////////////////////////
|
||||
class Link {
|
||||
public:
|
||||
string dData; // data item
|
||||
Link *pNext; // ptr to next link in list
|
||||
//-------------------------------------------------------------
|
||||
Link(string d) : dData(d), pNext(nullptr) // constructor
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
void displayLink() // display this link
|
||||
{ cout << dData; }
|
||||
//-------------------------------------------------------------
|
||||
};
|
||||
|
||||
//////// The Last in First Out Class - Queue ////////////////////
|
||||
class LastInFirstOut {
|
||||
private:
|
||||
Link *pFirst; // ptr to first link
|
||||
Link *pLast; // ptr to last link
|
||||
int Size = 0; // total in queue
|
||||
public:
|
||||
//-------------------------------------------------------------
|
||||
LastInFirstOut() : pFirst(nullptr), pLast(nullptr) //constructor
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
~LastInFirstOut() // destructor
|
||||
{ // (deletes all links)
|
||||
Link *pCurrent = pFirst; // start at beginning
|
||||
while (pCurrent != nullptr) // until end of list,
|
||||
{
|
||||
Link *pTemp = pCurrent; // remember current
|
||||
pCurrent = pCurrent->pNext; // move to next link
|
||||
delete pTemp; // delete old current
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
bool isEmpty() // true if no links
|
||||
{ return pFirst == nullptr; }
|
||||
|
||||
//-------------------------------------------------------------
|
||||
int size() // the size of the queue
|
||||
{ return Size; }
|
||||
|
||||
//-------------------------------------------------------------
|
||||
void insertLast(string dd) // insert at end of list
|
||||
{
|
||||
Link *pNewLink = new Link(dd); // make new link
|
||||
if (isEmpty()) // if empty list,
|
||||
pFirst = pNewLink; // first --> newLink
|
||||
else
|
||||
pLast->pNext = pNewLink; // old last --> newLink
|
||||
pLast = pNewLink; // newLink <-- last
|
||||
|
||||
Size++; // count insert
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
void removeFirst() // delete first link
|
||||
{
|
||||
if (!isEmpty()) {
|
||||
Size--; // count insert removed
|
||||
Link *pTemp = pFirst; // remember first link
|
||||
if (pFirst->pNext == nullptr) // if only one item
|
||||
pLast = nullptr; // null <-- last
|
||||
pFirst = pFirst->pNext; // first --> old next
|
||||
delete pTemp; // delete the link
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
void displayList() {
|
||||
Link *pCurrent = pFirst; // start at beginning
|
||||
while (pCurrent != nullptr) // until end of list,
|
||||
{
|
||||
pCurrent->displayLink(); // print data
|
||||
pCurrent = pCurrent->pNext; // move to next link
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
};
|
||||
|
||||
//////// The Cashier Class //////////////////////////////////////
|
||||
class Cashier {
|
||||
private:
|
||||
LastInFirstOut activeQueue; // the active queue
|
||||
int counter = 0; // the leaving queue counter
|
||||
|
||||
//-------------------------------------------------------------
|
||||
int _rndm(int min, int max) // set some random number
|
||||
{
|
||||
random_device rd;
|
||||
mt19937 get_card(rd());
|
||||
uniform_int_distribution<> my_random(min, max);
|
||||
return my_random(get_card);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void payed() // payed client leaves front of queue
|
||||
{
|
||||
// remove from queue
|
||||
activeQueue.removeFirst();
|
||||
// add to leaving queue
|
||||
counter++;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
bool hasClient() // true if has client
|
||||
{ return !activeQueue.isEmpty(); }
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------
|
||||
int queued() // number of clients in queue
|
||||
{ return activeQueue.size(); }
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void arrive() // new client arrive at rear of queue
|
||||
{ activeQueue.insertLast("*"); }
|
||||
|
||||
void arrive(int number) // new clients arrive at rear of queue
|
||||
{
|
||||
for (int n = 0; n < number; n++)
|
||||
arrive();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void process() // process client
|
||||
{
|
||||
int done = _rndm(0, 1);
|
||||
// if 1 remove one if not empty
|
||||
if (done == 1 && hasClient()) {
|
||||
// client paid and is leaving
|
||||
payed();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void camera(int spacer) {
|
||||
// remove the number in queue
|
||||
spacer = spacer - queued();
|
||||
// now add the spacing
|
||||
if (spacer > 0)
|
||||
cout << string(spacer, ' ');
|
||||
// display clients waiting
|
||||
activeQueue.displayList();
|
||||
// show clients leaving
|
||||
if (counter == 0) {
|
||||
cout << "[Cashier]" << endl;
|
||||
} else {
|
||||
cout << "[Cashier] (" << counter << ")->clients-served" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
};
|
||||
|
||||
//////// The Shop Class //////////////////////////////////////
|
||||
class Shop {
|
||||
private:
|
||||
bool open; // while the shop is open (true)
|
||||
bool limit = true; // turn on limit (false makes shop infinite)
|
||||
int dailyLimit = 3000; // the shops daily limit
|
||||
int speed = 100; // the shops processing speed
|
||||
int longestQueue = 1; // the longest queue
|
||||
int clientsIn = 0; // number of clients in shop
|
||||
int clientsTotal = 0; // number of total clients
|
||||
const static int tillN = 10; // the number of cashiers in shop
|
||||
Cashier Cashiers[tillN]; // all cashiers
|
||||
|
||||
//--------------------------------------------------------------
|
||||
int getNextQueue() // get the next queue
|
||||
{
|
||||
int smallest = dailyLimit * 100; // highest number allowed in the shop
|
||||
int counter = 0; // counter to check empty cashiers
|
||||
int key = _rndm(0, 9); // array key to return
|
||||
int size; // just a queued size
|
||||
clientsIn = 0; // reset the clients inside store
|
||||
// we go over all cashiers
|
||||
for (int t = 0; t < tillN; t++) {
|
||||
// get the queued size
|
||||
size = Cashiers[t].queued();
|
||||
// count how many is still in shop
|
||||
clientsIn += size;
|
||||
// check the smallest
|
||||
if (size <= smallest) {
|
||||
smallest = size;
|
||||
key = t;
|
||||
// at each zero we count
|
||||
if (size == 0) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
// also set longest
|
||||
if (size > longestQueue) {
|
||||
longestQueue = size;
|
||||
}
|
||||
}
|
||||
// we check if all cashiers are empty
|
||||
if (counter == tillN) {
|
||||
return _rndm(0, counter);
|
||||
}
|
||||
// return smallest
|
||||
return key;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
int _rndm(int min, int max) // set some random number
|
||||
{
|
||||
random_device rd;
|
||||
mt19937 get_card(rd());
|
||||
uniform_int_distribution<> my_random(min, max);
|
||||
return my_random(get_card);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void arrivals() // arriving client
|
||||
{
|
||||
int arrived = _rndm(0, 7);
|
||||
int key, arrivals;
|
||||
// if more then one we have new arrival
|
||||
if (arrived > 3) {
|
||||
// when clients arrive we must queue them
|
||||
for (int c = 0; c < arrived; c++) {
|
||||
// get smallest queue
|
||||
key = getNextQueue();
|
||||
// get the number of arrivals
|
||||
arrivals = _rndm(1, 2);
|
||||
// add to total
|
||||
clientsTotal += arrivals;
|
||||
// add the new arrivals also
|
||||
clientsIn += arrivals;
|
||||
// add the arrival
|
||||
Cashiers[key].arrive(arrivals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void clearScreen() { // method to clear the screen
|
||||
// not ideal... but okay
|
||||
cout << string(100, '\n');
|
||||
// I could also use this method
|
||||
// https://github.com/Llewellynvdm/game-of-life/blob/master/src/Util.cpp#L282
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void displayCameras() // display all queues
|
||||
{
|
||||
// show the total number of clients currently in shop
|
||||
cout << "==========================================================" << endl;
|
||||
cout << "== Clients In Store: " << clientsIn << endl;
|
||||
cout << "==========================================================" << endl;
|
||||
// we go over all cashier cameras
|
||||
for (int view = 0; view < tillN; view++) {
|
||||
// check who is in the queue
|
||||
Cashiers[view].camera(longestQueue);
|
||||
// check if we have to process clients
|
||||
Cashiers[view].process();
|
||||
}
|
||||
cout << "==========================================================" << endl;
|
||||
cout << "== Total Clients: " << clientsTotal << endl;
|
||||
cout << "==========================================================" << endl;
|
||||
// give final notice
|
||||
if (!open && clientsIn == 0) {
|
||||
cout << "== Supermarket Closed :) " << endl;
|
||||
cout << "==========================================================" << endl;
|
||||
cout << string(2, '\n');
|
||||
} else {
|
||||
cout << string(4, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------
|
||||
void watchCashiers() {
|
||||
// shop is open
|
||||
open = true;
|
||||
// this will run infinite
|
||||
while (open || clientsIn > 0) {
|
||||
// check if we are over daily limit
|
||||
// then we just help those still in shop
|
||||
if (clientsTotal >= dailyLimit && limit) {
|
||||
// close the shop now
|
||||
open = false;
|
||||
}
|
||||
// always clear the last view
|
||||
clearScreen();
|
||||
// start the shop view
|
||||
cout << "==========================================================" << endl;
|
||||
// are we using the limited version
|
||||
if (limit) {
|
||||
// we run until we have served daily limit of clients
|
||||
cout << "== Supermarket Client Limit - " << dailyLimit << " Per/Day " << endl;
|
||||
} else {
|
||||
// we run until we have served daily limit of clients
|
||||
cout << "== Infinite Supermarket" << endl;
|
||||
}
|
||||
// only allow arrivals if shop is open
|
||||
if (open) {
|
||||
// check if we new arrivals
|
||||
arrivals();
|
||||
} else {
|
||||
// update counters
|
||||
getNextQueue();
|
||||
}
|
||||
// display clients waiting
|
||||
displayCameras();
|
||||
// slow down a little
|
||||
this_thread::sleep_for(chrono::milliseconds(speed));
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
};
|
||||
|
||||
//////// Main //////////////////////////////////////////////////
|
||||
int main() {
|
||||
Shop supermarket; // the new shop
|
||||
supermarket.watchCashiers(); // the view of the cashiers
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user