def test_queue(): queue = Queue() queue.push("foo") queue.push("bar") queue.push("baz") assert "foo" == queue.pop() assert "bar" == queue.pop() assert "baz" == queue.pop()
def test_init(self): queue = Queue([6, 8, 45, 1, 84, 149, 9, 17]) self.assertEqual(queue.pop(), 6) self.assertEqual(queue.pop(), 8) self.assertEqual(queue.pop(), 45) self.assertEqual(queue.pop(), 1) self.assertEqual(queue.pop(), 84) self.assertEqual(queue.pop(), 149) self.assertEqual(queue.pop(), 9) self.assertEqual(queue.pop(), 17)
class IteratorBFT: def __init__(self, heap_size, heap_list): self.current_elem = 0 self.heap_list = heap_list self.end = heap_size - 1 self.count = 0 self.queue = Queue() self.queue.push(0) def __iter__(self): return self def has_left_child(self, index): if (2 * index) + 1 <= self.end: return True return False def has_right_child(self, index): if (2 * index) + 2 <= self.end: return True return False def __next__(self): if self.count <= self.end: current_elem = self.current_elem if self.has_left_child(self.current_elem): self.queue.push((2 * self.current_elem) + 1) if self.has_right_child(self.current_elem): self.queue.push((2 * self.current_elem) + 2) self.queue.pop() if self.count != self.end: self.current_elem = self.queue.get_top() self.count += 1 return self.heap_list[current_elem] else: raise StopIteration
def test_pop(self): queue = Queue() queue.push(1) queue.push(50) queue.push(30) queue.push(70) self.assertEqual(queue.pop(), 1) self.assertEqual(queue.pop(), 50) queue.push(75) self.assertEqual(queue.peek(), 30) self.assertEqual(queue.pop(), 30) self.assertEqual(queue.pop(), 70) queue.push(876) self.assertEqual(queue.peek(), 75) self.assertEqual(queue.pop(), 75) self.assertEqual(queue.pop(), 876)
class Truck: """ Truck class to hold packages and deliver to destination """ def __init__(self, truck_id, package_limit, speed, start_of_day, hub_location): """ Create Truck Object :param truck_id: id of the truck :int :param package_limit: maximum number of packages truck can hold :int :param speed: speed of truck in miles per hour :int :param start_of_day: time of start of day :str :param hub_location: location of hub :Location :return: Truck Object Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ self._id = truck_id self._package_limit = package_limit self._speed = (speed / 60) / 60 # truck speed in miles per second self._locations = Graph() self._packages = [] self._start_of_day = start_of_day self._locations.add_vertex(hub_location.name, hub_location) self._route = Queue() self._departure_time = None # departure time in seconds since start self._distance_traveled = 0.0 self._current_location = None self._next_location = None self._route_done = False @property def truck_id(self): """ Read-only truck id. Cannot be changed after Object creation :return: Truck ID :int Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ return self._id @property def distance_traveled(self): """ Read-only distance traveled. Cannot be set outside of class :return: distance traveled :float Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ return self._distance_traveled @property def package_limit(self): """ Read-only truck package limit. Cannot be changed after Object creation :return: package limit for truck :int Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ return self._package_limit @property def next_location(self): """ Returns next location to be visited :return: next locations to be visited, distance to that location :2-tuple Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ return self._next_location def get_next_location(self, time): """ Sets next_location to the next location to be visited :param time: current_time :return: None Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ if not self._route.is_empty(): self._next_location = self._route.pop() else: self._route_done = True print( f"{Clock.to_time_string(time, self._start_of_day)}: " f"Truck {self.truck_id} finished route ({self.distance_traveled:.2f} miles driven)" ) def start_route(self, time): """ Start truck's delivery route :param time: current time :return: None Worst Case Runtime Complexity: O(N) Best Case Runtime Complexity: O(N) """ self._next_location = self._route.pop() for package in self._packages: package.status = "EN ROUTE" self._departure_time = time self._next_location = self._route.pop() print( f"{Clock.to_time_string(time, self._start_of_day)}: Truck {self.truck_id} leaving Hub" ) def get_package_count(self): """ Return the number of packages currently on the truck :return: number of packages on truck :int Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ return len(self._packages) def move_truck(self): """ Move truck forward :return: distance moved Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ if not self._route_done: self._distance_traveled += self._speed return self._speed return 0 def is_route_done(self): """ Return whether truck has finished route or not :return: Boolean representing whether route is finished or not :Boolean Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ return self._route_done def get_package_list(self): """ Returns list of packages on truck :return: list of packages :List<Package> Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ return self._packages def is_on_truck(self, package_id): """ Returns True if package with given id is on the truck :param package_id: package_id to search for :return: True if package on truck, otherwise False Worst Case Runtime Complexity: O(N) Best Case Runtime Complexity: O(1) """ for package in self._packages: if package.package_id == package_id: return True return False def load_package(self, package): """ Add package to truck :param package: package to be added :Package :return: Void Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ self._packages.append(package) def set_locations(self, locations_graph): """ Populate _locations graph with package locations and set edges for the graph :param locations_graph: Graph with locations data for all locations :return: Void Worst Case Runtime Complexity: O(N^2) Best Case Runtime Complexity: O(N^2) """ for package in self._packages: if package.location not in map(lambda x: x.data, self._locations.get_vertex_list()): for vertex in locations_graph.get_vertex_list(): if vertex.data == package.location: self._locations.add_vertex(vertex.data.name, vertex.data) break for location in map(lambda x: x.data, self._locations.get_vertex_list()): # index in truck graph index = self._locations.get_vertex_list().index( self._locations.get_vertex(location.name)) # index in graph of all locations all_locations_index = locations_graph.get_vertex_list().index( locations_graph.get_vertex(location.name)) for num, loc in enumerate( map(lambda x: x.data, self._locations.get_vertex_list())): cur_index = locations_graph.get_vertex(loc.name).index self._locations.adjacency_matrix[index][ num] = locations_graph.adjacency_matrix[ all_locations_index][cur_index] def deliver_package(self, package): """ Remove package from truck and return package ID :param package: package to be removed :return: package ID of package removed :int Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ return self._packages.pop(self._packages.index(package)).package_id def print_packages(self): for package in self._packages: package.print(self._start_of_day) def find_route(self): """ Calculate delivery route :return: Void Worst Case Runtime Complexity: O(N^2) Best Case Runtime Complexity: O(N^2) """ # Worst Case Runtime Complexity: O(N^2) # Best Case Runtime Complexity: O(N^2) route = self._locations.calculate_tour( self._locations.get_vertex_list()[0]) start = route.peek() total_distance = 0.0 last_location = start while not route.is_empty(): current_location = route.pop() distance = self._locations.get_edge_weight(last_location, current_location) total_distance += distance self._route.push((current_location, total_distance)) last_location = current_location @staticmethod def sort_packages(packages, trucks, start_of_day, end_of_day): """ Sort packages into trucks :param packages: list of packages to load :param trucks: list of trucks :param start_of_day: start of day time :param end_of_day: end of day time :return: trucks with packages loaded :List<Truck> Worst Case Runtime Complexity: O(N^2) Best Case Runtime Complexity: O(N^2) """ # Load packages that must be on same truck onto truck 1 along with any packages with same address # Worst Case Runtime Complexity: O(N^2) # Best Case Runtime Complexity: O(N^2) same_truck_packages = [] for package in filter( lambda x: x.special_instructions.startswith( "Must be delivered with"), packages): deliver_with = package.special_instructions[23:].split(", ") if package not in same_truck_packages: same_truck_packages.append(package) for cur_package in filter( lambda x: str(x.package_id) in deliver_with, packages): if cur_package not in same_truck_packages: same_truck_packages.append(cur_package) # Worst Case Runtime Complexity: O(N) # Best Case Runtime Complexity: O(N) same_locations = [] for package in same_truck_packages: if package.location not in same_locations: same_locations.append(package.location) package.truck = 1 trucks[0].load_package(package) packages.remove(package) # Worst Case Runtime Complexity: O(N) # Best Case Runtime Complexity: O(N) found_packages = [] for package in packages: if package.location in same_locations and not package.has_special_instructions( ): found_packages.append(package) # Worst Case Runtime Complexity: O(N) # Best Case Runtime Complexity: O(N) for package in found_packages: package.truck = 1 trucks[0].load_package(package) packages.remove(package) # Load remaining packages with special instructions # Worst Case Runtime Complexity: O(N) # Best Case Runtime Complexity: O(N) for package in filter(lambda x: x.has_special_instructions(), packages): if package.special_instructions == "Wrong address listed": package.truck = len(trucks) trucks[-1].load_package(package) packages.remove(package) for pckg in packages: new_location = Location("410 S State St", "Salt Lake City", "UT", "84111") if pckg.location == new_location and pckg.deadline == Clock.seconds_since_start( end_of_day, start_of_day): pckg.truck = len(trucks) trucks[-1].load_package(pckg) packages.remove(pckg) elif package.special_instructions.startswith("Delayed on flight"): package.truck = 2 trucks[1].load_package(package) packages.remove(package) elif package.special_instructions.startswith( "Can only be on truck") and package in packages: package.truck = int(package.special_instructions[-1]) trucks[int(package.special_instructions[-1]) - 1].load_package(package) packages.remove(package) # Load packages with no deadline onto truck 3 # Worst Case Runtime Complexity: O(N) # Best Case Runtime Complexity: O(N) no_deadline = [] for package in filter( lambda x: not x.deadline < Clock.seconds_since_start( end_of_day, start_of_day), packages): no_deadline.append(package) for package in no_deadline: if len(trucks[-1]._packages) < 16: package.truck = len(trucks) trucks[-1].load_package(package) packages.remove(package) else: package.truck = len(trucks) - 1 trucks[-2].load_package(package) packages.remove(package) current_truck = 0 while len(packages) > 0: while current_truck < 3 and trucks[current_truck].get_package_count( ) < 16 and len(packages) > 0: packages[-1].truck = current_truck + 1 trucks[current_truck].load_package(packages[-1]) packages.remove(packages[-1]) current_truck += 1 return trucks
class Simulation: def __init__(self, start_time, delayed_flight_time, table_size): """ Create a Simulation Object :param start_time: start time of simulation :param delayed_flight_time: time delayed packages arrive on flight :param table_size: size of the hashtable Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ self._start_time = start_time self._clock = Clock(0, start_time) self._packages = HashTable(table_size) self._active_trucks = [] self._trucks = Queue() self.simulation_over = False self._delayed_flight_time = Clock.seconds_since_start(delayed_flight_time, start_time) self._delayed_packages_departed = False self._total_miles = 0.0 self.locations = Graph() self.wrong_address_fixed = False def add_package(self, package): """ Add a package to the simulation :param package: package to be added :return: Void Worst Case Runtime Complexity: O(N) Best Case Runtime Complexity: O(1) """ self._packages.insert(package) def setup(self, num_trucks, packages_per_truck, truck_mph, start_of_day, end_of_day): """ Sets up simulations by loading and queueing up trucks :param num_trucks: number of trucks available :param packages_per_truck: number of packages per truck :param truck_mph: speed of truck in miles per hour :param start_of_day: start time of simulation :param end_of_day: time of end of day :return: None Worst Case Runtime Complexity: O(N^2) Best Case Runtime Complexity: O(N^2) """ truck_list = [] for truck_id in range(1, num_trucks + 1): truck_list.append(Truck(truck_id, packages_per_truck, truck_mph, start_of_day, self.locations.get_vertex_by_index(0).data)) truck_queue = Queue() for truck in Truck.sort_packages([x for x in self._packages], truck_list, start_of_day, end_of_day): # Add location data for packages in truck truck.set_locations(self.locations) truck.find_route() # Add truck to truck queue self._trucks.push(truck) def main_menu(self): """ Main menu for simulation control :return: None Worst Case Runtime Complexity: O(N^2) Best Case Runtime Complexity: O(1) """ selection = 0 min_choice = 1 max_choice = 3 print("-------------------------------------------------------------------------------------------------------") while selection not in range(min_choice, max_choice + 1): print() print("1.\tPrint Package Data") print("2.\tMove Time Forward") print("3.\tExit Application") print() selection = int(input("Enter Selection: ")) if selection == 1: self.package_menu() elif selection == 2: self.clock_menu() elif selection == 3: sys.exit() def package_menu(self): """ Menu for printing package information Worst Case Runtime Complexity: O(N) Best Case Runtime Complexity: O(1) :return: """ selection = 0 min_choice = 1 max_choice = 4 while selection not in range(min_choice, max_choice + 1): print() print("1.\tPrint package by ID") print("2.\tPrint all packages") print("3.\tPrint packages by truck") print("4.\tMain Menu") print() selection = int(input("Enter Selection: ")) if selection == 1: selection = None while not isinstance(selection, int): print() selection = int(input("Enter Package ID: ")) package = self._packages.search(selection) package.print(self._start_time) elif selection == 2: print() print("---------------------------------------------------------------------------------------------------") print(f"Time: {Clock.to_time_string(self._clock.time, self._start_time)}") for package in self._packages: package.print(self._start_time) elif selection == 3: print() print("---------------------------------------------------------------------------------------------------") for num in range(1, 4): print(f"{Clock.to_time_string(self._clock.time, self._start_time)} : Truck {num} Packages:") for package in self._packages: if package.truck == num and package.status != "DELIVERED": package.print(self._start_time) elif selection == 4: self.main_menu() def clock_menu(self): """ Menu to get amount of time to move simulation forward :return: None Worst Case Runtime Complexity: O(N^2) Best Case Runtime Complexity: O(1) """ selection = 0 min_choice = 1 max_choice = 4 while selection not in range(min_choice, max_choice + 1): print() print("1.\tHours") print("2.\tMinutes") print("3.\tSeconds") print("4.\tMain Menu") print() selection = int(input("Enter Selection: ")) if selection == 1: num_hours = int(input("How many hours? ")) time_amount = self._clock.forward_hours(num_hours) self.advance_simulation(time_amount) elif selection == 2: num_minutes = int(input("How many minutes? ")) time_amount = self._clock.forward_minutes(num_minutes) self.advance_simulation(time_amount) elif selection == 3: num_seconds = int(input("How many seconds? ")) time_amount = self._clock.forward_seconds(num_seconds) self.advance_simulation(time_amount) elif selection == 4: self.main_menu() def start_simulation(self): """ Start simulation :return: None Worst Case Runtime Complexity: O(N^2) Best Case Runtime Complexity: O(1) """ self._active_trucks.append(self._trucks.pop()) for truck in self._active_trucks: truck.start_route(self._clock.time) while not self.simulation_over: self.main_menu() print() input("Press any key to print package data") print() print("-------------------------------------------------------------------------------------------------------") print(f"Time: {Clock.to_time_string(self._clock.time, self._start_time)}") for package in self._packages: package.print(self._start_time) def print_summary(self): """ Print summary information for simulation :return: None Worst Case Runtime Complexity: O(1) Best Case Runtime Complexity: O(1) """ print(f"Total Distance: {self._total_miles:.2f} Miles") late_packages = 0 print("-------------------------------------------------------------------------------------------------------") print("Late Packages:") for package in self._packages: if package.time_delivered is not None and package.time_delivered > package.deadline: late_packages += 1 package.print(self._start_time) print(f"Total Late Packages: {late_packages}") print("-------------------------------------------------------------------------------------------------------") print("Undelivered Packages:") undelivered_packages = 0 for package in self._packages: if package.status != "DELIVERED": undelivered_packages += 1 package.print(self._start_time) print(f"Total Undelivered Packages: {undelivered_packages}") print("-------------------------------------------------------------------------------------------------------") print(f"Total distance traveled: {self._total_miles:.2f} miles") print(f"Packages delivered: {self._packages.num_items}") duration = Clock.total_duration(self._clock.time) print(f"Duration: {duration[0]} Hours {duration[1]} Minutes {duration[2]} Seconds") def advance_simulation(self, time_amount): """ Move simulation forward :param time_amount: amount of time to move simulation forward :return: None Worst Case Runtime Complexity: O(N^2) Best Case Runtime Complexity: O(N^2) """ # Run simulation for amount of time selected in clock menu while self._clock.time < time_amount and not self.simulation_over: # advance time forward self._clock.advance_time() # Fix wrong address package if current time is 10:20 AM or later # Worst Case Runtime Complexity: O(1) # Best Case Runtime Complexity: O(1) if self._clock.time >= Clock.seconds_since_start("10:20 AM", self._start_time) \ and not self.wrong_address_fixed: new_location = Location("410 S State St", "Salt Lake City", "UT", "84111", "") self._packages.search(9).location = new_location self.wrong_address_fixed = True print(f"{Clock.to_time_string(self._clock.time, self._start_time)} : Package 9 address changed to {new_location}") # for each truck update truck and package data # Worst Case Runtime Complexity: O(N) # Best Case Runtime Complexity: O(N) for truck in self._active_trucks: # move truck for one second self._total_miles += truck.move_truck() # if truck distance is greater or equal to distance to next location if truck.distance_traveled >= truck.next_location[1]: # deliver packages for current location # Worst Case Runtime Complexity: O(N) # Best Case Runtime Complexity: O(N) delivered_packages = [x for x in truck.get_package_list() if x.location == truck.next_location[0].data] for package in delivered_packages: truck.deliver_package(package) # set status of delivered package to delivered self._packages.search(package.package_id).status = "DELIVERED" # set time delivered for delivered package to current time self._packages.search(package.package_id).time_delivered = self._clock.time # Display information about current delivery print(f"{Clock.to_time_string(self._clock.time, self._start_time)} : Package {package.package_id} " f"delivered to {truck.next_location[0].data.name}, {truck.next_location[0].data}") # wait a short time so that delivery activity can be read more easily time.sleep(.2) # Get truck's next location truck.get_next_location(self._clock.time) # if truck's route is done, remove it from active trucks if truck.is_route_done(): self._active_trucks.remove(truck) # When delayed packages arrive send out second truck if self._clock.time >= self._delayed_flight_time and not self._delayed_packages_departed: self._active_trucks.append(self._trucks.pop()) self._delayed_packages_departed = True self._active_trucks[-1].start_route(self._clock.time) # If active trucks is less than 2 and delayed packages have left send out next truck if self._delayed_packages_departed and len(self._active_trucks) < 2 and not self._trucks.is_empty(): self._active_trucks.append(self._trucks.pop()) self._active_trucks[-1].start_route(self._clock.time) # If not more active trucks, end simulation if len(self._active_trucks) == 0: self.simulation_over = True self.print_summary() break