| /************************************************************************** |
| * |
| * icecream.cpp - Priority queue example program. |
| * |
| * $Id$ |
| * |
| *************************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed |
| * with this work for additional information regarding copyright |
| * ownership. The ASF licenses this file to you under the Apache |
| * License, Version 2.0 (the "License"); you may not use this file |
| * except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| * implied. See the License for the specific language governing |
| * permissions and limitations under the License. |
| * |
| * Copyright 1994-2006 Rogue Wave Software. |
| * |
| **************************************************************************/ |
| |
| #include <algorithm> // for random_shuffle() |
| #include <iostream> // for cout |
| #include <queue> // for queue |
| #include <vector> // for vector |
| |
| #include <examples.h> |
| |
| |
| // Execution event in a descrete event driven simulation. |
| class event { |
| public: |
| // Construct sets time of event. |
| event (unsigned int t) : time (t) |
| { } |
| |
| // Execute event by invoking this method. |
| virtual void processEvent () = 0; |
| |
| const unsigned int time; |
| }; |
| |
| struct eventComparator { |
| bool operator() (const event * left, const event * right) const { |
| return left->time > right->time; |
| } |
| }; |
| |
| |
| // Framework for discrete event-driven simulations. |
| class simulation { |
| public: |
| simulation () : time (0), eventQueue () |
| {} |
| void run (); |
| void scheduleEvent (event * newEvent) { |
| eventQueue.push (newEvent); |
| } |
| unsigned int time; |
| protected: |
| std::priority_queue<event*, |
| std::vector<event *, std::allocator<event*> >, |
| eventComparator> eventQueue; |
| }; |
| |
| |
| void simulation::run () { |
| |
| while (! eventQueue.empty ()) { |
| |
| event * nextEvent = eventQueue.top (); |
| eventQueue.pop (); |
| time = nextEvent->time; |
| nextEvent->processEvent (); |
| delete nextEvent; |
| } |
| } |
| |
| |
| // Ice cream store simulation. |
| class storeSimulation : public simulation { |
| public: |
| storeSimulation () : simulation (), freeChairs (35), profit (0.0) |
| { } |
| bool canSeat (unsigned int numberOfPeople); |
| void order (unsigned int numberOfScoops); |
| void leave (unsigned int numberOfPeople); |
| // Data fields. |
| unsigned int freeChairs; |
| double profit; |
| } theSimulation; |
| |
| |
| class arriveEvent : public event { |
| public: |
| arriveEvent (unsigned int t, unsigned int groupSize) |
| : event (t), size (groupSize) |
| { } |
| virtual void processEvent (); |
| private: |
| unsigned int size; |
| }; |
| |
| |
| class orderEvent : public event { |
| public: |
| orderEvent (unsigned int t, unsigned int groupSize) |
| : event (t), size (groupSize) |
| { } |
| virtual void processEvent (); |
| private: |
| unsigned int size; |
| }; |
| |
| |
| class leaveEvent : public event |
| { |
| public: |
| leaveEvent (unsigned int t, unsigned int groupSize) |
| : event (t), size (groupSize) |
| { } |
| virtual void processEvent (); |
| private: |
| unsigned int size; |
| }; |
| |
| |
| // returns a random integer between 0 and n with n <= 32767 <= INT_MAX |
| int irand (int n) |
| { |
| static int seq[] = { |
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf |
| }; |
| |
| std::random_shuffle (seq, seq + sizeof seq / sizeof *seq); |
| |
| const int rnd = (seq [0] << 11) | (seq [1] << 8) | (seq [2] << 4) + seq [3]; |
| |
| return rnd % n; |
| } |
| |
| |
| void arriveEvent::processEvent () { |
| |
| if (theSimulation.canSeat (size)) |
| theSimulation.scheduleEvent |
| (new orderEvent (time + 1 + irand (4), size)); |
| } |
| |
| |
| void orderEvent::processEvent () { |
| |
| // Each person orders some number of scoops. |
| for (unsigned int i = 0; i < size; i++) |
| theSimulation.order (1 + irand (4)); |
| |
| // Then we schedule the leave event. |
| theSimulation.scheduleEvent |
| (new leaveEvent (time + 1 + irand (10), size)); |
| } |
| |
| |
| void leaveEvent::processEvent () { |
| |
| theSimulation.leave (size); |
| } |
| |
| |
| // If sufficient room then seat customers. |
| bool storeSimulation::canSeat (unsigned int numberOfPeople) { |
| |
| std::cout << "Time: " << time; |
| std::cout << " group of " << numberOfPeople << " customers arrives"; |
| |
| if (numberOfPeople < freeChairs) { |
| std::cout << " is seated\n"; |
| freeChairs -= numberOfPeople; |
| return true; |
| } |
| else { |
| std::cout << " no room, they leave\n"; |
| return false; |
| } |
| } |
| |
| |
| // Service icecream, compute profits. |
| void storeSimulation::order (unsigned int numberOfScoops) { |
| |
| std::cout << "Time: " << time << " serviced order for " |
| << numberOfScoops << '\n'; |
| profit += 0.35 * numberOfScoops; |
| } |
| |
| |
| // People leave, free up chairs. |
| void storeSimulation::leave (unsigned int numberOfPeople) { |
| |
| std::cout << "Time: " << time << " group of size " |
| << numberOfPeople << " leaves\n"; |
| freeChairs += numberOfPeople; |
| } |
| |
| |
| int main () { |
| |
| std::cout << "Ice Cream Store simulation from Chapter 9\n"; |
| |
| // Load queue with some number of initial events. |
| for (unsigned t = 0; t < 20; t += irand (6)) { |
| |
| std::cout << "pumping queue with event " << t << '\n'; |
| theSimulation.scheduleEvent (new arriveEvent (t, 1 + irand (4))); |
| } |
| |
| // Run the simulation. |
| theSimulation.run (); |
| |
| std::cout << "Total profits " << theSimulation.profit |
| << "\nEnd of ice cream store simulation\n"; |
| |
| return 0; |
| } |