1
-
2
1
"""
3
2
Taxi simulator
4
3
27
26
28
27
"""
29
28
30
- import sys
31
29
import random
32
30
import collections
33
31
import queue
34
32
import argparse
33
+ import time
35
34
36
35
DEFAULT_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
40
39
DEPARTURE_INTERVAL = 5
41
40
42
41
Event = collections .namedtuple ('Event' , 'time proc action' )
43
42
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
47
66
return int (random .expovariate (1 / interval )) + 1
48
67
68
+
49
69
# BEGIN TAXI_PROCESS
50
70
def taxi_process (ident , trips , start_time = 0 ): # <1>
51
71
"""Yield to simulator issuing event at each state change"""
52
72
time = yield Event (start_time , ident , 'leave garage' ) # <2>
53
73
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>
56
76
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>
62
79
# END TAXI_PROCESS
63
80
81
+
64
82
# BEGIN TAXI_SIMULATOR
65
83
class Simulator :
66
84
67
85
def __init__ (self , procs_map ):
68
86
self .events = queue .PriorityQueue ()
69
87
self .procs = dict (procs_map )
70
88
71
-
72
- def run (self , end_time ): # <1>
89
+ def run (self , end_time , delay = False ): # <1>
73
90
"""Schedule and display events until time is up"""
74
91
# schedule the first event for each cab
75
92
for _ , proc in sorted (self .procs .items ()): # <2>
76
93
first_event = next (proc ) # <3>
77
94
self .events .put (first_event ) # <4>
78
95
79
96
# 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 >
83
100
print ('*** end of events ***' )
84
101
break
85
102
86
103
# 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 ]
91
111
# 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 )
94
113
try :
95
- next_event = proc .send (time ) # <11 >
114
+ next_event = active_proc .send (next_time ) # <12 >
96
115
except StopIteration :
97
- del self .procs [current_event . proc ] # <12 >
116
+ del self .procs [proc_id ] # <13 >
98
117
else :
99
- self .events .put (next_event ) # <13 >
100
- else : # <14 >
118
+ self .events .put (next_event ) # <14 >
119
+ else : # <15 >
101
120
msg = '*** end of simulation time: {} events pending ***'
102
121
print (msg .format (self .events .qsize ()))
103
122
# END TAXI_SIMULATOR
104
123
124
+
125
+
126
+
105
127
def main (end_time = DEFAULT_END_TIME , num_taxis = DEFAULT_NUMBER_OF_TAXIS ,
106
- seed = None ):
128
+ seed = None , delay = False ):
107
129
"""Initialize random generator, build procs and run simulation"""
108
130
if seed is not None :
109
131
random .seed (seed ) # get reproducible results
110
132
111
133
taxis = {i : taxi_process (i , (i + 1 )* 2 , i * DEPARTURE_INTERVAL )
112
134
for i in range (num_taxis )}
113
135
sim = Simulator (taxis )
114
- sim .run (end_time )
136
+ sim .run (end_time , delay )
115
137
116
138
117
139
if __name__ == '__main__' :
@@ -128,9 +150,11 @@ def main(end_time=DEFAULT_END_TIME, num_taxis=DEFAULT_NUMBER_OF_TAXIS,
128
150
% DEFAULT_NUMBER_OF_TAXIS )
129
151
parser .add_argument ('-s' , '--seed' , type = int , default = None ,
130
152
help = 'random generator seed (for testing)' )
153
+ parser .add_argument ('-d' , '--delay' , action = 'store_true' ,
154
+ help = 'introduce delay proportional to simulation time' )
131
155
132
156
args = parser .parse_args ()
133
- main (args .end_time , args .taxis , args .seed )
157
+ main (args .end_time , args .taxis , args .seed , args . delay )
134
158
135
159
136
160
"""
0 commit comments