1+
2+ """
3+ Taxi simulator
4+
5+ Sample run with two cars, random seed = 4::
6+
7+ >>> main(num_taxis=2, seed=7)
8+ taxi: 0 Event(time=2, actor_id=0, action='pick up passenger')
9+ taxi: 1 Event(time=11, actor_id=1, action='pick up passenger')
10+ taxi: 1 Event(time=12, actor_id=1, action='drop off passenger')
11+ taxi: 0 Event(time=13, actor_id=0, action='drop off passenger')
12+ taxi: 0 Event(time=15, actor_id=0, action='pick up passenger')
13+ taxi: 0 Event(time=16, actor_id=0, action='drop off passenger')
14+ taxi: 1 Event(time=16, actor_id=1, action='pick up passenger')
15+ taxi: 0 Event(time=17, actor_id=0, action='going home')
16+ taxi: 1 Event(time=24, actor_id=1, action='drop off passenger')
17+ taxi: 1 Event(time=25, actor_id=1, action='pick up passenger')
18+ taxi: 1 Event(time=31, actor_id=1, action='drop off passenger')
19+ taxi: 1 Event(time=32, actor_id=1, action='pick up passenger')
20+ taxi: 1 Event(time=33, actor_id=1, action='drop off passenger')
21+ taxi: 1 Event(time=34, actor_id=1, action='going home')
22+ *** end of events ***
23+
24+ """
25+
126import sys
227import random
328import collections
429import queue
30+ import argparse
531
32+ DEFAULT_NUMBER_OF_TAXIS = 3
33+ DEFAULT_END_TIME = 80
634FIND_PASSENGER_INTERVAL = 4
735TRIP_DURATION = 10
836
9- Event = collections .namedtuple ('Event' , 'time actor action' )
37+ Event = collections .namedtuple ('Event' , 'time actor_id action' )
1038
1139
1240def compute_delay (interval ):
1341 """Compute action delay using exponential distribution"""
1442 return int (random .expovariate (1 / interval )) + 1
1543
1644
17- def taxi_process (ident , trips ):
45+ def taxi_process (ident , trips , start_time = 0 ):
1846 """Yield to simulator issuing event at each state change"""
19- trip_ends = 0
47+ time = start_time
2048 for i in range (trips ):
21- prowling_ends = trip_ends + compute_delay (FIND_PASSENGER_INTERVAL )
22- yield Event (prowling_ends , ident , 'passenger picked up ' )
49+ prowling_ends = time + compute_delay (FIND_PASSENGER_INTERVAL )
50+ time = yield Event (prowling_ends , ident , 'pick up passenger ' )
2351
24- trip_ends = prowling_ends + compute_delay (TRIP_DURATION )
25- yield Event (trip_ends , ident , 'passenger dropped off' )
52+ trip_ends = time + compute_delay (TRIP_DURATION )
53+ time = yield Event (trip_ends , ident , 'drop off passenger ' )
2654
2755 yield Event (trip_ends + 1 , ident , 'going home' )
2856
@@ -31,90 +59,100 @@ class Simulator:
3159
3260 def __init__ (self , actors ):
3361 self .events = queue .PriorityQueue ()
34- self .actors = list (actors )
35- self .time = 0
62+ self .actors = dict (actors )
3663
37- def schedule_events (self ):
38- """Advance each actor to next state, scheduling events"""
39- for actor in list (self .actors ):
40- try :
41- future_event = next (actor )
42- except StopIteration :
43- self .actors .remove (actor ) # remove exhausted actor
44- else :
45- self .events .put (future_event )
4664
4765 def run (self , end_time ):
4866 """Schedule and execute events until time is up"""
49- while self .time < end_time :
50- self .schedule_events ()
67+ for ident , actor in sorted (self .actors .items ()):
68+ first_event = next (actor ) # prime each coroutine
69+ self .events .put (first_event )
70+ time = 0
71+ while time < end_time :
5172 if self .events .empty ():
5273 print ('*** end of events ***' )
5374 break
54- event = self .events .get ()
55- self .time = event .time
56- print ('taxi:' , event .actor , event .actor * ' ' , event )
75+
76+ # get and display current event
77+ current_event = self .events .get ()
78+ print ('taxi:' , current_event .actor_id ,
79+ current_event .actor_id * ' ' , current_event )
80+
81+ # schedule next action for current actor
82+ actor = self .actors [current_event .actor_id ]
83+ time = current_event .time
84+ try :
85+ next_event = actor .send (time )
86+ except StopIteration :
87+ del self .actors [current_event .actor_id ]
88+ else :
89+ self .events .put (next_event )
5790 else :
5891 msg = '*** end of simulation time: {} events pending ***'
5992 print (msg .format (self .events .qsize ()))
6093
6194
62- def extract_seed (args ):
63- """Set random seed if given in command line"""
64- for index , arg in enumerate (list (args )):
65- if arg .startswith ('seed=' ): # for testing...
66- seed = int (arg .split ('=' )[1 ])
67- random .seed (seed ) # get reproducible results
68- del args [index ]
69- return
70-
71-
72- def main (args ):
73- """Parse command line, build actors and run simulation"""
74- extract_seed (args )
75- if args :
76- end_time = int (args [0 ])
77- else :
78- end_time = 100
79- taxis = [taxi_process (i , (i + 1 )* 2 ) for i in range (3 )]
95+ def main (end_time = DEFAULT_END_TIME , num_taxis = DEFAULT_NUMBER_OF_TAXIS ,
96+ seed = None ):
97+ """Initialize random generator, build actors and run simulation"""
98+ if seed is not None :
99+ random .seed (seed ) # get reproducible results
100+
101+ taxis = {i : taxi_process (i , (i + 1 )* 2 , i * 10 ) for i in range (num_taxis )}
80102 sim = Simulator (taxis )
81103 sim .run (end_time )
82104
105+
83106if __name__ == '__main__' :
84- main (sys .argv [1 :])
107+
108+ parser = argparse .ArgumentParser (
109+ description = 'Taxi fleet simulator.' )
110+ parser .add_argument ('-e' , '--end-time' , type = int ,
111+ default = DEFAULT_END_TIME ,
112+ help = 'simulation end time; default = %s'
113+ % DEFAULT_END_TIME )
114+ parser .add_argument ('-t' , '--taxis' , type = int ,
115+ default = DEFAULT_NUMBER_OF_TAXIS ,
116+ help = 'number of taxis running; default = %s'
117+ % DEFAULT_NUMBER_OF_TAXIS )
118+ parser .add_argument ('-s' , '--seed' , type = int , default = None ,
119+ help = 'random generator seed (for testing)' )
120+
121+ args = parser .parse_args ()
122+ main (args .end_time , args .taxis , args .seed )
85123
86124
87125"""
88126Sample run:
89127
90- $ clear; python3 taxi_sim.py seed=5 110
91- taxi: 0 Event(time=4, actor =0, action='passenger picked up ')
92- taxi: 1 Event(time=6, actor=1 , action='passenger picked up ')
93- taxi: 2 Event(time=7, actor=2 , action='passenger picked up ')
94- taxi: 1 Event(time=20, actor =1, action='passenger dropped off ')
95- taxi: 1 Event(time=23, actor =1, action='passenger picked up ')
96- taxi: 0 Event(time=33, actor=0 , action='passenger dropped off ')
97- taxi: 2 Event(time=33, actor =2, action='passenger dropped off ')
98- taxi: 0 Event(time=34, actor=0 , action='passenger picked up ')
99- taxi: 0 Event(time=45, actor=0 , action='passenger dropped off')
100- taxi: 2 Event(time=45, actor=2 , action='passenger picked up ')
101- taxi: 0 Event(time=46, actor=0 , action='going home ')
102- taxi: 1 Event(time=47, actor =1, action='passenger dropped off')
103- taxi: 2 Event(time=47, actor=2 , action='passenger dropped off ')
104- taxi: 2 Event(time=49, actor =2, action='passenger picked up ')
105- taxi: 1 Event(time=50, actor=1 , action='passenger picked up ')
106- taxi: 1 Event(time=58, actor=1 , action='passenger dropped off')
107- taxi: 2 Event(time=58, actor =2, action='passenger dropped off ')
108- taxi: 1 Event(time=59, actor =1, action='passenger picked up ')
109- taxi: 2 Event(time=59, actor=2 , action='passenger picked up ')
110- taxi: 1 Event(time=63, actor=1 , action='passenger dropped off')
111- taxi: 1 Event(time=64, actor=1 , action='going home ')
112- taxi: 2 Event(time=84, actor =2, action='passenger dropped off')
113- taxi: 2 Event(time=90, actor =2, action='passenger picked up ')
114- taxi: 2 Event(time=92, actor =2, action='passenger dropped off')
115- taxi: 2 Event(time=99, actor=2 , action='passenger picked up ')
116- taxi: 2 Event(time=101, actor =2, action='passenger dropped off ')
117- taxi: 2 Event(time=102, actor=2 , action='going home')
128+ $ clear; python3 taxi_sim.py -s 19
129+ taxi: 0 Event(time=5, actor_id =0, action='pick up passenger ')
130+ taxi: 0 Event(time=13, actor_id=0 , action='drop off passenger ')
131+ taxi: 0 Event(time=16, actor_id=0 , action='pick up passenger ')
132+ taxi: 1 Event(time=17, actor_id =1, action='pick up passenger ')
133+ taxi: 1 Event(time=21, actor_id =1, action='drop off passenger ')
134+ taxi: 1 Event(time=22, actor_id=1 , action='pick up passenger ')
135+ taxi: 2 Event(time=23, actor_id =2, action='pick up passenger ')
136+ taxi: 1 Event(time=26, actor_id=1 , action='drop off passenger ')
137+ taxi: 2 Event(time=27, actor_id=2 , action='drop off passenger ')
138+ taxi: 1 Event(time=28, actor_id=1 , action='pick up passenger ')
139+ taxi: 2 Event(time=29, actor_id=2 , action='pick up passenger ')
140+ taxi: 1 Event(time=30, actor_id =1, action='drop off passenger ')
141+ taxi: 1 Event(time=32, actor_id=1 , action='pick up passenger ')
142+ taxi: 2 Event(time=33, actor_id =2, action='drop off passenger ')
143+ taxi: 2 Event(time=34, actor_id=2 , action='pick up passenger ')
144+ taxi: 2 Event(time=35, actor_id=2 , action='drop off passenger ')
145+ taxi: 2 Event(time=36, actor_id =2, action='pick up passenger ')
146+ taxi: 1 Event(time=41, actor_id =1, action='drop off passenger ')
147+ taxi: 1 Event(time=42, actor_id=1 , action='going home ')
148+ taxi: 2 Event(time=44, actor_id=2 , action='drop off passenger ')
149+ taxi: 2 Event(time=46, actor_id=2 , action='pick up passenger ')
150+ taxi: 2 Event(time=60, actor_id =2, action='drop off passenger ')
151+ taxi: 2 Event(time=67, actor_id =2, action='pick up passenger ')
152+ taxi: 2 Event(time=73, actor_id =2, action='drop off passenger ')
153+ taxi: 0 Event(time=74, actor_id=0 , action='drop off passenger ')
154+ taxi: 2 Event(time=74, actor_id =2, action='going home ')
155+ taxi: 0 Event(time=75, actor_id=0 , action='going home')
118156*** end of events ***
119157
120158"""
0 commit comments