1-
21"""
32Taxi simulator
43
2726
2827"""
2928
30- import sys
3129import random
3230import collections
3331import queue
3432import argparse
33+ import time
3534
3635DEFAULT_NUMBER_OF_TAXIS = 3
37- DEFAULT_END_TIME = 80
38- SEARCH_DURATION = 4
39- TRIP_DURATION = 10
36+ DEFAULT_END_TIME = 180
37+ SEARCH_DURATION = 5
38+ TRIP_DURATION = 20
4039DEPARTURE_INTERVAL = 5
4140
4241Event = collections .namedtuple ('Event' , 'time proc action' )
4342
44-
45- def compute_delay (interval ):
46- """Compute action delay using exponential distribution"""
43+ Actitivy = collections .namedtuple ('Actitivy' , 'name distr_param' )
44+
45+ START = Actitivy ('start shift' , TRIP_DURATION )
46+ SEARCH_PAX = Actitivy ('searching for passenger' , SEARCH_DURATION )
47+ DRIVE_PAX = Actitivy ('driving passenger' , TRIP_DURATION )
48+
49+ TRANSITIONS = {
50+ START : SEARCH_PAX ;
51+ SEARCH_PAX : DRIVE_PAX ;
52+ }
53+
54+ def compute_duration (previous_action ):
55+ """Compute action duration using exponential distribution"""
56+ if previous_action in ['leave garage' , 'drop off passenger' ]:
57+ # state is prowling
58+ interval = SEARCH_DURATION
59+ elif previous_action == 'pick up passenger' :
60+ # state is trip
61+ interval = TRIP_DURATION
62+ elif previous_action == 'going home' :
63+ interval = 1
64+ else :
65+ assert False
4766 return int (random .expovariate (1 / interval )) + 1
4867
68+
4969# BEGIN TAXI_PROCESS
5070def taxi_process (ident , trips , start_time = 0 ): # <1>
5171 """Yield to simulator issuing event at each state change"""
5272 time = yield Event (start_time , ident , 'leave garage' ) # <2>
5373 for i in range (trips ): # <3>
54- prowling_ends = time + compute_delay ( SEARCH_DURATION ) # <4>
55- time = yield Event (prowling_ends , ident , 'pick up passenger' ) # <5>
74+ time = yield Event ( time , ident , 'pick up passenger' ) # <4>
75+ time = yield Event (time , ident , 'drop off passenger' ) # <5>
5676
57- trip_ends = time + compute_delay (TRIP_DURATION ) # <6>
58- time = yield Event (trip_ends , ident , 'drop off passenger' ) # <7>
59-
60- yield Event (time + 1 , ident , 'going home' ) # <8>
61- # end of taxi process # <9>
77+ yield Event (time , ident , 'going home' ) # <6>
78+ # end of taxi process # <7>
6279# END TAXI_PROCESS
6380
81+
6482# BEGIN TAXI_SIMULATOR
6583class Simulator :
6684
6785 def __init__ (self , procs_map ):
6886 self .events = queue .PriorityQueue ()
6987 self .procs = dict (procs_map )
7088
71-
72- def run (self , end_time ): # <1>
89+ def run (self , end_time , delay = False ): # <1>
7390 """Schedule and display events until time is up"""
7491 # schedule the first event for each cab
7592 for _ , proc in sorted (self .procs .items ()): # <2>
7693 first_event = next (proc ) # <3>
7794 self .events .put (first_event ) # <4>
7895
7996 # main loop of the simulation
80- time = 0
81- while time < end_time : # <5 >
82- if self .events .empty (): # <6 >
97+ sim_time = 0 # <5>
98+ while sim_time < end_time : # <6 >
99+ if self .events .empty (): # <7 >
83100 print ('*** end of events ***' )
84101 break
85102
86103 # get and display current event
87- current_event = self .events .get () # <7>
88- print ('taxi:' , current_event .proc , # <8>
89- current_event .proc * ' ' , current_event )
90-
104+ current_event = self .events .get () # <8>
105+ if delay :
106+ time .sleep ((current_event .time - sim_time ) / 2 )
107+ # update the simulation time
108+ sim_time , proc_id , previous_action = current_event
109+ print ('taxi:' , proc_id , proc_id * ' ' , current_event )
110+ active_proc = self .procs [proc_id ]
91111 # schedule next action for current proc
92- time = current_event .time # <9>
93- proc = self .procs [current_event .proc ] # <10>
112+ next_time = sim_time + compute_duration (previous_action )
94113 try :
95- next_event = proc .send (time ) # <11 >
114+ next_event = active_proc .send (next_time ) # <12 >
96115 except StopIteration :
97- del self .procs [current_event . proc ] # <12 >
116+ del self .procs [proc_id ] # <13 >
98117 else :
99- self .events .put (next_event ) # <13 >
100- else : # <14 >
118+ self .events .put (next_event ) # <14 >
119+ else : # <15 >
101120 msg = '*** end of simulation time: {} events pending ***'
102121 print (msg .format (self .events .qsize ()))
103122# END TAXI_SIMULATOR
104123
124+
125+
126+
105127def main (end_time = DEFAULT_END_TIME , num_taxis = DEFAULT_NUMBER_OF_TAXIS ,
106- seed = None ):
128+ seed = None , delay = False ):
107129 """Initialize random generator, build procs and run simulation"""
108130 if seed is not None :
109131 random .seed (seed ) # get reproducible results
110132
111133 taxis = {i : taxi_process (i , (i + 1 )* 2 , i * DEPARTURE_INTERVAL )
112134 for i in range (num_taxis )}
113135 sim = Simulator (taxis )
114- sim .run (end_time )
136+ sim .run (end_time , delay )
115137
116138
117139if __name__ == '__main__' :
@@ -128,9 +150,11 @@ def main(end_time=DEFAULT_END_TIME, num_taxis=DEFAULT_NUMBER_OF_TAXIS,
128150 % DEFAULT_NUMBER_OF_TAXIS )
129151 parser .add_argument ('-s' , '--seed' , type = int , default = None ,
130152 help = 'random generator seed (for testing)' )
153+ parser .add_argument ('-d' , '--delay' , action = 'store_true' ,
154+ help = 'introduce delay proportional to simulation time' )
131155
132156 args = parser .parse_args ()
133- main (args .end_time , args .taxis , args .seed )
157+ main (args .end_time , args .taxis , args .seed , args . delay )
134158
135159
136160"""
0 commit comments