# stores and manages clue DB # also manages currently available bike teams import router import csv, time # time since last ping before deactivating/deleting BIKE_TIMEOUT = 60 BIKE_DELETE = 1800 # 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}" class Clue(Point): def __init__(self, lat, long, name, info, status): self.longitude = long self.latitude = lat self.name = name self.info = info self.status = status # UNVISITED | ASSIGNED | VISITED def visit(self): self.status = "VISITED" 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} 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 = "N/A" self.route_to_next = [] # list of coords if target isnt' N/A self.status = status # ACTIVE | INACTIVE def setTarget(self, clue_name): self.target = clue_name def ping(self): self.status = "ACTIVE" self.last_contact = time.time() 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} return json_dict # variables homeBase = Point(42.340226, -71.088395) # krentzman, can be changed on dashboard clues = [] bikes = [] assigned_clues = [] clues_last_changed = time.time() home_last_changed = time.time() # called every time a node is added # a bike is added/removed # determines/assigns clusters, and assigns routes to bikes def updateRoutes(): clusters = router.getClusters(bikes, clues, homeBase) # interface functions def getTime(): return time.time() def getHomeBaseJSON(timestamp): if timestamp < 0 or home_last_changed - timestamp > 0: return homeBase.toJSON() return False def setHomeBase(latitude, longitude): homeBase.setCoords(latitude, longitude) home_last_changed = time.time() def addBike(team_name, latitude, longitude): for bike in bikes: if bike.name == team_name: # already exists bike.ping() bike.setCoords(latitude, longitude) return # return code indicating already exists, although status still OK newBike = Bike(latitude, longitude, team_name, "ACTIVE") bikes.append(newBike) def pingBike(team_name, latitude, longitude): for bike in bikes: if bike.name == team_name: bike.ping() bike.setCoords(latitude, longitude) break else: # bike team does not exist yet newBike = Bike(latitude, longitude, team_name, "ACTIVE") bikes.append(newBike) def getBikesJSON(): global bikes bikes = [x for x in bikes if x.checkStatus() >= 0] return [x.toJSON() for x in bikes] def getCluesJSON(timestamp): if timestamp < 0 or clues_last_changed - timestamp > 0: return [x.toJSON() for x in clues] return False def addClue(clue_name, clue_info, longitude, latitude, visited="UNVISITED"): newClue = Clue(latitude, longitude, clue_name, clue_info, visited) clues.append(newClue) clues_last_changed = time.time() def deleteClue(clue_name): for i, clue in enumereate(clues): if clue.name == clue_name: clues.pop(i) clues_last_changed = time.time() break def visitClue(clue_name): for clue in clues: if clue.name == clue_name: clue.visit() clues_last_changed = time.time() # junk for testing with open("all_clues.csv", newline='') as f: csvreader = csv.reader(f, delimiter=',', quotechar='"') i = 1 for row in csvreader: coords = row[1].split(",") coords[0] = float(coords[0]); coords[1] = float(coords[1]); newClue = Clue(coords[0], coords[1], f"Clue #{i}", row[0], "UNVISITED" if i < 50 else "VISITED") clues.append(newClue) i += 1 bike1 = Bike(42.340226, -71.088395, 'speedster', 'ACTIVE') bike2 = Bike(42.320226, -71.100395, 'slowpoke', "ACTIVE") bike1.setTarget("Clue #6") def moveBike2Test(): bike1.move(0, -0.001); bike1.ping(); bikes.append(bike1); bikes.append(bike2)