// Chap 7, pp 334 - 339
// See also files C07P339.CPP and C07P341.CPP

// *******************************************************
// Event-driven simulation of a single waiting line of
// people.
//
// Input:
//    A text file of arrival and transaction times.
//    Each line contains the arrival time and required
//    transaction time for a customer.
//
// Assumption:
//    The arrival times in the input file are ordered by
//    increasing time.
//
// Output:
//    A trace of the events executed and a summary of
//    statistics (total number of arrivals and average time
//    spent waiting in line).
//
// ADTs:
//    Line of people - a queue of arrival events
//    Event list     - a list of arrival events and 
//                     departure events that are sorted 
//                     by the time of the event.

// Functions:
//    GetArrival       - reads arrival event from input file 
//                       and inserts it into event list
//    ProcessArrival   - executes an arrival event
//    ProcessDeparture - executes a departure event
//    Simulate         - performs the simulation
// *******************************************************
char* const ARRIVAL_FILE_NAME = "BANK.DAT";
const int FIELD_WIDTH = 3;  // output field width for time
const int MAX_STRING = 12;
typedef char nameType[MAX_STRING];

#include   // file operations
#include   // enables setw()
#include    // enables exit()
#include "EL.h"       // ADT event list operations

// for simplicity, queue items and event list items
// are the same structures; both indicate the kind of
// event and contain arrival and transaction times
#ifndef QTYPE
typedef event queueItemType;  // desired-type-of-queue-item
#define QTYPE
#endif
// omit declaration of queueItemType from Queue.h
//#include "Queue.h"  // ADT queue operations

// statistics of simulation
struct stats
{  int TotalNum;   // total no. of customers
   int TotalWait;  // cumulative waiting time

   stats();        // constructor
};  // end struct

stats::stats() : TotalNum(0), TotalWait(0)
{
}  // end constructor

void GetArrival(ifstream& ArrivalFile, eventListClass& EL,
                boolean& Success)
// --------------------------------------------------------
// Reads data for the next arrival event, and inserts the
// new arrival node into the event list.
// Precondition: ArrivalFile is a text file, which is open
// for input, of arrival and transaction times. EL is the
// current event list.
// Postcondition: The next event is read from ArrivalFile
// and is inserted into EL and Success is TRUE. At end-of-
// file, EL is unchanged. If insertion is impossible,
// Success is FALSE. ArrivalFile is open for input.
// Calls: InsertEvent.
// --------------------------------------------------------
{
   int NextTime;  // time of next arrival event
   int TTime;     // event's transaction time
                  // (i.e. transaction length)

   if (ArrivalFile >> NextTime >> TTime)  // read next event
   {  // create a new arrival event
      event NewEvent(A, NextTime, TTime);

      // insert the event into the event list
      EL.InsertEvent(NewEvent, Success);
   }  // end if
}  // end GetArrival

void ProcessArrival(event ArrivalEvent, 
                    ifstream& ArrivalFile,
                    eventListClass& EL, queueClass& Line,
                    stats& Statistics, boolean& Success)
// --------------------------------------------------------
// Executes an arrival event.
// Precondition: ArrivalEvent contains the arrival event,
// ArrivalFile of arrival events is open for input,
// EL is the event list, the queue Line has been created,
// and Statistics.TotalNum is the total number of arrivals.
// Postcondition: If Line is empty, a departure event is
// created for ArrivalEvent and inserted into event list EL.
// ArrivalEvent is deleted from event list and added to
// Line (the queue). A new arrival event is read from
// ArrivalFile and is inserted into EL. Statistics.TotalNum
// (total no. of arrivals) is updated. ArrivalFile is open
// for input. Success is TRUE unless an insertion into the
// event list is impossible.
// Calls: InsertEvent, DeleteEvent, GetArrival,
// QueueIsEmpty, and QueueAdd.
// --------------------------------------------------------
{
   // update the total number of arrivals
   ++Statistics.TotalNum;

   int CurrentTime = ArrivalEvent.Time;  // arrival time
   cout << "Processing an arrival event at time:  "
        << setw(FIELD_WIDTH) << CurrentTime << endl;

   // if queue is empty, arrival will be at head of line
   boolean AtHead = Line.QueueIsEmpty();

   // person arrives and enters the waiting line (queue)
   Line.QueueAdd(ArrivalEvent, Success);

   // update event list
   EL.DeleteEvent(Success);  // delete event from event list

   // if at head of line, the person starts transaction
   if (AtHead)
   {  // create a departure event
      event DepartureEvent(D, CurrentTime +
                                 ArrivalEvent.TransTime, 0);

      // insert the event into the event list
      EL.InsertEvent(DepartureEvent, Success);
   }  // end if

   if (Success)
      // get the next arrival event, if any, from input file
      GetArrival(ArrivalFile, EL, Success);
}  // end ProcessArrival

