// Terminal Simulation Program
// This program will implement the siimulation of an environment where there
is
// one computer terminal and many users that arrive at random times. Constants
// are used for the mean and standard deviation with which students arrive
at the
// computer terminal and how long each student stays on the computer. Users
are
// given an id number and a connect time when they arrive at the terminal.
A
// queue is used to keep track of the users that are waiting and another
one keeps
// track of all arrivals and departures in chronological order. The apqueue
class
// is used for this implementation. Statistics are kept throughout the simulation.
#include <iostream.h>
#include <iomanip.h>
#include "apqueue.h"
#include "randgen.h"
#include <math.h>
const MAXUSERS = 1000, MAXTIME = 2500, CONNECTMEAN = 30, CONNECTSDEV
= 10;
const EVENTMEAN = 25, EVENTSDEV = 10;
enum kindtype {arrival,departure};
struct eventtype
{
kindtype kind;
int eventtime;
};
struct usertype
{
int id;
int connect;
int arrivetime;
};
struct stattype
{
int time;
int queuelen;
int maxqueue;
int maxtimeq;
int tottimeq;
int smplqueue;
int smplqlen;
int hackers;
int arrivals;
};
void init(stattype &, bool);
void runsimul(stattype &, bool, bool);
void analsimul(const stattype &);
void masterscheduler(apqueue<eventtype> &,apqueue<usertype>
&, stattype &,
bool &, bool, bool);
int connecttime(int, int);
void printusers(apqueue<usertype>);
void printevents(apqueue<eventtype>);
void depart(apqueue<eventtype> &, apqueue<usertype> &,
stattype &,
bool &, bool, bool);
void insertevent(apqueue<eventtype> &, eventtype, bool);
void arrive(apqueue<eventtype> &, apqueue<usertype> &,
stattype &, bool &, bool, bool);
void queueperson(apqueue<eventtype> &, apqueue<usertype>
&, usertype, stattype &,
bool &, bool, bool);
int main()
//description: This simulates an environment where there is one computer
terminal and many
// users who arrive at random times. Statistics are kept as a way of
// analyzing the situation. The user is given a debug and trace option.
{
stattype stats;
bool debugging, tracing;
char choice;
cout << "Welcome to the terminal simulation program!!!"
<< endl
<< endl;
cout << "Do you want to see debugging information? ";
cin >> choice;
if (choice == 'Y' || choice == 'y')
debugging = true;
else
debugging = false;
cout << "Do you want to trace the simulation? ";
cin >> choice;
if (choice == 'Y' || choice == 'y')
tracing = true;
else
tracing = false;
do
{
init(stats,debugging);
runsimul(stats,debugging,tracing);
analsimul(stats);
cout << "Do you want to run it again? ";
cin >> choice;
}
while (choice == 'y');
return 0;
}
int connecttime(int mean, int sdev)
//description: This uses the mean and st. dev. to calculate a random integer
// with that distribution.
//precondition: mean and standard deviation are positive values
//postcondition: a random integer is returned
{
RandGen rnum; // a parameter will provide the same sequence each time
float sum = 0;
for (int i=1;i<mean*2;i++)
{
sum += rnum.RandReal();
}
sum = (sum - mean) / sqrt(5);
sum = sum * sdev + mean;
return int(sum);
}
void printusers(apqueue<usertype> users)
//description: This prints out the users who are waiting to use the computer
// by using a value parameter so that the original one is not
// destroyed by dequeueing each user
//precondition: the users queue is defined
//postcondition: the users queue remains the same
{
usertype user;
while (!users.isEmpty())
{
users.dequeue(user);
cout << "User #" << user.id << " arrived
at " << user.arrivetime
<< " and was given a connect time of " << user.connect
<< endl;
}
}
void printevents(apqueue<eventtype> events)
//description: This prints out the events that have not been processed
yet
// by using a value parameter so that the original one is not
// destroyed by dequeueing each user
//precondition: the events queue is defined
//postcondition: the events queue remains the same
{
eventtype event;
while (!events.isEmpty())
{
events.dequeue(event);
cout << "A(n) ";
switch (event.kind)
{
case arrival : cout << "arrival"; break;
case departure : cout << "departure"; break;
}
cout << " occurred at time " << event.eventtime
<< endl;
}
}
void init(stattype &stats, bool debugging)
//description: initializes all statistics to 0 at the start of each simulation
//postcondition: the events queue remains the same
{
char ch;
stats.queuelen = 0; stats.maxqueue = 0; stats.maxtimeq = 0;
stats.tottimeq = 0; stats.hackers = 0; stats.arrivals = 0;
stats.smplqueue = 0; stats.smplqlen = 0; stats.time = 0;
if (debugging)
{
cout << endl << "Every time you see an *, hit non-whitespace
to continue."
<< endl << endl << "Initialization taking place
*";
cin >> ch;
}
}
void runsimul(stattype &stats, bool debugging, bool tracing)
//description: This actually runs the simulation and controls it by either
an
// inputted number of users or an inputted amount of time. The
// value of inuse is kept throughout the simulation. Two
// initially empty queues keep track of the users and the events.
//precondition: all statistics have been initialized
//postcondition: all statistics have been found and the number of users
// exceeds the maximum number of users or the time exceeds the
// maximum simulation time
{
apqueue<eventtype> events;
apqueue<usertype> users;
char choice;
bool inuse = false;
bool invalid = false;
int stoptime, stopusers;
do
{
cout << "Should the simulation be limited by the number of
"
<< endl << "users (U) or the maximum time (T)? ";
cin >> choice;
if (choice == 'T' || choice == 't')
{
do
{
cout << "Maximum time is " << MAXTIME << "
minutes. Time => ";
cin >> stoptime;
}
while (stoptime > MAXTIME);
while (stats.time < stoptime)
masterscheduler(events,users,stats,inuse,debugging,tracing);
}
else if (choice == 'U' || choice == 'u')
{
do
{
cout << "Maximum users are " << MAXUSERS <<
" Users => ";
cin >> stopusers;
}
while (stopusers > MAXUSERS);
while (stats.arrivals < stopusers)
masterscheduler(events,users,stats,inuse,debugging,tracing);
}
else
invalid = true;
}
while (invalid);
}
void masterscheduler(apqueue<eventtype> &events, apqueue<usertype>
&users,
stattype &stats, bool &inuse, bool debug, bool trace)
//description: This implements a time slice of the simulation by determining
if
// there are users waiting, If not, it creates a new arrival to the
// terminal. if there are, then the next arrival or departure from the
// event queue is processed.
//precondition: all statistics have been initialized and the events and
users queues
// have been created
//postcondition: the events queue has been updated with an arrival if
it is empty or
// either an arrival or a departure from the event queue is processed
{
eventtype currevent;
stats.smplqueue++;
stats.smplqlen += stats.queuelen;
if (debug)
cout << "Entering Master Scheduler. Time is " <<
stats.time
<< endl;
if (events.isEmpty())
arrive(events,users,stats,inuse,debug,trace);
else
{
events.dequeue(currevent);
if (debug)
{
cout << "The current event is ";
switch (currevent.kind)
{
case arrival : cout << "arrival"; break;
case departure : cout << "departure"; break;
}
cout << " at time " << currevent.eventtime <<
endl;
}
stats.time = currevent.eventtime;
if (currevent.kind == arrival)
arrive(events,users,stats,inuse,debug,trace);
else
depart(events,users,stats,inuse,debug,trace);
}
if (debug)
cout << "Exiting Master Scheduler. Time is " <<
stats.time
<< endl;
}
void depart(apqueue<eventtype> &events, apqueue<usertype>
&users,
stattype &stats, bool &inuse, bool debug, bool trace)
//description: This effectively removes a student from working on the
computer
// at the allocated time and places the next person waiting on the
// vacant computer. Statistics are kept involving the length of time
// waiting and how many were on the users queue.
//precondition: a student is currently on the computer
//postcondition: that student is now off and either a student who was
first in line
// is now on the computer or the terminal is emptyb because no one
// is waiting
{
char ch;
int queuetime;
eventtype anevent;
usertype curruser;
inuse = false;
if (debug)
{
cout << "Processing a departure *";
cin >> ch;
}
if (!users.isEmpty())
{
inuse = true;
users.dequeue(curruser);
queuetime = stats.time - curruser.arrivetime;
stats.hackers++;
if (stats.maxtimeq < queuetime)
stats.maxtimeq = queuetime;
stats.tottimeq += queuetime;
if (trace)
cout << "-- User #" << curruser.id << "
got on the terminal at "
<< "time " << stats.time << " for "
<< curruser.connect
<< " minutes." << endl;
stats.queuelen--;
anevent.kind = departure;
anevent.eventtime = stats.time + curruser.connect;
insertevent(events,anevent,debug);
}
else
if (trace)
cout << endl
<< "-- Terminal is free and no users are waiting.'"
<< endl;
}
void insertevent(apqueue<eventtype> &events, eventtype currevent,
bool debug)
//description: This inserts a new event into the current event queue in
the
// proper place based on the time of the event being chronological.
//precondition: a current event is defined with its type and time
//postcondition: the events queue has been updated with an arrival or
departure
// and all events are in chronological order from lowest to highest
{
// char ch;
apqueue<eventtype> newevents(events);
eventtype anevent;
events.makeEmpty();
if (newevents.isEmpty())
events.enqueue(currevent);
else
{
bool found = false;
while (!newevents.isEmpty())
{
newevents.dequeue(anevent);
if (!found && anevent.eventtime > currevent.eventtime)
{
found = true;
events.enqueue(currevent);
}
events.enqueue(anevent);
}
if (!found) events.enqueue(currevent);
}
if (debug)
{
cout << "Inserting an event. The calendar currently is:"
<< endl;
apqueue<eventtype> eventqueue(events);
printevents(eventqueue);
cout << "==============================================="
<< endl;
}
}
void arrive(apqueue<eventtype> &events, apqueue<usertype>
&users, stattype &stats,
bool &inuse, bool debug, bool trace)
//description: This processes a student's arrival to the computer area.
The user is
// assigned an id#, a random connect time and his/her arrival time is
kept
// so that she can be placed on the users queue. The arrival event is
also
// placed sequentially on the event queue with a different random time
// between arrivals.
//precondition: a student has arrived at the computer terminal room
//postcondition: a new user has been placed on the users queue or directly
onto the terminal
// and an arrival event is placed on the event queue in the correct
// chronological order so that students can't start working until the
// computer is vacated by the previous user
{
char ch;
int aneventtime;
eventtype anevent;
if (debug)
{
cout << "Processing an arrival *";
cin >> ch;
}
stats.arrivals++;
usertype curruser;
curruser.id = stats.arrivals;
curruser.connect = connecttime(CONNECTMEAN,CONNECTSDEV);
curruser.arrivetime = stats.time;
if (debug)
if (!users.isEmpty())
{
cout << "Queue for the terminal:" << endl;
apqueue<usertype> userqueue(users);
printusers(userqueue);
cout << "================================================="
<< endl;
}
else
cout << "The terminal queue is empty." << endl;
queueperson(events,users,curruser,stats,inuse,debug,trace);
if (trace)
cout << "-- User #" << curruser.id << "
was placed on a "
<< stats.queuelen << "-person queue at time " <<
stats.time
<< endl;
if (debug)
if (!events.isEmpty())
{
cout << "Queue for the terminal:" << endl;
apqueue<eventtype> eventqueue(events);
printevents(eventqueue);
cout << "================================================="
<< endl;
}
else
cout << "The terminal queue is empty." << endl;
anevent.kind = arrival;
aneventtime = connecttime(EVENTMEAN,EVENTSDEV);
anevent.eventtime = stats.time + aneventtime;
insertevent(events,anevent,debug);
}
void queueperson(apqueue<eventtype> &events, apqueue<usertype>
&users,
usertype curruser, stattype &stats, bool &inuse, bool debug,
bool trace)
//description: This places a new user on the queue of users waiting to
use the
// computer terminal if it is in use and otherwise puts the user on the
// terminal for the assigned time and immediately creates a departure
event.
//precondition: the variable inuse is defined and a student has just arrived
at the
// terminal
//postcondition: either a student gets onto the computer right away or
is placed in line to
// wait until it becomes available
{
char ch;
users.enqueue(curruser);
stats.queuelen++;
if (stats.queuelen > stats.maxqueue)
stats.maxqueue = stats.queuelen;
if (!inuse)
{
if (debug)
{
cout << "Queueperson. Someone gets on the terminal *";
cin >> ch;
}
depart(events,users,stats,inuse,debug,trace);
}
else
if (debug)
{
cout << "Queueperson. Queued someone so queuelen = "
<< stats.queuelen << " *" << endl;
cin >> ch;
}
}
void analsimul(const stattype &stats)
//description: This prints out the final statistical infomration for the
simulation.
//precondition: all statistics have been compiled
//postcondition: the final output for the program has been printed
{
float avgqueuelen = float(stats.smplqlen) / stats.smplqueue;
float avgqueuetime = float(stats.tottimeq) / stats.hackers;
cout << endl << endl << endl << "The simulation
is over now." << endl;
cout << "Total Users: " << setw(10) << stats.arrivals
<< endl;
cout << "Simulation time: " << setw(10) <<
stats.time << endl;
cout << "Maximum queue length: " << setw(10) <<
stats.maxqueue << endl;
cout << "Average queue length: " << setw(10) <<
setprecision(2)
<< avgqueuelen << endl;
cout << "Maximum queue time: " << setw(10) <<
stats.maxtimeq << endl;
cout << "Average queue time: " << setw(10) <<
setprecision(2)
<< showpoint << avgqueuetime << endl << endl;
}
|