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
+
1
26
import sys
2
27
import random
3
28
import collections
4
29
import queue
30
+ import argparse
5
31
32
+ DEFAULT_NUMBER_OF_TAXIS = 3
33
+ DEFAULT_END_TIME = 80
6
34
FIND_PASSENGER_INTERVAL = 4
7
35
TRIP_DURATION = 10
8
36
9
- Event = collections .namedtuple ('Event' , 'time actor action' )
37
+ Event = collections .namedtuple ('Event' , 'time actor_id action' )
10
38
11
39
12
40
def compute_delay (interval ):
13
41
"""Compute action delay using exponential distribution"""
14
42
return int (random .expovariate (1 / interval )) + 1
15
43
16
44
17
- def taxi_process (ident , trips ):
45
+ def taxi_process (ident , trips , start_time = 0 ):
18
46
"""Yield to simulator issuing event at each state change"""
19
- trip_ends = 0
47
+ time = start_time
20
48
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 ' )
23
51
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 ' )
26
54
27
55
yield Event (trip_ends + 1 , ident , 'going home' )
28
56
@@ -31,90 +59,100 @@ class Simulator:
31
59
32
60
def __init__ (self , actors ):
33
61
self .events = queue .PriorityQueue ()
34
- self .actors = list (actors )
35
- self .time = 0
62
+ self .actors = dict (actors )
36
63
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 )
46
64
47
65
def run (self , end_time ):
48
66
"""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 :
51
72
if self .events .empty ():
52
73
print ('*** end of events ***' )
53
74
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 )
57
90
else :
58
91
msg = '*** end of simulation time: {} events pending ***'
59
92
print (msg .format (self .events .qsize ()))
60
93
61
94
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 )}
80
102
sim = Simulator (taxis )
81
103
sim .run (end_time )
82
104
105
+
83
106
if __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 )
85
123
86
124
87
125
"""
88
126
Sample run:
89
127
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')
118
156
*** end of events ***
119
157
120
158
"""
0 commit comments