summaryrefslogtreecommitdiff
path: root/dashboard_website/datastructs.py
blob: 4fe5038f2756508435abcbc62f9185f979151e66 (plain)
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
import math
import time
import datetime

# time since last ping before deactivating/deleting
BIKE_TIMEOUT = 60000  # 3 minutes

endtime = datetime.datetime(2024, 11, 16, hour=18, minute=45)

# 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 set_team(self, team):
        self.assigned_team = team

    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):
        self.longitude = long
        self.latitude = lat
        self.name = name
        self.deadline = endtime
        self.last_contact = time.time()
        self.target_clue = None
        self.time_modifier = 1 # factor by which to modulate expected arrival time
        self.cluster = []  # list of clues this bike team is responsible for
        self.status = "DISABLED"  # DISABLED | ACTIVE | INACTIVE
        self.clue_assignment_time = 0 # when clue was assigned, so that upon clue visitation we can determine speed

    def setTarget(self, clue_name):
        self.target_name = clue_name

    def setCluster(self, clue_cluster):
        self.cluster = clue_cluster
        self.updateTarget()

    def setDeadline(self, new_deadline):
        self.deadline = new_deadline
    
    def timeTilDeadline(self):
        return (self.deadline - datetime.datetime.now()).total_seconds()

    def updateTarget(self):
        self.clue_assignment_time = time.time()
        if len(self.cluster) <= 0:
            self.target_clue = None
            self.status = "INACTIVE"
        else:
            self.status = "ACTIVE"
            self.target_clue = self.cluster[0]

    def visitTarget(self):
        print("clue visit time: ", time.time() - self.clue_assignment_time)
        self.target_clue.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 = "DISABLED"
        self.target = None
    
    def enable(self):
        self.status = "INACTIVE"
        self.target = None
    
    def tripTime(self):
        return datetime.datetime.now() - self.deadline

    def toJSON(self):
        json_dict = {
            "longitude": self.longitude,
            "latitude": self.latitude,
            "time_since_last_contact": time.time() - self.last_contact,
            "team_deadline" : str(self.deadline),
            "team_name": self.name,
            "team_status": self.status,
            "target_clue": self.target_clue.name if self.target_clue else "N/A",
        }
        return json_dict