-
Notifications
You must be signed in to change notification settings - Fork 1
/
monitor.py
162 lines (135 loc) · 5.01 KB
/
monitor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
"""
The Monitor module contains the Monitor class, the Activity class,
and a collection of constants. Together the elements of the module
help keep a record of activities that have occurred.
Activities fall into two categories: Rider activities and Driver
activities. Each activity also has a description, which is one of
request, cancel, pickup, or dropoff.
=== Constants ===
@type RIDER: str
A constant used for the Rider activity category.
@type DRIVER: str
A constant used for the Driver activity category.
@type REQUEST: str
A constant used for the request activity description.
@type CANCEL: str
A constant used for the cancel activity description.
@type PICKUP: str
A constant used for the pickup activity description.
@type DROPOFF: str
A constant used for the dropoff activity description.
"""
RIDER = "rider"
DRIVER = "driver"
REQUEST = "request"
CANCEL = "cancel"
PICKUP = "pickup"
DROPOFF = "dropoff"
class Activity:
"""An activity that occurs in the simulation.
=== Attributes ===
@type timestamp: int
The time at which the activity occurred.
@type description: str
A description of the activity.
@type identifier: str
An identifier for the person doing the activity.
@type location: Location
The location at which the activity occurred.
"""
def __init__(self, timestamp, description, identifier, location):
"""Initialize an Activity.
@type self: Activity
@type timestamp: int
@type description: str
@type identifier: str
@type location: Location
@rtype: None
"""
self.description = description
self.time = timestamp
self.id = identifier
self.location = location
class Monitor:
"""A monitor keeps a record of activities that it is notified about.
When required, it generates a report of the activities it has recorded.
"""
# === Private Attributes ===
# @type _activities: dict[str, dict[str, list[Activity]]]
# A dictionary whose key is a category, and value is another
# dictionary. The key of the second dictionary is an identifier
# and its value is a list of Activities.
def __init__(self):
"""Initialize a Monitor.
@type self: Monitor
"""
self._activities = {
RIDER: {},
DRIVER: {}
}
"""@type _activities: dict[str, dict[str, list[Activity]]]"""
def __str__(self):
"""Return a string representation.
@type self: Monitor
@rtype: str
"""
return "Monitor ({} drivers, {} riders)".format(
len(self._activities[DRIVER]), len(self._activities[RIDER]))
def notify(self, timestamp, category, description, identifier, location):
"""Notify the monitor of the activity.
@type self: Monitor
@type timestamp: int
The time of the activity.
@type category: DRIVER | RIDER
The category for the activity.
@type description: REQUEST | CANCEL | PICKUP | DROP_OFF
A description of the activity.
@type identifier: str
The identifier for the actor.
@type location: Location
The location of the activity.
@rtype: None
"""
if identifier not in self._activities[category]:
self._activities[category][identifier] = []
activity = Activity(timestamp, description, identifier, location)
self._activities[category][identifier].append(activity)
def report(self):
"""Return a report of the activities that have occurred.
@type self: Monitor
@rtype: dict[str, object]
"""
return {"rider_wait_time": self._average_wait_time(),
"driver_total_distance": self._average_total_distance(),
"driver_ride_distance": self._average_ride_distance()}
def _average_wait_time(self):
"""Return the average wait time of riders that have either been picked
up or have cancelled their ride.
@type self: Monitor
@rtype: float
"""
wait_time = 0
count = 0
for activities in self._activities[RIDER].values():
# A rider that has less than two activities hasn't finished
# waiting (they haven't cancelled or been picked up).
if len(activities) >= 2:
# The first activity is REQUEST, and the second is PICKUP
# or CANCEL. The wait time is the difference between the two.
wait_time += activities[1].time - activities[0].time
count += 1
return wait_time / count
def _average_total_distance(self):
"""Return the average distance drivers have driven.
@type self: Monitor
@rtype: float
"""
# TODO
pass
def _average_ride_distance(self):
"""Return the average distance drivers have driven on rides.
@type self: Monitor
@rtype: float
"""
# TODO
pass