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
|
import math
import time
# time since last ping before deactivating/deleting
BIKE_TIMEOUT = 60000 # 3 minutes
BIKE_DELETE = 360000 # time before bike deletes itself
# data structures
class Point:
def __init__(self, lat, long):
self.longitude = long
self.latitude = lat
def toJSON(self):
json_dict = {"longitude": self.longitude, "latitude": self.latitude}
return json_dict
def setCoords(self, lat, long):
self.longitude = long
self.latitude = lat
def move(self, d_lat, d_long):
self.longitude += d_long
self.latitude += d_lat
def __str__(self):
return f"{self.longitude},{self.latitude}"
def __repr__(self):
return f"{self.longitude},{self.latitude}"
def distanceTo(self, pt): # distance between points in miles
lat1 = self.latitude
lon1 = self.longitude
lat2 = pt.latitude
lon2 = pt.longitude
R = 3958.8 # Radius of the earth
lat_d = math.radians(lat2 - lat1)
lon_d = math.radians(lon2 - lon1)
a = math.sin(lat_d / 2) * math.sin(lat_d / 2) + math.cos(
math.radians(lat1)
) * math.cos(math.radians(lat2)) * math.sin(lon_d / 2) * math.sin(lon_d / 2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
d = R * c
# Distance in mi
return d
class Clue(Point):
def __init__(self, lat, long, name, info, status, assigned_team = 0, required=False):
self.longitude = long
self.latitude = lat
self.name = name
self.info = info
self.status = status # UNVISITED | VISITED | DISABLED | ASSIGNED
self.assigned_team = assigned_team # 0 = to be assigned algorithmically
self.required = required
def visit(self):
self.status = "VISITED"
def unvisit(self):
self.status = "UNVISITED"
def toggle_enable(self):
if self.status == "UNVISITED" or self.status == "ASSIGNED":
self.status = "DISABLED"
elif self.status == "DISABLED":
self.status = "UNVISITED"
def toggle_required(self):
self.required = False if self.required else True
def toJSON(self):
json_dict = {'longitude' : self.longitude,
'latitude' : self.latitude,
'clue_name' : self.name.replace('"', "'"),
'clue_info' : self.info.replace('"', "'"),
'clue_status' : self.status,
'assigned_team' : self.assigned_team,
'clue_required' : self.required}
return json_dict
class Bike(Point):
def __init__(self, lat, long, name, status):
self.longitude = long
self.latitude = lat
self.name = name
self.last_contact = time.time()
self.target_name = "N/A"
self.cluster = [] # list of clues this bike team is responsible for
self.status = status # ACTIVE | INACTIVE
def setTarget(self, clue_name):
self.target_name = clue_name
def setCluster(self, clue_cluster):
self.cluster = clue_cluster
self.updateTarget()
def updateTarget(self):
if len(self.cluster) <= 0:
self.target_name = "N/A"
else:
self.target_name = self.cluster[0].name
def visitTarget(self):
self.cluster[0].visit()
self.cluster.pop(0)
self.updateTarget()
while len(self.cluster) > 0 and self.cluster[0].status == "VISITED":
self.cluster.pop(0) # skip next node if it has been somehow visited
self.updateTarget()
def ping(self):
self.status = "ACTIVE"
self.last_contact = time.time()
def disable(self):
self.status = "INACTIVE"
self.target = "N/A"
self.last_contact = 0
def checkStatus(self):
if time.time() - self.last_contact > BIKE_TIMEOUT:
self.status = "INACTIVE"
self.target = "N/A"
if time.time() - self.last_contact > BIKE_DELETE:
return -1
return 0
def toJSON(self):
json_dict = {
"longitude": self.longitude,
"latitude": self.latitude,
"time_since_last_contact": time.time() - self.last_contact,
"team_name": self.name,
"team_status": self.status,
"target_clue": self.target_name,
}
return json_dict
|