def find_routes(self, needed_items, nearby_stores, max_distance, use_api=True): """ Finds all the possible routes to purchase the needed items within the specified search radius. NOTE: The list of stores passed may include stores outside the search radius. This method will filter the list based on search radius before finding routes. :param needed_items: list of grocery items needed - [str] :param nearby_stores: list of nearby stores - [Store] :param max_distance: maximum distance (in miles) of stores from starting location to include in route - int :param use_api: whether or not to use the Supermarket API - bool :return a list of TripPlans sorted best to worst - [TripPlan] """ # Filter the stores to only include stores with a Euclidean distance within the specified search radius self.stores = [ store for store in nearby_stores if Geolocation.get_euclidean_dist( self.starting_location, store.location) <= max_distance ] print('Checking nearest {} stores for the needed items...'.format( len(self.stores))) # Load items at stores found_all_items, missing_item = StoreItemFetcher( use_api).check_stores_for_ingredients(needed_items, self.stores) if not found_all_items: print('Could not find item {} anywhere. Aborting.'.format( missing_item)) return False, missing_item print('Calculating the distances between places...') # Get distances between places locations = [store.location for store in self.stores] locations.insert(0, self.starting_location) self.distance_mapper.load_distances(locations, locations) print('Planning...') base_plan = TripPlan(first_stop=self.starting_location) routes = self.__find_path_continuations( base_plan, [], needed_items, 2 * max_distance) # Max distance is the diameter of the circle # Add returning to the starting point for route in routes: dist_home = self.distance_mapper.get_distance( route.last_stop.location, self.starting_location) home_stop = TripStop(route.last_stop, None, self.starting_location, dist_home, None, 0) route.add_stop(home_stop) # Sort stores best to worst routes.sort(key=lambda r: r.last_stop.dist_from_start) return True, routes
def get_stores_near_me(my_loc, radius, number): """ Get stores within a certain radius of user location. :param my_loc: location of the user - Location :param radius: search radius (miles) :param number: maximum number of stores to return """ sia = StoreInfoAccessor() stores = sia.get_stores_in_zip_range(my_loc.zipcode - 200, my_loc.zipcode + 200) stores_in_range = [] euc_dists = {} for s in stores: dist = Geolocation.get_euclidean_dist(my_loc, s.location) if dist <= radius: euc_dists[s.store_id] = dist stores_in_range.append(s) # Sort according to Euclidean distance stores_in_range.sort(key=lambda store: euc_dists[store.store_id]) # Return the top _number_ of stores return stores_in_range[:number]