# stores and manages clue DB # also manages currently available bike teams from datastructs import * import router import csv, time from threading import Thread # constants CLUE_MIN_DISTANCE = 0.1 # minimum distance between clue and bike to be considered valid visitation # variables homeBase = Point(42.340226, -71.088395) # krentzman, can be changed on dashboard clues = [] bikes = [] clusters = [] routes = {"clusters" : [], "cluster_times" : {}, "individual_routes" : []} #geojson polylines, both between all the clusters assigned_clues = [] clues_last_changed = time.time() home_last_changed = time.time() routes_last_changed = time.time() currently_updating = False startup = False # # called every time a node is added # a bike is added/removed # determines/assigns clusters, and assigns routes to bikes def updateRoutes_background(): # run in thread due to long runtime global currently_updating, routes_last_changed, routes print("Calculating clusters...") routes = {"clusters" : [], "cluster_times" : {}, "individual_routes" : []} # reset clusters, paths, times = router.getClusters(bikes, clues, homeBase) routes['individual_routes'] = paths.copy() routes['cluster_times'] = times routes['clusters'] = paths for i in range(len(bikes)): if bikes[i].status == "ACTIVE": routes['individual_routes'][i] = router.getRouteHDPolyline(bikes[i], clusters[i][0]) routes_last_changed = time.time() print("Finished calculating clusters/routes.") currently_updating = False def updateRoutes(): # if necessary global currently_updating if not currently_updating: currently_updating = True t = Thread(target=updateRoutes_background) t.start() # 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 getBikeCluePair(team_name): b = None; c = None for bike in bikes: if bike.name == team_name: b = bike for clue in clues: if clue.name == b.target: c = clue break break return b, c def getRoutesJSON(timestamp): if timestamp < 0 or routes_last_changed - timestamp > 0: return routes return False def deleteBike(team_name): for bike in bikes: if bike.name == team_name: # already exists bike.disable() updateRoutes() return 0 # OK return 4 # bike does not exist def addBike(team_name, latitude, longitude): for bike in bikes: if bike.name == team_name: # already exists return 4 # already exists newBike = Bike(latitude, longitude, team_name, "ACTIVE") bikes.append(newBike) updateRoutes() return 0 def pingBike(team_name, latitude, longitude): for bike in bikes: if bike.name == team_name: bike.ping() bike.setCoords(latitude, longitude) return 0 return 4 # team not found def getBikesJSON(): global bikes old_length = len(bikes) bikes = [x for x in bikes if x.checkStatus() >= 0] if old_length != len(bikes): updateRoutes() 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() updateRoutes() break def visitClue(clue_name): for clue in clues: if clue.name == clue_name: if clue.status == "VISITED": return 3 # already visited clue.visit() clues_last_changed = time.time() #updateRoutes() return 0 # OK return 2 # no clue found def visitClueTeam(team_name, clue_name): b = None for bike in bikes: if bike.name == team_name: b = bike else: return 4 # team not found c = None for clue in clues: if clue.name == clue_name: c = clue if c.status == "VISITED": return 6 # already visited break # continue else: return 5 # clue not found # if visited clue is the expected one (current target) if clue_name == b.target_name: if c.distanceTo(b) < CLUE_MIN_DISTANCE: return 3 # too far away b.visitTarget() clues_last_changed = time.time() return 0 # otherwise c.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 < 100 else "VISITED") clues.append(newClue) i += 1