void ProcessDeparture(event DepartureEvent,
                      eventListClass& EL, queueClass& Line,
                      stats& Statistics, boolean& Success)
// --------------------------------------------------------
// Executes a departure event.
// Precondition: DepartureEvent contains the departure 
// event, EL is the event list, the queue Line has been 
// created, Statistics.TotalWait is the total waiting time.
// Postcondition: A person is removed from the queue. The
// event list is updated by deleting the current event and
// adding a departure event for the next customer, if any.
// Statistics.TotalWait (total waiting time) is updated.
// Success is TRUE unless an insertion into the event list
// was impossible.
// Calls: InsertEvent, DeleteEvent, QueueIsEmpty, 
// QueueRemove, and GetQueueFront.
// --------------------------------------------------------
{
   queueItemType PersonInLine; // data for person in queue

   int CurrentTime = DepartureEvent.Time;  // arrival time
   cout << "Processing a departure event at time: "
        << setw(FIELD_WIDTH) << CurrentTime << endl;

   // person departs - update the line (queue)
   Line.QueueRemove(Success); // remove person from queue

   // update the event list:
   EL.DeleteEvent(Success);  // delete event from event list

   // if the line is not empty, the next person starts
   // a transaction
   if (!Line.QueueIsEmpty())
   {  // create a departure event
      Line.GetQueueFront(PersonInLine, Success);
      event DepartureEvent(D, CurrentTime +
                                  PersonInLine.TransTime,0);

      // insert the event into the event list
      EL.InsertEvent(DepartureEvent, Success);

      if (Success)
         // update the statistics
         Statistics.TotalWait += (CurrentTime - 
                       PersonInLine.Time);
   }  // end if
}  // end ProcessDeparture

void Simulate(nameType FileName, stats& Statistics)
// --------------------------------------------------------
// Simulates a line of people.
// Precondition: FileName is the name of the text file
// of arrival events. Data members of Statistics are 0.
// Postcondition: Statistics.TotalWait is the total
// cumulative waiting time of all customers.
// Statistics.TotalNum is the total number of customers.
// ArrivalFile is closed.
// Calls: GetArrival, ProcessArrival, ProcessDeparture,
// EventListIsEmpty, and RetrieveEvent.
// --------------------------------------------------------
{
   event          NewEvent;              // current event
   eventListClass EL;                    // event list
   queueClass     Line;                  // waiting line
   ifstream       ArrivalFile(FileName); // file of times
   boolean        Success;

   cout << "Simulation begins:\n";

   // get the first arrival event and place on event list
   GetArrival(ArrivalFile, EL, Success);

   // process events until the event list is empty
   while ( Success && !EL.EventListIsEmpty() )
   {  // get next event from beginning of event list
      EL.RetrieveEvent(NewEvent, Success);

      if (NewEvent.WhichEvent == A)
         // process arrival event
         ProcessArrival(NewEvent, ArrivalFile, EL, Line, 
                        Statistics, Success);
      else
         // process departure event
         ProcessDeparture(NewEvent, EL, Line, 
                          Statistics, Success);
   }  // end while

   if (!Success)
   {  cerr << "Error in event list. "
           << "Execution aborted.\n";
      exit(1);  // abort
   }  // end if
   cout << "Simulation ends.\n";
}  // end Simulate

main()
{
   stats Statistics;  // summary statistics initialized to 0

   // perform the simulation
   Simulate(ARRIVAL_FILE_NAME, Statistics);

   // write out the final statistics
   cout << "\nFinal Statistics:\n"
        << "  Total number of people processed: "
        << Statistics.TotalNum << "\n"
        << "  Average amount of time spent waiting: ";
   if (Statistics.TotalNum == 0)
      cout << " 0.0\n";
   else
      cout << float(Statistics.TotalWait)/
                         float(Statistics.TotalNum) << endl;

   return 0;
}  // end program

    Source: geocities.com/siliconvalley/program/2864/ds/CHAP7

               ( geocities.com/siliconvalley/program/2864/ds)                   ( geocities.com/siliconvalley/program/2864)                   ( geocities.com/siliconvalley/program)                   ( geocities.com/siliconvalley)