def schedule(self, parcels: List[Parcel], trucks: List[Truck], verbose: bool = False) -> List[Parcel]: rejects = [] parcels2 = PriorityQueue(self._func) for p in parcels: parcels2.add(p) while not parcels2.is_empty(): parcel = parcels2.remove() truckos = _greedy_capable_trucks(parcel, trucks) if self._t_priority == 'non-increasing': ordereds = PriorityQueue(_more_truck_space) else: ordereds = PriorityQueue(_less_truck_space) for i in truckos: ordereds.add(trucks[i]) if ordereds.is_empty(): rejects.append(parcel) continue picked = ordereds.remove() for t in trucks: if picked.id == t.id: t.pack(parcel) return rejects
def test_priority_queue_add_remove_doctest() -> None: """Test the doctest provided for PriorityQueue.add and PriorityQueue.remove""" pq = PriorityQueue(_shorter) pq.add('fred') pq.add('arju') pq.add('monalisa') pq.add('hat') assert pq.remove() == 'hat' assert pq.remove() == 'fred' assert pq.remove() == 'arju' assert pq.remove() == 'monalisa'
def schedule(self, parcels: List[Parcel], trucks: List[Truck], verbose: bool = False) -> List[Parcel]: """Returns a list of parcels that were not allocated to a truck due to lack of volume available""" # defining left over parcels and priority list for parcels leftovers = [] parcel_lst = self._parcel_lst_generator() # adding parcels to priority list for parcel in parcels: parcel_lst.add(parcel) # assigning parcels to trucks while not parcel_lst.is_empty(): # removing parcels from the remaining parcels to be # allocated parcel = parcel_lst.remove() # defining truck priority list with two separate lists indicating # routes that match-up vs not if self._truck_order == "non-decreasing": truck_lst = PriorityQueue(_truck_vol_least) truck_lst_high = PriorityQueue(_truck_vol_least) else: # self._truck_order == "non-increasing": truck_lst = PriorityQueue(_truck_vol_most) truck_lst_high = PriorityQueue(_truck_vol_most) # making available truck lists for current parcel for truck in trucks: # check if parcel will fit current_vol = truck.unused_space() valid = current_vol >= parcel.volume # if parcel fits and the truck's last current stop is the # parcel's destination prioritize this truck over any others if truck.route[-1] == parcel.destination and valid: truck_lst_high.add(truck) # if parcel fits add this truck to list elif valid: truck_lst.add(truck) # if the high_prio list not is empty (i.e. there is a truck # with the last route as its destination) add the parcel # to the most prioritized truck if not truck_lst_high.is_empty(): truck_lst_high.remove().pack(parcel) # if not same route but eligibble trucks add it to # the most prioritzed truck elif not truck_lst.is_empty(): truck_lst.remove().pack(parcel) # otherwise append to leftover parcels else: leftovers.append(parcel) return leftovers
def _update_active_rides_fast(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - see Task 5 of the assignment handout """ event = PriorityQueue.remove()
class Simulation: """A simulation. This is the class which is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the two methods according to their docstrings. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for auto-testing purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _dispatcher: Dispatcher # The dispatcher associated with the simulation. def __init__(self): """Initialize a Simulation. @type self: Simulation @rtype: None """ self._events = PriorityQueue() self._dispatcher = Dispatcher() self._monitor = Monitor() def run(self, initial_events): """Run the simulation on the list of events in <initial_events>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: Simulation @type initial_events: list[Event] An initial list of events. @rtype: dict[str, object] """ # Add all initial events to the event queue. for item in initial_events: self._events.add(item) # Until there are no more events, remove an event # from the event queue and do it. Add any returned # events to the event queue. while not (self._events.is_empty()): temp_event = self._events.remove() event_list = temp_event.do(self._dispatcher, self._monitor) for event in event_list: self._events.add(event) return self._monitor.report()
class GroceryStoreSimulation: """A Grocery Store simulation. This is the class which is responsible for setting up and running a simulation. """ def __init__(self, store_file): """Initialize a GroceryStoreSimulation from a file. @type store_file: str A file containing the configuration of the grocery store. @rtype: None """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, event_file): """Run the simulation on the events stored in <event_file>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: GroceryStoreSimulation @type event_file: str A filename referring to a raw list of events. Precondition: the event file is a valid list of events. @rtype: dict[str, object] """ # Initialize statistics stats = { 'num_customers': 0, 'total_time': 0, 'max_wait': -1 } initial_events = create_event_list(event_file) for item in initial_events: self._events.add(item) while self._events.is_empty() == False: processEvent= self._events.remove() #change the stats acrroding to the eventbeing popped out from list if(processEvent.status=="Finish"): waitTime=processEvent.getWaitTime() if waitTime > stats['max_wait']: stats['max_wait'] = waitTime if(processEvent.status=="Begin"): stats['num_customers']+=1 if(self._events.is_empty() and processEvent.status=="Finish"): stats['total_time']=processEvent.timestamp newEvents=processEvent.do(self._store) if(newEvents!=None): for event in newEvents: self._events.add(event) return stats
def schedule(self, parcels, trucks, verbose=False): """Mutate the trucks so that they store information about which parcels they will deliver and what route they will take. The parcels will not be mutated. Return the parcels that do not get scheduled onto any truck, due to lack of capacity. @type self: Scheduler @type parcels: list[Parcel] The parcels to be scheduled for delivery. @type trucks: list[Truck] The trucks that can carry parcels for delivery. @type verbose: bool Whether or not to run in verbose mode. @rtype: list[Parcel] The parcels that did not get scheduled onto any truck, due to lack of capacity. """ parcel_queue = PriorityQueue(self._fun1) for each in parcels: parcel_queue.add(each) while not parcel_queue.is_empty(): target_parcel = parcel_queue.remove() parcel_data = target_parcel.get_parcel() truck_1st = [] truck_2nd = [] for each in trucks: if each.get_volume() >= parcel_data[-1]: truck_1st.append(each) for i in truck_1st: if parcel_data[-2] in i.get_destination(): truck_2nd.append(i) if not len(truck_2nd): truck_2nd = truck_1st truck_queue = PriorityQueue(self._fun2) for j in truck_2nd: truck_queue.add(j) if not truck_queue.is_empty(): truck_choice = truck_queue.remove() indx = trucks.index(truck_choice) trucks.remove(truck_choice) truck_choice.load_parcel(parcel_data[0], parcel_data[-2], parcel_data[-1]) parcels.remove(target_parcel) trucks.insert(indx, truck_choice) return parcels
class GroceryStoreSimulation: """A Grocery Store simulation. This is the class which is responsible for setting up and running a simulation. The interface is given to you: your main task is to implement the two methods according to their docstrings. Of course, you may add whatever private attributes you want to this class. Because you should not change the interface in any way, you may not add any public attributes. === Private Attributes === _events: A sequence of events arranged in priority determined by the event sorting order. _store: The store being simulated. """ _events: PriorityQueue _store: GroceryStore def __init__(self, store_file: TextIO) -> None: """Initialize a GroceryStoreSimulation using configuration <store_file>. """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, file: TextIO) -> Dict[str, Any]: """Run the simulation on the events stored in <initial_events>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. """ # Initialize statistics stats = { 'num_customers': 0, 'total_time': 0, 'max_wait': -1 } max_waits = dict() initial_event_list = create_event_list(file) for event in initial_event_list: self._events.add(event) if isinstance(event, CustomerArrival): stats['num_customers'] += 1 max_waits[event.customer] = event.timestamp while not self._events.is_empty(): event = self._events.remove() if isinstance(event, CheckoutCompleted): max_waits[event.customer] = event.timestamp - \ max_waits[event.customer] spawns = event.do(self._store) for spawn in spawns: self._events.add(spawn) stats['total_time'] = event.timestamp stats['max_wait'] = max_waits[max(max_waits, key=max_waits.get)] return stats
class Simulation: """A simulation. This is the class that is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the run method below according to its docstring. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for auto-testing purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === _events: PriorityQueue # A sequence of events arranged in priority determined by the event # sorting order. _dispatcher: Dispatcher # The dispatcher associated with the simulation. _monitor: Monitor # The monitor associated with the simulation. def __init__(self) -> None: """Initialize a Simulation. """ self._events = PriorityQueue() self._dispatcher = Dispatcher() self._monitor = Monitor() def run(self, initial_events: List[Event]) -> Dict[str, float]: """Run the simulation on the list of events in <initial_events>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. initial_events: An initial list of events. """ # Add all initial events to the event queue. for event in initial_events: self._events.add(event) # Until there are no more events, remove an event # from the event queue and do it. Add any returned # events to the event queue. while not self._events.is_empty(): new = self._events.remove() future = new.do(self._dispatcher, self._monitor) for i in future: self._events.add(i) return self._monitor.report()
class Simulation: """A simulation. This is the class which is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the run method below according to its docstring. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for auto-testing purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _dispatcher: Dispatcher # The dispatcher associated with the simulation. def __init__(self): """Initialize a Simulation. @type self: Simulation @rtype: None """ self._events = PriorityQueue() self._dispatcher = Dispatcher() self._monitor = Monitor() def run(self, initial_events): """Run the simulation on the list of events in <initial_events>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: Simulation @type initial_events: list[Event] An initial list of events. @rtype: dict[str, object] """ # TODO #Adding the events to the queue, UNSURE ABOUT THIS ???!?? for event in initial_events: self._events.add(event) while not self._events.is_empty(): currentEvent = self._events.remove() additionalEvents = currentEvent.do(self._dispatcher,self._monitor) if additionalEvents != []: for event in additionalEvents: self._events.add(event) # Add all initial events to the event queue. # Until there are no more events, remove an event # from the event queue and do it. Add any returned # events to the event queue. return self._monitor.report()
def test_priority_queue_non_increasing_destination() -> None: """Test the doctest provided for PriorityQueue.add and PriorityQueue.remove""" p1 = Parcel(1, 25, 'York', 'a') p2 = Parcel(2, 10, 'York', 'aa') p3 = Parcel(3, 8, 'York', 'aaa') p4 = Parcel(4, 20, 'York', 'a') p5 = Parcel(5, 15, 'York', 'aaaa') p6 = Parcel(6, 15, 'York', 'aa') p7 = Parcel(7, 20, 'York', 'aaaaaa') parcels = [p1, p2, p3, p4, p5, p6, p7] pq = PriorityQueue(_smaller_city) for parcel in parcels: pq.add(parcel) assert pq.remove().id == 7 assert pq.remove().id == 5 assert pq.remove().id == 3 assert pq.remove().id == 2 assert pq.remove().id == 6 assert pq.remove().id == 1 assert pq.remove().id == 4
def test_priority_queue_non_decreasing_volume() -> None: """Test the doctest provided for PriorityQueue.add and PriorityQueue.remove""" p1 = Parcel(1, 25, 'York', 'Toronto') p2 = Parcel(2, 10, 'York', 'London') p3 = Parcel(3, 8, 'York', 'London') p4 = Parcel(4, 20, 'York', 'Toronto') p5 = Parcel(5, 15, 'York', 'Toronto') p6 = Parcel(6, 15, 'York', 'Hamilton') p7 = Parcel(7, 20, 'York', 'London') parcels = [p1, p2, p3, p4, p5, p6, p7] pq = PriorityQueue(_smaller_volume) for parcel in parcels: pq.add(parcel) assert pq.remove().volume == 8 assert pq.remove().volume == 10 assert pq.remove().volume == 15 assert pq.remove().volume == 15 assert pq.remove().volume == 20 assert pq.remove().volume == 20 assert pq.remove().volume == 25
def schedule(self, parcels, trucks, verbose=False): """ Schedule parcels greedily <trucks> are mutated. Do not reuse <trucks> for another scheduler/trial. === Local Variables === type queue: PriorityQueue Queue of parcels. type unused_parcel: [Parcel] If the parcel does not fit any truck, the parcel is appended to <unused_parcel> type one_parcel: Parcel An element of <parcels> or <queue> type trucks_with_space: [Truck] List of trucks with space """ queue = PriorityQueue(self._greater_priority) unused_parcel = [] for one_parcel in parcels: queue.add(one_parcel) while queue.is_empty() is False: one_parcel = queue.remove() trucks_with_space = [] for one_truck in trucks: if one_truck.get_unused_space() >= one_parcel.get_volume(): trucks_with_space.append(one_truck) trucks_with_destination = [] for one_truck in trucks_with_space: if one_truck.city_in_route(one_parcel.get_destination()): trucks_with_destination.append(one_truck) # if there is at least 1 suitable truck with the destination, # trucks without the destination will not be considered. if len(trucks_with_destination) > 0: trucks_with_space = trucks_with_destination if len(trucks_with_space) > 0: self._choose_load_truck(trucks_with_space, one_parcel, verbose) else: if verbose: print("Parcel #{} was not loaded.".format( one_parcel.get_id())) unused_parcel.append(one_parcel) return unused_parcel
def schedule(self, parcels: List[Parcel], trucks: List[Truck], verbose: bool = False) -> List[Parcel]: rejects = [] parcels1 = PriorityQueue(_smaller_volume) parcels2 = PriorityQueue(_larger_volume) parcels3 = PriorityQueue(_smaller_city) parcels4 = PriorityQueue(_larger_city) for p in parcels: parcels1.add(p) parcels2.add(p) parcels3.add(p) parcels4.add(p) print("-----------------------") while not parcels1.is_empty(): p = parcels1.remove() print(p.id) print("-----------------------") while not parcels2.is_empty(): p = parcels2.remove() print(p.id) print("-----------------------") while not parcels3.is_empty(): p = parcels3.remove() print(p.id) print("-----------------------") while not parcels4.is_empty(): p = parcels4.remove() print(p.id) print("-----------------------") while not parcels2.is_empty(): parcel = parcels2.remove() truckos = _greedy_capable_trucks(parcel, trucks) if self._t_priority == 'non-increasing': ordereds = PriorityQueue(_more_truck_space) else: ordereds = PriorityQueue(_less_truck_space) for i in truckos: ordereds.add(trucks[i]) if ordereds.is_empty(): rejects.append(parcel) continue picked = ordereds.remove() for t in trucks: if picked.id == t.id: t.pack(parcel) pr return rejects
def test_priority_truck_non_decreasing_destination() -> None: """Test the doctest provided for PriorityQueue.add and PriorityQueue.remove""" t1 = Truck(1, 25, 'York') t2 = Truck(2, 10, 'York') t3 = Truck(3, 8, 'York') t4 = Truck(4, 20, 'York') t5 = Truck(5, 15, 'York') t6 = Truck(6, 15, 'York') t7 = Truck(7, 20, 'York') p1 = Parcel(1, 15, 'York', 'Toronto') trucks = [t1, t2, t3, t4, t5, t6, t7] et = _capable_trucks(p1, trucks) assert len(et) == 5 pq = PriorityQueue(_less_truck_space) for t in et: pq.add(trucks[t]) truck = pq.remove() assert truck.id == 5
class TestPriorityQueue(unittest.TestCase): def setUp(self): self.queue = PriorityQueue(Helper.shorter) self.queue.add('fred') self.queue.add('arju') self.queue.add('monalisa') self.queue.add('hat') def test_pq_add(self): actual = self.queue._queue expected = ['monalisa', 'arju', 'fred', 'hat'] msg = "We expected {}, but found {}".format(str(expected), str(actual)) self.assertEqual(actual, expected, msg) def test_pq_remove(self): pq = self.queue._queue actual = self.queue.remove() expected = 'hat' msg = "Applied remove() to {}, expected {}, actual {}".format(pq, expected, actual) self.assertEqual(actual, expected, msg)
class GroceryStoreSimulation: """A Grocery Store simulation. """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _store: GroceryStore # The grocery store associated with the simulation. def __init__(self, store_file): """Initialize a GroceryStoreSimulation from a file. @type store_file: str A file containing the configuration of the grocery store. @rtype: None """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, event_file): """Run the simulation on the events stored in <event_file>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: GroceryStoreSimulation @type event_file: str A filename referring to a raw list of events. Precondition: the event file is a valid list of events. @rtype: dict[str, object] """ # Initialize statistics stats = {'num_customers': 0, 'total_time': 0, 'max_wait': -1} initial_events = create_event_list(event_file) # The initial events tells us how many customers went through the # simulation, since new Customers only join a line through a file. for event in initial_events: if type(event) == AddCustomerEvent: stats['num_customers'] += 1 for item in initial_events: self._events.add(item) while not self._events.is_empty(): current_event = self._events.remove() # Adds spawned events from doing the current event to the # simulation's PriorityQueue. new_events = current_event.do(self._store) for item in new_events: self._events.add(item) if type(current_event) == CheckOutCompleted: customer_time = current_event.wait_time if customer_time > stats['max_wait']: stats['max_wait'] = customer_time # If current event is the final event, then the time it ends is the # amount of time the simulation took. if self._events.is_empty(): stats['total_time'] = current_event.timestamp return stats
class GroceryStoreSimulation: """A Grocery Store simulation. This is the class which is responsible for setting up and running a simulation. The interface is given to you: your main task is to implement the two methods according to their docstrings. Of course, you may add whatever private attributes you want to this class. Because you should not change the interface in any way, you may not add any public attributes. === Private Attributes === _events: A sequence of events arranged in priority determined by the event sorting order. _store: The store being simulated. """ _events: PriorityQueue _store: GroceryStore def __init__(self, store_file: TextIO) -> None: """Initialize a GroceryStoreSimulation using configuration <store_file>. """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, file: TextIO) -> Dict[str, Any]: """Run the simulation on the events stored in <initial_events>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. """ # Initialize statistics stats = { 'num_customers': 0, 'total_time': 0, 'max_wait': -1 } # TODO: Calculate and return the correct statistics. file_list = create_event_list(file) for i in file_list: self._events.add(i) dict_name = {} max_wait = 0 while not self._events.is_empty(): i = self._events.remove() if isinstance(i, CustomerArrival): if i.customer.name not in dict_name: dict_name[i.customer.name] = i.timestamp stats['num_customers'] += 1 if isinstance(i, CheckoutCompleted): dict_name[i.customer.name] \ = i.timestamp - dict_name[i.customer.name] for event in i.do(self._store): self._events.add(event) for j in dict_name: if dict_name[j] > max_wait: max_wait = dict_name[j] time_last = i.timestamp stats['total_time'] = time_last stats["max_wait"] = max_wait return stats
class Simulation: """Runs the core of the simulation through time. === Attributes === all_rides: A list of all the rides in this simulation. Note that not all rides might be used, depending on the timeframe when the simulation is run. all_stations: A dictionary containing all the stations in this simulation. visualizer: A helper class for visualizing the simulation. active_rides: A list to keep track of the rides that are in progress at the current time in the simulation. queue: A queue to keep track of of when rides become active or inactive. """ all_stations: Dict[str, Station] all_rides: List[Ride] visualizer: Visualizer active_rides: List[Ride] queue: PriorityQueue def __init__(self, station_file: str, ride_file: str) -> None: """Initialize this simulation with the given configuration settings. """ self.visualizer = Visualizer() self.all_stations = create_stations(station_file) self.all_rides = create_rides(ride_file, self.all_stations) self.active_rides = [] self.queue = PriorityQueue() def run(self, start: datetime, end: datetime) -> None: """Run the simulation from <start> to <end>. """ step = timedelta(minutes=1) # Each iteration spans one minute of time # Add the rides into the queue. for r in self.all_rides: if r.start_time <= end and r.end_time >= start: ride_start = RideStartEvent(self, r.start_time, r) self.queue.add(ride_start) # Main run simulation loop. current_time = start while current_time <= end: # Update the rides. self._update_active_rides_fast(current_time) # Draw the map, the rides, and the stations. everything_list = \ list(self.all_stations.values()) + self.active_rides self.visualizer.render_drawables(everything_list, current_time) # Add to the time spent with low number of bikes and/or low number # of vacant spot <= 5. for s in self.all_stations: if self.all_stations[s].check_num_bikes() \ and current_time < end: self.all_stations[s].time_low_bikes += step.total_seconds() if self.all_stations[s].check_vacancy() \ and current_time < end: self.all_stations[s].time_low_vacant += step.total_seconds( ) current_time += step # Leave this code at the very bottom of this method. # It will keep the visualization window open until you close # it by pressing the 'X'. while True: if self.visualizer.handle_window_events(): return # Stop the simulation def _update_active_rides(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - Loop through `self.all_rides` and compare each Ride's start and end times with <time>. If <time> is between the ride's start and end times (inclusive), then add the ride to self.active_rides if it isn't already in that list. Otherwise, remove the ride from self.active_rides if it is in that list. - This means that if a ride started before the simulation's time period but ends during or after the simulation's time period, it should still be added to self.active_rides. """ for r in self.all_rides: if r.start_time <= time <= r.end_time: if r not in self.active_rides and r.start.num_bikes > 0: r.add_leave(time) self.active_rides.append(r) elif r.end_time <= time: if r in self.active_rides: r.add_arrive() self.active_rides.remove(r) def calculate_statistics(self) -> Dict[str, Tuple[str, float]]: """Return a dictionary containing statistics for this simulation. The returned dictionary has exactly four keys, corresponding to the four statistics tracked for each station: - 'max_start' - 'max_end' - 'max_time_low_availability' - 'max_time_low_unoccupied' The corresponding value of each key is a tuple of two elements, where the first element is the name (NOT id) of the station that has the maximum value of the quantity specified by that key, and the second element is the value of that quantity. For example, the value corresponding to key 'max_start' should be the name of the station with the most number of rides started at that station, and the number of rides that started at that station. """ # Create empty dictionaries to store the neccessary values from the # stations. d_start = {} d_end = {} d_low_availability = {} d_low_unoccupied = {} # Use stations'name as the dictionaries' key. # The value of each dictionary will be the amount of bike leave, # the amount of bike arrive, the amount of time spent with low number of # bikes and the amount of unoccupied spot of each stations respectively. for s in self.all_stations: current_name = self.all_stations[s].name d_start[current_name] = self.all_stations[s].leave d_end[current_name] = self.all_stations[s].arrive d_low_availability[current_name] = \ self.all_stations[s].time_low_bikes d_low_unoccupied[current_name] = \ self.all_stations[s].time_low_vacant # Find the maximum values, store them into these varibles respectively: # - 'max_start' # - 'max_end' # - 'max_time_low_availability' # - 'max_time_low_unoccupied' # and return them in form of a Dict[str, Tuple[str, float]]. max_start = find_maximum(d_start) max_end = find_maximum(d_end) max_time_low_availability = find_maximum(d_low_availability) max_time_low_unoccupied = find_maximum(d_low_unoccupied) return { 'max_start': max_start, 'max_end': max_end, 'max_time_low_availability': max_time_low_availability, 'max_time_low_unoccupied': max_time_low_unoccupied } def _update_active_rides_fast(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - see Task 5 of the assignment handout """ # Loop through the queue while not self.queue.is_empty(): event = self.queue.remove() if event.time > time: self.queue.add(event) break else: event_num_bikes = event.ride.start.num_bikes if isinstance(event, RideStartEvent) and event_num_bikes > 0: event.ride.add_leave(time) end_event = event.process() self.queue.add(end_event[0]) if isinstance(event, RideEndEvent): event.process()
def find_path(self, start_node, target_node): """ Implement the A-star path search algorithm If you will add a new node to the path, don't forget to set the parent. You can find an example in the docstring of Node class Please note the shortest path between two nodes may not be unique. However all of them have same length! @type self: Grid @type start_node: Node The starting node of the path @type target_node: Node The target node of the path @rtype: None >>> g = Grid("",["B.....", "+++++.", ".+++.+", "+.++..", "..+...", \ "..+..T"]) >>> g.find_path(g.boat, g.treasure) """ def less_than(a, b): """Return if a is less than b. >>> less_than(1, 2) True """ return a < b opened = PriorityQueue(less_than) closed = [] if opened.is_empty(): start_node.set_gcost(0) start_node.set_hcost(start_node.distance(target_node)) start_node.set_parent(None) opened.add(start_node) while not opened.is_empty(): current = opened.remove() closed.append(current) if current == target_node: break neighbors = self._get_neighbors(current) for neighbor in range(len(neighbors)): # Check if the neighbor you are viewing is in the closed list # If it is go to the next neighbor (go back to for loop above) # Otherwise, keep going if neighbors[neighbor] not in closed: # If the hcost from the neighbor to the target is # less than the distance from the current to target # or the neighbor is not in the opened list if neighbors[neighbor].distance(target_node) < \ current.distance(target_node) or \ neighbors[neighbor] not in opened: # Set the gcost if current.parent is not None: neighbors[neighbor].set_gcost( neighbors[neighbor].distance(current) + current.parent.gcost) else: neighbors[neighbor].set_gcost( neighbors[neighbor].distance(current)) # Set the hcost neighbors[neighbor].set_hcost( neighbors[neighbor].distance(target_node)) # Set the parent neighbors[neighbor].set_parent(current) if neighbors[neighbor] not in opened: opened.add(neighbors[neighbor]) # Use the nodes in the closed list to find the nodes in the map and # set their parents to access them LATER closed = closed[::-1] for node in range(len(closed)): for i in range(len(self.map)): if closed[node] in self.map[i]: node_index = self.map[i].index(closed[node]) self.map[i][node_index].set_parent(closed[node].parent)
class Simulation: """Runs the core of the simulation through time. === Attributes === all_rides: A list of all the rides in this simulation. Note that not all rides might be used, depending on the timeframe when the simulation is run. all_stations: A dictionary containing all the stations in this simulation. visualizer: A helper class for visualizing the simulation. active_rides A list that contains the active rides that progess currently in the time of the simulation """ all_stations: Dict[str, Station] all_rides: List[Ride] visualizer: Visualizer active_rides: List[Ride] event_priority: PriorityQueue['Event'] def __init__(self, station_file: str, ride_file: str) -> None: """Initialize this simulation with the given configuration settings. """ self.visualizer = Visualizer() self.all_stations = create_stations(station_file) self.all_rides = create_rides(ride_file, self.all_stations) self.active_rides = [] self.event_priority = PriorityQueue() def run(self, start: datetime, end: datetime) -> None: """Run the simulation from <start> to <end>. """ for ride in self.all_rides: if ride.start_time >= start: self.event_priority.add( RideStartEvent(self, ride.start_time, ride)) step = timedelta(minutes=1) # Each iteration spans one minute of time while start <= end: #self._update_active_rides_fast(start) self._update_active_rides(start) if start < end: self.update_availability_and_unoccupied() self.visualizer.render_drawables( list(self.all_stations.values()) + self.active_rides, start) start += step # if start == end: # self.active_rides = [] # Leave this code at the very bottom of this method. # It will keep the visualization window open until you close # it by pressing the 'X'. while True: if self.visualizer.handle_window_events(): return # Stop the simulation def update_availability_and_unoccupied(self): """ updates the stations availability and unoccupied method per minute """ for station in self.all_stations.values(): station.low_availabilty() station.low_unoccupied() def update_giving_station(self, ride: Ride, time: datetime) -> None: """Decrease the num_bikes of a station if the ride is being added to the active rides list """ if ride.start_time == time: if ride.start.num_bikes > 0: ride.start.num_bikes -= 1 def update_taking_station(self, ride: Ride, time: datetime) -> None: """Increase the num_bikes of a station if the ride is being added to the active rides list only if we haven't exceeded the station capacity yet.""" if ride.end_time == time: if ride.end.capacity > ride.end.num_bikes: ride.end.num_bikes += 1 def _update_active_rides_fast(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - see Task 5 of the assignment handout """ while not self.event_priority.is_empty(): current_event = self.event_priority.remove() if current_event.ride.start_time >= time: self.event_priority.add(current_event) return else: self.event_priority.add(current_event.process) def _update_active_rides(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - Loop through `self.all_rides` and compare each Ride's start and end times with <time>. If <time> is between the ride's start and end times (inclusive), then add the ride to self.active_rides if it isn't already in that list. Otherwise, remove the ride from self.active_rides if it is in that list. - This means that if a ride started before the simulation's time period but ends during or after the simulation's time period, it should still be added to self.active_rides. """ for current_ride in self.all_rides: ride_station_start = current_ride.start ride_station_end = current_ride.end s = current_ride.start_time e = current_ride.end_time if time == s and time < e: if ride_station_start.num_bikes > 0 and ride_station_start. \ unocc_spots != ride_station_start.capacity: ride_station_start.num_bikes -= 1 ride_station_start.stats['starting rides'] += 1 ride_station_start.unocc_spots += 1 self.active_rides.append(current_ride) if time == e and current_ride in self.active_rides: if ride_station_end.num_bikes < ride_station_end.capacity and \ ride_station_end.unocc_spots > 0: ride_station_end.stats['ending rides'] += 1 ride_station_end.num_bikes += 1 ride_station_end.unocc_spots -= 1 self.active_rides.remove(current_ride) else: self.active_rides.remove(current_ride) def calculate_statistics(self) -> Dict[str, Tuple[str, float]]: """Return a dictionary containing statistics for this simulation. The returned dictionary has exactly four keys, corresponding to the four statistics tracked for each station: - 'max_start' - 'max_end' - 'max_time_low_availability' - 'max_time_low_unoccupied' The corresponding value of each key is a tuple of two elements, where the first element is the name (NOT id) of the station that has the maximum value of the quantity specified by that key, and the second element is the value of that quantity. For example, the value corresponding to key 'max_start' should be the name of the station with the most number of rides started at that station, and the number of rides that started at that station. """ max_start = -1 max_start_station_name = None max_end = -1 max_end_station_name = None max_avail = -1 max_avail_station_name = None max_unocc = -1 max_unocc_station_name = None for station in self.all_stations.values(): if station.stats['starting rides'] >= max_start: if station.stats['starting rides'] > max_start: max_start = station.stats['starting rides'] max_start_station_name = station.name elif station.stats['starting rides'] == max_start: if station.name < max_start_station_name: max_start_station_name = station.name if station.stats['ending rides'] >= max_end: if station.stats['ending rides'] > max_end: max_end = station.stats['ending rides'] max_end_station_name = station.name elif station.stats['ending rides'] == max_start: if station.name < max_end_station_name: max_end_station_name = station.name if station.stats['low availability'] >= max_avail: if station.stats['low availability'] > max_avail: max_avail_station_name = station.name max_avail = station.stats['low availability'] elif station.stats['low availability'] == max_avail: if station.name < max_avail_station_name: max_avail_station_name = station.name if station.stats['low unoccupied'] >= max_unocc: if station.stats['low unoccupied'] > max_unocc: max_unocc_station_name = station.name max_unocc = station.stats['low unoccupied'] elif station.stats['low unoccupied'] == max_unocc: if station.name < max_unocc_station_name: max_unocc_station_name = station.name return { 'max_start': (max_start_station_name, max_start), 'max_end': (max_end_station_name, max_end), 'max_time_low_availability': (max_avail_station_name, max_avail), 'max_time_low_unoccupied': (max_unocc_station_name, max_unocc) }
class GroceryStoreSimulation: """A Grocery Store simulation. This is the class which is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the two methods according to their docstrings. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for autotesting purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _store: GroceryStore # The grocery store associated with the simulation. def __init__(self, store_file): """Initialize a GroceryStoreSimulation from a file. @type store_file: str A file containing the configuration of the grocery store. @rtype: None """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, event_file): """Run the simulation on the events stored in <event_file>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: GroceryStoreSimulation @type event_file: str A filename referring to a raw list of events. Precondition: the event file is a valid list of events. @rtype: dict[str, object] """ # Initialize statistics stats = { 'num_customers': 0, 'total_time': 0, 'max_wait': -1 } initial_events = create_event_list(event_file) # TODO: Process all of the events, collecting statistics along the way. #add events to self._events for event in initial_events: self._events.add(event) while not self._events.is_empty(): event = self._events.remove() if isinstance(event,EventJoin): new_events = EventJoin.do() elif isinstance(event,EventClose): new_events = EventClose.do() elif isinstance(event,EventBegin): new_events = EventBegin.do() elif isinstance(event,EventFinish): new_events = EventFinish.do() for item in new_events: self._events.add(new_events) return stats
class Simulation: """Runs the core of the simulation through time. === Attributes === all_rides: A list of all the rides in this simulation. Note that not all rides might be used, depending on the timeframe when the simulation is run. all_stations: A dictionary containing all the stations in this simulation. visualizer: A helper class for visualizing the simulation. active_rides: A list of the active rides in the simulation event_queue: A priority queue of the events to be processed in the simulation """ all_stations: Dict[str, Station] all_rides: List[Ride] visualizer: Visualizer active_rides: List[Ride] event_queue: PriorityQueue def __init__(self, station_file: str, ride_file: str) -> None: """Initialize this simulation with the given configuration settings. """ self.all_stations = create_stations(station_file) self.all_rides = create_rides(ride_file, self.all_stations) self.active_rides = [] self.visualizer = Visualizer() self.event_queue = PriorityQueue() def run(self, start: datetime, end: datetime) -> None: """Run the simulation from <start> to <end>. """ current_time = start step = timedelta(minutes=1) # Each iteration spans one minute of time station_list = list(self.all_stations.values()) for ride in self.all_rides: if (ride.end_time > start and ride.end_time < end) or \ (ride.start_time < end and ride.start_time > start): self.event_queue.add(RideStartEvent(self, ride, start, end)) while current_time != end: self._update_status(current_time) self.visualizer.render_drawables(station_list + \ self.active_rides, current_time) current_time += step # Leave this code at the very bottom of this method. # It will keep the visualization window open until you close # it by pressing the 'X'. while True: if self.visualizer.handle_window_events(): return # Stop the simulation def _update_active_rides(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - Loop through `self.all_rides` and compare each Ride's start and end times with <time>. If <time> is between the ride's start and end times (inclusive), then add the ride to self.active_rides if it isn't already in that list. Otherwise, remove the ride from self.active_rides if it is in that list. - This means that if a ride started before the simulation's time period but ends during or after the simulation's time period, it should still be added to self.active_rides. """ for ride in self.active_rides: if ride.end_time == time: ride.end.update_bikes(1) self.active_rides.remove(ride) for ride in self.all_rides: if ride.start_time == time and ride not in self.active_rides: if ride.start.update_bikes(-1): self.active_rides.append(ride) def _update_status(self, time: datetime): """Wrapper method for updating this simulation's rides and station """ self._update_active_rides_fast(time) for station in list(self.all_stations.values()): station.update_time() def calculate_statistics(self) -> Dict[str, Tuple[str, float]]: """Return a dictionary containing statistics for this simulation. The returned dictionary has exactly four keys, corresponding to the four statistics tracked for each station: - 'max_start' - 'max_end' - 'max_time_low_availability' - 'max_time_low_unoccupied' The corresponding value of each key is a tuple of two elements, where the first element is the name (NOT id) of the station that has the maximum value of the quantity specified by that key, and the second element is the value of that quantity. For example, the value corresponding to key 'max_start' should be the name of the station with the most number of rides started at that station, and the number of rides that started at that station. """ stats = [] for station in list(self.all_stations.values()): stats.append(station.get_stats()) # sort list by station name stats = sorted(stats, key=lambda station: station[4]) sorted_lists = [] # a list of lists sorted by: max_start, max_end, # max_time_low_availability, max_time_low_unoccupied sorted_lists.append(sorted(stats, key=lambda station: station[0])) sorted_lists.append(sorted(stats, key=lambda station: station[1])) sorted_lists.append(sorted(stats, key=lambda station: station[2])) sorted_lists.append(sorted(stats, key=lambda station: station[3])) index = 0 for sorted_list in sorted_lists: # for each of the four statistics, remove the ones with the largest # but also equal values,leaving the station with the "smallest" name while len(sorted_list) > 1: if sorted_list[-1][index] == sorted_list[-2][index]: sorted_list.pop(-1) else: break index += 1 max_start = sorted_lists[0][-1] max_end = sorted_lists[1][-1] max_time_low_availability = sorted_lists[2][-1] max_time_low_unoccupied = sorted_lists[3][-1] return { 'max_start': (max_start[4], max_start[0]), 'max_end': (max_end[4], max_end[1]), 'max_time_low_availability': (max_time_low_availability[4] \ , max_time_low_availability[2]), 'max_time_low_unoccupied': (max_time_low_unoccupied[4] \ , max_time_low_unoccupied[3]) } def _update_active_rides_fast(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - see Task 5 of the assignment handout """ done = False while not done and not self.event_queue.is_empty(): event = self.event_queue.remove() if event.time > time: self.event_queue.add(event) done = True else: events = event.process() for event in events: self.event_queue.add(event)
class GroceryStoreSimulation: """A Grocery Store simulation. This is the class which is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the two methods according to their docstrings. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for autotesting purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _store: GroceryStore # The grocery store associated with the simulation. def __init__(self, store_file): """Initialize a GroceryStoreSimulation from a file. @type store_file: str A file containing the configuration of the grocery store. @rtype: None """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, event_file): """Run the simulation on the events stored in <event_file>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: GroceryStoreSimulation @type event_file: str A filename referring to a raw list of events. Precondition: the event file is a valid list of events. @rtype: dict[str, object] """ # Initialize statistics stats = { 'num_customers': 0, 'total_time': 0, 'max_wait': -1 } initial_events = create_event_list(event_file) # TODO: Process all of the events, collecting statistics along the way. for event in initial_events: self._events.add(event) while not self._events.is_empty(): current_event = self._events.remove() new_events = current_event.do(self._store) stats['total_time'] = current_event.timestamp # collects the total time if new_events is None: pass elif len(new_events) > 0: for x in new_events: self._events.add(x) # find out how many Customers have checked out # through store's finished_customers dict stats['num_customers'] = len(self._store.finished_customers) # find out max_wait from store's finished_customers for customer in self._store.finished_customers: if self._store.finished_customers[customer].get_wait_time() > \ stats['max_wait']: stats['max_wait'] = self._store.finished_customers[ customer].get_wait_time() return stats
class Simulation: """Runs the core of the simulation through time. === Attributes === all_rides: A list of all the rides in this simulation. Note that not all rides might be used, depending on the timeframe when the simulation is run. all_stations: A dictionary containing all the stations in this simulation. visualizer: A helper class for visualizing the simulation. active rides: A list o all rides that are in progress at the current time in the simulation """ all_stations: Dict[str, Station] all_rides: List[Ride] visualizer: Visualizer active_rides: List[Ride] event_list: List['Event'] def __init__(self, station_file: str, ride_file: str) -> None: """Initialize this simulation with the given configuration settings. """ self.visualizer = Visualizer() self.all_stations = create_stations(station_file) self.all_rides = create_rides(ride_file, self.all_stations) self.active_rides = [] self.event_list = PriorityQueue() def run(self, start: datetime, end: datetime) -> None: """Run the simulation from <start> to <end>. """ step = timedelta(minutes=1) # Each iteration spans one minute of time for ride in self.all_rides: if ride.start_time > start or start <= ride.end_time <= end: start_event = RideStartEvent(self, ride.start_time) self.event_list.add(start_event) simulation_start = start while not start > end: self._update_active_rides_fast(start) if not start == simulation_start: self.low_avail_check() self.low_occ_check() drawables = self.active_rides + list(self.all_stations.values()) self.visualizer.render_drawables(drawables + self.active_rides, start) start += step # Leave this code at the very bottom of this method. # It will keep the visualization window open until you close # it by pressing the 'X'. while True: if self.visualizer.handle_window_events(): return # Stop the simulation def low_avail_check(self): """Check whether station's current state is "low available". If it is update station's low availability time """ for id_ in self.all_stations: station = self.all_stations[id_] if station.is_low_availability(): station.low_avail += 60.0 def low_occ_check(self): """Check whether station's current state is "low unoccupied." If it is update station's low availability time """ for id_ in self.all_stations: station = self.all_stations[id_] if station.is_low_unoccupied(): station.low_occ += 60.0 def _update_active_rides(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - Loop through `self.all_rides` and compare each Ride's start and end times with <time>. If <time> is between the ride's start and end times (inclusive), then add the ride to self.active_rides if it isn't already in that list. Otherwise, remove the ride from self.active_rides if it is in that list. - This means that if a ride started before the simulation's time period but ends during or after the simulation's time period, it should still be added to self.active_rides. """ for ride in self.all_rides: if ride.start_time <= time <= ride.end_time: if ride not in self.active_rides: if not ride.start.num_bikes == 0: self.active_rides.append(ride) ride.start.num_bikes -= 1 ride.start.rides_start += 1 else: self.all_rides.remove(ride) else: if ride in self.active_rides: if not ride.end.is_full(): ride.end.num_bikes += 1 ride.end.rides_end += 1 self.active_rides.remove(ride) def calculate_statistics(self) -> Dict[str, Tuple[str, float]]: """Return a dictionary containing statistics for this simulation. The returned dictionary has exactly four keys, corresponding to the four statistics tracked for each station: - 'max_start' - 'max_end' - 'max_time_low_availability' - 'max_time_low_unoccupied' The corresponding value of each key is a tuple of two elements, where the first element is the name (NOT id) of the station that has the maximum value of the quantity specified by that key, and the second element is the value of that quantity. For example, the value corresponding to key 'max_start' should be the name of the station with the most number of rides started at that station, and the number of rides that started at that station. """ return { 'max_start': (self.max_start()), 'max_end': (self.max_end()), 'max_time_low_availability': (self.lowest_avail()), 'max_time_low_unoccupied': (self.lowest_occ()) } def max_start(self): """Return the station and the amount with most rides that starts there """ max_ = -1 name = '' for id_ in self.all_stations: station = self.all_stations[id_] if station.rides_start > max_: max_ = station.rides_start name = station.name elif station.rides_start == max_: if station.name < name: name = station.name return name, max_ def max_end(self): """Return the station and the amount with most rides that starts there """ max_ = -1 name = '' for id_ in self.all_stations: station = self.all_stations[id_] if station.rides_end > max_: max_ = station.rides_end name = station.name elif station.rides_end == max_: if station.name < name: name = station.name return name, max_ def lowest_avail(self): """Return the station with longest time in the state of "low availability" and it's time """ avail = -1 name = '' for id_ in self.all_stations: station = self.all_stations[id_] if station.low_avail > avail: avail = station.low_avail name = station.name elif station.low_avail == avail: if station.name < name: name = station.name return name, avail def lowest_occ(self): """Return the station with longest time in the state of "low unoccupied" and it's time """ occ = -1 name = '' for id_ in self.all_stations: station = self.all_stations[id_] if station.low_occ > occ: occ = station.low_occ name = station.name elif station.low_occ == occ: if station.name < name: name = station.name return name, occ def _update_active_rides_fast(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - see Task 5 of the assignment handout """ if not self.event_list.is_empty(): event = self.event_list.remove() if event.time > time: self.event_list.add(event) else: while event is not None and event.time == time: new_events = event.process() for event in new_events: self.event_list.add(event) event = None if not self.event_list.is_empty(): event = self.event_list.remove() if event.time > time: self.event_list.add(event)
class Dispatcher: """A dispatcher fulfills requests from riders and drivers for a ride-sharing service. When a rider requests a driver, the dispatcher assigns a driver to the rider. If no driver is available, the rider is placed on a waiting list for the next available driver. A rider that has not yet been picked up by a driver may cancel their request. When a driver requests a rider, the dispatcher assigns a rider from the waiting list to the driver. If there is no rider on the waiting list the dispatcher does nothing. Once a driver requests a rider, the driver is registered with the dispatcher, and will be used to fulfill future rider requests. """ def __init__(self): """Initialize a Dispatcher. @type self: Dispatcher @rtype: None """ self.driver_list = [] self.rider_queue = PriorityQueue() def __str__(self): """Return a string representation. @type self: Dispatcher @rtype: str """ print("Drivers: ",end="") print(self.driver_list) def request_driver(self, rider): """Return a driver for the rider, or None if no driver is available. Add the rider to the waiting list if there is no available driver. @type self: Dispatcher @type rider: Rider @rtype: Driver | None """ if len(self.driver_list) == 0: self.rider_queue.add(rider) return None else: shortest_time = self.driver_list[0] for name in self.driver_list: if name.get_travel_time(rider.destination) < shortest_time.get_travel_time(rider.destination): if name.is_idle: shortest_time = name return shortest_time def request_rider(self, driver): """Return a rider for the driver, or None if no rider is available. If this is a new driver, register the driver for future rider requests. @type self: Dispatcher @type driver: Driver @rtype: Rider | None """ if not self.rider_queue.is_empty(): return self.rider_queue.remove() else: self.driver_list.append(driver) return None def cancel_ride(self, rider): """Cancel the ride for rider. @type self: Dispatcher @type rider: Rider @rtype: None """ if self.rider_queue.__contains__(rider): self.rider_queue.delete(rider) rider.status = CANCELLED
class Simulation: """Runs the core of the simulation through time. === Attributes === all_rides: A list of all the rides in this simulation. Note that not all rides might be used, depending on the timeframe when the simulation is run. all_stations: A dictionary containing all the stations in this simulation. visualizer: A helper class for visualizing the simulation. active_rides: Keep track of the list of all rides that are in progress at the current time in the simulation. events_queue: Keep track of the event of specific rides in a priority queue. """ all_stations: Dict[str, Station] all_rides: List[Ride] visualizer: Visualizer active_rides: List[Ride] events_queue: PriorityQueue['Event'] def __init__(self, station_file: str, ride_file: str) -> None: """Initialize this simulation with the given configuration settings. """ self.visualizer = Visualizer() self.all_stations = create_stations(station_file) self.all_rides = create_rides(ride_file, self.all_stations) self.active_rides = [] self.events_queue = PriorityQueue() def run(self, start: datetime, end: datetime) -> None: """Run the simulation from <start> to <end>. """ step = timedelta(minutes=1) # Each iteration spans one minute of time current_time = start self._update_events_queue(current_time, end) while current_time <= end: l1 = list(self.all_stations.values()) self._update_active_rides_fast(current_time) self._update_station(current_time) for stations in self.all_stations.values(): stations.update_timer(current_time) l2 = self.active_rides l1.extend(l2) self.visualizer.render_drawables(l1, current_time) current_time += step # Leave this code at the very bottom of this method. # It will keep the visualization window open until you close # it by pressing the 'X'. while True: if self.visualizer.handle_window_events(): return # Stop the simulation def _update_events_queue(self, time: datetime, end: datetime) -> None: """ update events_queue by comparing ride start_time and end_time to simulation time period. """ for ride in self.all_rides: if time <= ride.start_time <= end: ride_event = RideStartEvent(ride, ride.start_time, self) self.events_queue.add(ride_event) elif time <= ride.end_time <= end: self.events_queue.add(RideEndEvent(ride, ride.end_time, self)) # add this ride to active_rides self.active_rides.append(ride) def _update_station(self, time: datetime) -> None: """ update stations information at current time. """ for ride in self.active_rides: # if the ride start at current time during simulation if ride.start.num_bikes > 0 and ride.start_time == time: # update the start information at it's start station ride.start.update_start(time) if ride.end.capacity - ride.end.num_bikes > 0 \ and ride.end_time == time: ride.end.update_end(time) def _update_active_rides(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - Loop through `self.all_rides` and compare each Ride's start and end times with <time>. If <time> is between the ride's start and end times (inclusive), then add the ride to self.active_rides if it isn't already in that list. Otherwise, remove the ride from self.active_rides if it is in that list. - This means that if a ride started before the simulation's time period but ends during or after the simulation's time period, it should still be added to self.active_rides. """ # need to remove it from active ride # when it endstation doesn't have enough bike upon its end time for ride in self.all_rides: if ride.start_time <= time <= ride.end_time: if ride not in self.active_rides: self.active_rides.append(ride) else: if ride in self.active_rides: self.active_rides.remove(ride) def _update_active_rides_fast(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. - Remove an event from the priority queue. - If the event’s time is after the current time, put the event back into the priority queue and return. - Otherwise, - process the event - add any new events generated into the priority queue. - Repeat by removing the next item from the priority queue. """ while not self.events_queue.is_empty(): event = self.events_queue.remove() if event.time > time: self.events_queue.add(event) return None else: next_events = event.process() for next_event in next_events: self.events_queue.add(next_event) def calculate_statistics(self) -> Dict[str, Tuple[str, float]]: """Return a dictionary containing statistics for this simulation. The returned dictionary has exactly four keys, corresponding to the four statistics tracked for each station: - 'max_start' - 'max_end' - 'max_time_low_availability' - 'max_time_low_unoccupied' The corresponding value of each key is a tuple of two elements, where the first element is the name (NOT id) of the station that has the maximum value of the quantity specified by that key, and the second element is the value of that quantity. For example, the value corresponding to key 'max_start' should be the name of the station with the most number of rides started at that station, and the number of rides that started at that station. """ max_start = 0 potential_start = '' max_end = 0 potential_end = '' time_low_avail = 0 low_availability = '' time_low_unoccupied = 0 low_unoccupied = '' for stations in list(self.all_stations.values()): if stations.num_start > max_start: max_start = stations.num_start potential_start = stations.name elif stations.num_start == max_start: if potential_start == '': potential_start = stations.name elif stations.name < potential_start: potential_start = stations.name if stations.num_end > max_end: max_end = stations.num_end potential_end = stations.name elif stations.num_end == max_end: if potential_end == '': potential_end = stations.name elif stations.name < potential_end: potential_end = stations.name if stations.low_bikes_total > time_low_avail: low_availability = stations.name time_low_avail = stations.low_bikes_total elif stations.low_bikes_total == time_low_avail: if low_availability == '': low_availability = stations.name elif stations.name < low_availability: low_availability = stations.name if stations.low_spots_total == time_low_unoccupied: if low_unoccupied == '': low_unoccupied = stations.name elif stations.name < low_unoccupied: low_unoccupied = stations.name elif stations.low_spots_total > time_low_unoccupied: low_unoccupied = stations.name time_low_unoccupied = stations.low_spots_total return { 'max_start': (potential_start, max_start), 'max_end': (potential_end, max_end), 'max_time_low_availability': (low_availability, time_low_avail), 'max_time_low_unoccupied': (low_unoccupied, time_low_unoccupied) }
class GroceryStoreSimulation: """A Grocery Store simulation. This is the class which is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the two methods according to their docstrings. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for auto testing purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _store: GroceryStore # The grocery store associated with the simulation. def __init__(self, store_file): """Initialize a GroceryStoreSimulation from a file. @type store_file: str A file containing the configuration of the grocery store. @rtype: None """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, event_file): """Run the simulation on the events stored in <event_file>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: GroceryStoreSimulation @type event_file: str A filename referring to a raw list of events. Precondition: the event file is a valid list of events. @rtype: dict[str, int] """ # Initialize statistics stats = { 'num_customers': 0, 'total_time': 0, 'max_wait': -1 } initial_events = create_event_list(event_file) for i in range(len(initial_events)): self._events.add(initial_events[i]) if type(initial_events[i]) == JoinLine: stats['num_customers'] += 1 # THE FOLLOWING CODE MAY SHOW SOME WARNINGS. # (IF NOT, PLEASE IGNORE THIS COMMENT) # PROFESSOR LIU TOLD ME THAT THESE WARNINGS ARE PROBLEMS # WITH PyCharm ITSELF. SINCE WE ARE NOT ALLOWED TO CHANGE # THE INTERFACE, PROF SAID WE CAN JUST IGNORE THEM. THANK YOU. while not self._events.is_empty(): event = self._events.remove() spawned_events = event.do(self._store) stats['total_time'] = event.timestamp # Calculate max_wait if type(event) == FinishCheckOut: end_time = event.timestamp customer_name = event.name for u in range(len(initial_events)): if type(initial_events[u]) == JoinLine: temp = initial_events[u] if customer_name == temp.name: start_time = temp.timestamp waited_time = end_time - start_time if waited_time > stats['max_wait']: stats['max_wait'] = waited_time if spawned_events is not None: for j in range(len(spawned_events)): self._events.add(spawned_events[j]) return stats
class Simulation: """Runs the core of the simulation through time. === Attributes === all_rides: A list of all the rides in this simulation. Note that not all rides might be used, depending on the timeframe when the simulation is run. all_stations: A dictionary containing all the stations in this simulation. visualizer: A helper class for visualizing the simulation. active_rides: A list of all the rides in this simulation that are in progress. ride_pq: priorityquete of rides which are going to happen between simulation time. """ all_stations: Dict[str, Station] all_rides: List[Ride] visualizer: Visualizer active_rides: List[Ride] rides_pq: PriorityQueue def __init__(self, station_file: str, ride_file: str) -> None: """Initialize this simulation with the given configuration settings. """ self.all_stations = create_stations(station_file) self.all_rides = create_rides(ride_file, self.all_stations) self.active_rides = [] self.rides_pq = PriorityQueue() self.visualizer = Visualizer() def run(self, start: datetime, end: datetime) -> None: """Run the simulation from <start> to <end>. """ step = timedelta(minutes=1) # Each iteration spans one minute of time for ride in self.all_rides: if start <= ride.start_time <= end: self.rides_pq.add(RideStartEvent(self, ride.start_time, ride)) if (ride.start_time < start) and (ride.end_time >= start): ride.stats_decider = 0 self.rides_pq.add(RideStartEvent(self, ride.start_time, ride)) current = start # current = current time of the simulation for ride in self.all_rides: # to add the rides which has been started before the simulation's # time and hasn't finished yet if ride.start_time < start < ride.end_time: self.active_rides.append(ride) while current <= end: self._update_active_rides_fast(current) self.visualizer.render_drawables( list(self.all_stations.values()) + list(self.active_rides), current) if current != start: # because 8:00 to 8:00 doens't include any doration self.availibility_checker(int(step.total_seconds())) # to calculate the low_availibility and low_unoccupied of each # station current += step # Leave this code at the very bottom of this method. # It will keep the visualization window open until you close # it by pressing the 'X'. while True: if self.visualizer.handle_window_events(): return # Stop the simulation def availibility_checker(self, duration: int) -> None: """ It changes the amount of low_availibility and low occupied amount of each station by the amount of duration( which in this case duration is always 60 seconds)""" for station in self.all_stations.values(): if station.num_bikes <= 5: station.low_availability += duration if station.capacity - station.num_bikes <= 5: station.low_unoccupied += duration def _update_active_rides(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - Loop through `self.all_rides` and compare each Ride's start and end times with <time>. If <time> is between the ride's start and end times (inclusive), then add the ride to self.active_rides if it isn't already in that list. Otherwise, remove the ride from self.active_rides if it is in that list. - This means that if a ride started before the simulation's time period but ends during or after the simulation's time period, it should still be added to self.active_rides. - *** we use the attribiute'ride.allowance' to avoid adding the rides that couldn't happen at their start time due to the shortage of bikes in their station, at the other time between their start and end time. """ for ride in self.all_rides: if ride.start_time <= time <= ride.end_time and\ ride not in self.active_rides and\ ride.allowance == 1: if ride.start.num_bikes < 1: ride.allowance = 0 # therefor if the statoin that ride # start from it doesn't have enought bikes when the start # time arrives, the ride won't happen anymore( because of # the change of the ride.allowace) else: ride.start.num_bikes -= 1 ride.start.start_from += 1 ride.allowance = 0 self.active_rides.append(ride) if (not ride.start_time <= time <= ride.end_time) and\ (ride in self.active_rides): if ride.end.capacity >= ride.end.num_bikes + 1: ride.end.num_bikes += 1 ride.end.end_in += 1 # we're going to remove the bike at its endtime anyway but # if its station doesn't have enough spots it won't count for # the statistics. self.active_rides.remove(ride) def calculate_statistics(self) -> Dict[str, Tuple[str, float]]: """Return a dictionary containing statistics for this simulation. The returned dictionary has exactly four keys, corresponding to the four statistics tracked for each station: - 'max_start' - 'max_end' - 'max_time_low_availability' - 'max_time_low_unoccupied' The corresponding value of each key is a tuple of two elements, where the first element is the name (NOT id) of the station that has the maximum value of the quantity specified by that key, and the second element is the value of that quantity. For example, the value corresponding to key 'max_start' should be the name of the station with the most number of rides started at that station, and the number of rides that started at that station. """ max_start: Station # The station which has maximum rides that start from it. max_end: Station # The statoin which has maximun rides that end in it. mtla: Station # The station which has the maximum time of low availibilty. mtlu: Station # The station which has the maximun time of low unoccupied. first_loop = True # using first_loop variable to give value to the # {max_start, max_endd, mtla, mtlu} when the loop operates for the # first time, unless none of the if statements will occure.(cause the # variables don't have specific value) for station in self.all_stations.values(): if first_loop is True: max_start = max_end = mtla = mtlu = station first_loop = False max_start = bigger(max_start, station, max_start.start_from, station.start_from) max_end = bigger(max_end, station, max_end.end_in, station.end_in) mtla = bigger(mtla, station, mtla.low_availability, station.low_availability) mtlu = bigger(mtlu, station, mtlu.low_unoccupied, station.low_unoccupied) return { 'max_start': (max_start.name, max_start.start_from), 'max_end': (max_end.name, max_end.end_in), 'max_time_low_availability': (mtla.name, mtla.low_availability), 'max_time_low_unoccupied': (mtlu.name, mtlu.low_unoccupied) } def _update_active_rides_fast(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - see Task 5 of the assignment handout """ let = 0 # using let instead of syntax break, because when the first # event of our pq has not been occured because of the time, since our # pq has been sorted base on the event's time, therefore there is no # need to check other event so we do not need to check the others events # so we change the let to 1 to come out of the loop. while (self.rides_pq.is_empty() is False) and (let == 0): event = self.rides_pq.remove() if event.time > time: self.rides_pq.add(event) let = 1 if time >= event.time: endevent = event.process() while endevent != []: # because if our event is an EndRideEvent then its return's # list is empty and there is no consequence event. consequence_event = endevent.pop() self.rides_pq.add(consequence_event)
def find_path(self, start_node, target_node): """ Implement the A-star path search algorithm If you will add a new node to the path, don't forget to set the parent. You can find an example in the docstring of Node class Please note the shortest path between two nodes may not be unique. However all of them have same length! @type self: Grid @type start_node: Node The starting node of the path @type target_node: Node The target node of the path @rtype: None """ #create a copy of the original map g = copy.copy(self.map) #make an open PriorityQueue to store children opens = PriorityQueue(Node.__lt__) #set the starting node's g and h costs to be 0 or else it starts around infinity start_node.gcost = 0 start_node.hcost = 0 #add the starting node to the open Queue opens.add(start_node) #loop while the open set is not empty while not opens.is_empty(): #remove the value with the lowest fcost built into the PriorityQueue class q = opens.remove() #create a list of successors suc = [] #add each new successor node in the 8 surrounding points to the list if the index is in range and the point is navigable if q.grid_y-1 >= 0 and q.grid_y - 1 < self.height and q.grid_x-1 >= 0 and q.grid_x - 1 < self.width and g[q.grid_x-1][q.grid_y-1].navigable == True: suc.append(Node(g[q.grid_x-1][q.grid_y-1].navigable,q.grid_x-1,q.grid_y-1)) if q.grid_y-1 >= 0 and q.grid_y - 1 < self.height and q.grid_x >= 0 and q.grid_x < self.width and g[q.grid_x][q.grid_y-1].navigable == True: suc.append(Node(g[q.grid_x][q.grid_y-1].navigable,q.grid_x,q.grid_y-1)) if q.grid_y-1 >= 0 and q.grid_y - 1 < self.height and q.grid_x + 1 >= 0 and q.grid_x + 1 < self.width and g[q.grid_x+1][q.grid_y-1].navigable == True: suc.append(Node(g[q.grid_x+1][q.grid_y-1].navigable,q.grid_x+1,q.grid_y-1)) if q.grid_y >= 0 and q.grid_y < self.height and q.grid_x-1 >= 0 and q.grid_x - 1 < self.width and g[q.grid_x-1][q.grid_y].navigable == True: suc.append(Node(g[q.grid_x-1][q.grid_y].navigable,q.grid_x-1,q.grid_y)) if q.grid_y >= 0 and q.grid_y < self.height and q.grid_x+1 >= 0 and q.grid_x + 1 < self.width and g[q.grid_x+1][q.grid_y].navigable == True: suc.append(Node(g[q.grid_x+1][q.grid_y].navigable,q.grid_x+1,q.grid_y)) if q.grid_y+1 >= 0 and q.grid_y + 1 < self.height and q.grid_x-1 >= 0 and q.grid_x - 1 < self.width and g[q.grid_x-1][q.grid_y+1].navigable == True: suc.append(Node(g[q.grid_x-1][q.grid_y+1].navigable,q.grid_x-1,q.grid_y+1)) if q.grid_y+1 >= 0 and q.grid_y + 1 < self.height and q.grid_x >= 0 and q.grid_x < self.width and g[q.grid_x][q.grid_y+1].navigable == True: suc.append(Node(g[q.grid_x][q.grid_y+1].navigable,q.grid_x,q.grid_y+1)) if q.grid_y+1 >= 0 and q.grid_y + 1 < self.height and q.grid_x+1 >= 0 and q.grid_x + 1 < self.width and g[q.grid_x+1][q.grid_y+1].navigable == True: suc.append(Node(g[q.grid_x+1][q.grid_y+1].navigable,q.grid_x+1,q.grid_y+1)) #for each successor for i in range(len(suc)): #set the parent to be the one that was just removed suc[i].set_parent(q) #stop the search if the target node is found if suc[i] == target_node: #also add the successor to the closed set self.path.add(suc[i]) return None #set the target's g, h, and f costs suc[i].set_gcost(q.gcost + q.distance(suc[i])) suc[i].set_hcost(target_node.distance(suc[i])) suc[i].fcost() #if the successor is in the open set and is lower f than the value in the successor then skip the successsor if opens.is_less_than(suc[i]): pass #if the successor is in the closed set and is lower f than the value in the successor then skip the successsor if self.path.is_less_than(suc[i]): pass #otherwise add the successor to the open set else: opens.add(suc[i]) #add the q value to the closed set self.path.add(q)
class Simulation: """A simulation. This is the class which is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the run method below according to its docstring. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for auto-testing purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _dispatcher: Dispatcher # The dispatcher associated with the simulation. # @type _monitor: monitor # The monitor which is used to record the events def __init__(self): """Initialize a Simulation. @type self: Simulation @rtype: None """ self._events = PriorityQueue() self._dispatcher = Dispatcher() self._monitor = Monitor() def run(self, initial_events): """Run the simulation on the list of events in <initial_events>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: Simulation @type initial_events: list[Event] An initial list of events. @rtype: dict[str, object] >>> event_list_1 = [RiderRequest(1, Rider('Z', Location(1,1),\ Location(6,6), 15)), ] >>> event_list_1.append(DriverRequest(10, Driver('Y',\ Location(3,3), 2))) >>> simulation_1 = Simulation() >>> d1 = simulation_1.run(event_list_1) >>> d2 = {'rider_wait_time': 11.0, 'driver_ride_distance': 10.0,\ 'driver_total_distance': 14.0} >>> d1 == d2 True >>> event_list_2 = [DriverRequest(0, Driver('A', Location(1,1), 1)), \ DriverRequest(0, Driver('B', Location(1,2), 1)),RiderRequest(0, \ Rider('A2', Location(1,1),Location(5,5), 10)), RiderRequest(10,\ Rider('B2', Location(4,2), Location(1,5), 15)) ] >>> simulation_2 = Simulation() >>> d3 = simulation_2.run(event_list_2) >>> d4 = {'driver_ride_distance': 7.0, 'driver_total_distance': 8.5,\ 'rider_wait_time': 1.5} >>> d3 == d4 True """ # Add all initial events to the event queue. for event in initial_events: self._events.add(event) while not self._events.is_empty(): # Get the most nearest event, and remove it from the event queue removed_event = self._events.remove() # Do the event if isinstance(removed_event, Event): new_events = removed_event.do(self._dispatcher, self._monitor) # Append the result events back for event in new_events: self._events.add(event) return self._monitor.report()
class Simulation: """Runs the core of the simulation through time. === Attributes === all_rides: A list of all the rides in this simulation. Note that not all rides might be used, depending on the timeframe when the simulation is run. all_stations: A dictionary containing all the stations in this simulation. active_rides: A list containing all the rides currently in progress. event_queue: A priority queue containing all the events to be processed by the simulation. Note that some events added during the run of the simulation may not be processed, as they fall outside of the run time. visualizer: A helper class for visualizing the simulation. """ all_stations: Dict[str, Station] all_rides: List[Ride] active_rides: List[Ride] event_queue: PriorityQueue['Event'] visualizer: Visualizer def __init__(self, station_file: str, ride_file: str) -> None: """Initialize this simulation with the given configuration settings. """ self.all_stations = create_stations(station_file) self.all_rides = create_rides(ride_file, self.all_stations) self.active_rides = [] self.event_queue = PriorityQueue() self.visualizer = Visualizer() def run(self, start: datetime, end: datetime) -> None: """Run the simulation from <start> to <end>. """ step = timedelta(minutes=1) # Add ride start events to event_queue for ride in self.all_rides: if ride.start_time <= end: ride_start = RideStartEvent(self, ride.start_time, ride) self.event_queue.add(ride_start) # Begin main loop while start <= end: # Update active_rides and render sprites self._update_active_rides_fast(start) drawables = self.active_rides + list(self.all_stations.values()) self.visualizer.render_drawables(drawables, start) # Update statistics stored in the Station objects. Don't update # time related statistics if it's the last minute of the simulation self._update_ride_statistics(start) if start != end: self._update_time_statistics() start += step while True: if self.visualizer.handle_window_events(): return def _update_ride_statistics(self, current_time: datetime) -> None: """Updates the number of rides started and ended at each station. Also updates the number of bikes available at each station. """ for ride in self.active_rides: if current_time == ride.start_time: ride.start.num_rides_started += 1 ride.start.num_bikes -= 1 if current_time == ride.end_time: if ride.end.num_bikes < ride.end.capacity: ride.end.num_rides_ended += 1 ride.end.num_bikes += 1 def _update_time_statistics(self) -> None: """Updates the time spent at low availability and low occupied for each station. As the time increments this method adds 60 seconds to a station's time_low_availability and time_low_unoccupied attributes if it has no more than 5 bikes and no more than 5 open spots respectively. """ for station in self.all_stations.values(): if station.num_bikes <= 5: station.time_low_availability += 60 if station.capacity - station.num_bikes <= 5: station.time_low_unoccupied += 60 def _update_active_rides(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - Loop through `self.all_rides` and compare each Ride's start and end times with <time>. If <time> is between the ride's start and end times (inclusive), then add the ride to self.active_rides if it isn't already in that list. Otherwise, remove the ride from self.active_rides if it is in that list. - This means that if a ride started before the simulation's time period but ends during or after the simulation's time period, it should still be added to self.active_rides. """ for ride in self.all_rides: if ride.start_time <= time <= ride.end_time: if ride not in self.active_rides and ride.start.num_bikes > 0: self.active_rides.append(ride) elif ride in self.active_rides: self.active_rides.remove(ride) def calculate_statistics(self) -> Dict[str, Tuple[str, float]]: """Return a dictionary containing statistics for this simulation. The returned dictionary has exactly four keys, corresponding to the four statistics tracked for each station: - 'max_start' - 'max_end' - 'max_time_low_availability' - 'max_time_low_unoccupied' The corresponding value of each key is a tuple of two elements, where the first element is the name (NOT id) of the station that has the maximum value of the quantity specified by that key, and the second element is the value of that quantity. For example, the value corresponding to key 'max_start' should be the name of the station with the most number of rides started at that station, and the number of rides that started at that station. Student Note: This function makes a list of stats for each station and then loops through the dictionary and the list simultaneously and compares each item with each value in the dictionary. This is done to reduce duplicate code. """ stats_dict = { 'max_start': ['', -1], 'max_end': ['', -1], 'max_time_low_availability': ['', -1], 'max_time_low_unoccupied': ['', -1] } # Loop through each station for station in self.all_stations.values(): # Store the stats for each station in a list to be iterated over station_stats = [ station.num_rides_started, station.num_rides_ended, station.time_low_availability, station.time_low_unoccupied ] # Iterate through the dictionary and the list at the same time index = 0 for stat in stats_dict.values(): # Compare the dictionary's value with the station's values if station_stats[index] > stat[1]: stat[0] = station.name stat[1] = station_stats[index] elif station_stats[index] == stat[1] and station.name < stat[0]: stat[0] = station.name stat[1] = station_stats[index] index += 1 # Format dictionary for key in stats_dict: stats_dict[key] = tuple(stats_dict[key]) return stats_dict def _update_active_rides_fast(self, time: datetime) -> None: """Update this simulation's list of active rides for the given time. REQUIRED IMPLEMENTATION NOTES: - see Task 5 of the assignment handout """ while not self.event_queue.is_empty(): event = self.event_queue.remove() if event.time <= time: # If there are no bikes available do not start a ride if event.ride.start.num_bikes < 1 and \ isinstance(event, RideStartEvent): continue new_events = event.process() for new_event in new_events: self.event_queue.add(new_event) else: self.event_queue.add(event) return
class Simulation: """A simulation. This is the class which is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the run method below according to its docstring. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for auto-testing purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _dispatcher: Dispatcher # The dispatcher associated with the simulation. def __init__(self): """Initialize a Simulation. @type self: Simulation @rtype: None """ self._events = PriorityQueue() self._dispatcher = Dispatcher() self._monitor = Monitor() def run(self, initial_events): """Run the simulation on the list of events in <initial_events>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: Simulation @type initial_events: list[Event] An initial list of events. @rtype: dict[str, object] >>> events = [] >>> loc = Location(0,0) >>> events.append(RiderRequest(2,Rider("r1", loc, Location(3,4), 4))) >>> events.append(DriverRequest(3, Driver("d1", Location(0,4), 10))) >>> sim = Simulation() >>> sim.run(events) {'rider_wait_time': 1.0, 'driver_ride_distance': 7.0, 'driver_total_distance': 11.0} # Above line couldn't be changed to go to next line because doing that # made the doctest compare the output so that it also flows to the next # line """ # Add all initial events to the event queue. # Until there are no more events, remove an event # from the event queue and do it. Add any returned # events to the event queue. for event in initial_events: self._events.add(event) new_events = [] while not self._events.is_empty(): new_events = self._events.remove().do(self._dispatcher, self._monitor) if new_events is not None: for event in new_events: self._events.add(event) return self._monitor.report()
def find_path(self, start_node, target_node): """ Implement the A-star path search algorithm If you will add a new node to the path, don't forget to set the parent. You can find an example in the docstring of Node class Please note the shortest path between two nodes may not be unique. However all of them have same length! @type self: Grid @type start_node: Node The starting node of the path @type target_node: Node The target node of the path @rtype: None >>> g = Grid("", ["B.++", ".+..", "...T"]) >>> g.find_path(g.boat, g.treasure) >>> n = g.treasure >>> print(n.grid_x, n.grid_y, ... n.gcost, n.hcost, n.fcost(), ... n.parent.grid_x, n.parent.grid_y) 3 2 38 0 38 2 1 >>> n = g.treasure.parent >>> print(n.grid_x, n.grid_y, ... n.gcost, n.hcost, n.fcost(), ... n.parent.grid_x, n.parent.grid_y) 2 1 24 14 38 1 0 >>> n = g.map[1][0] >>> print(n.grid_x, n.grid_y, ... n.gcost, n.hcost, n.fcost(), ... n.parent.grid_x, n.parent.grid_y) 1 0 10 28 38 0 0 >>> n = g.map[0][1].parent >>> n == g.boat True """ # TODO def less_than(x_node, y_node): """ Compare the priority of x over y @type x_node: Node @type y_node: Node @rtype: bool True if x has higher priority over y otherwise False """ return x_node < y_node # create an empty list as open set open_set = [] # loop the row on the map for row in self.map: # extend the row in the list open_set.extend(row) # remove the start node from the list open_set.remove(start_node) # define a closed set as the priority queue in less_than closed_set = PriorityQueue(less_than) # add the start node to the list of closed set closed_set.add(start_node) # set the gcost for start node start_node.set_gcost(0) # loop the closed set if it is not empty while not closed_set.is_empty(): # get the current node from the closed set curr_node = closed_set.remove() # if the current node is the target node if curr_node is target_node: # done break # loop the next node in the neighours for current node for next_node in self.get_neighours(curr_node): # if the next node is in the open set if next_node in open_set: # remove the next node open_set.remove(next_node) # add it to the closed set closed_set.add(next_node) # set the gcost for the next node next_node.set_gcost(curr_node.gcost + curr_node.distance(next_node)) # set the hcost for the next_node next_node.set_hcost(next_node.distance(target_node)) # set the parent for the next node next_node.set_parent(curr_node)
class GroceryStoreSimulation: """A Grocery Store simulation. This is the class which is responsible for setting up and running a simulation. The interface is given to you: your main task is to implement the two methods according to their docstrings. Of course, you may add whatever private attributes you want to this class. Because you should not change the interface in any way, you may not add any public attributes. === Private Attributes === _events: A sequence of events arranged in priority determined by the event sorting order. _store: The store being simulated. """ _events: PriorityQueue _store: GroceryStore def __init__(self, store_file: TextIO) -> None: """Initialize a GroceryStoreSimulation using configuration <store_file>. """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, file: TextIO) -> Dict[str, Any]: """Run the simulation on the events stored in <initial_events>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. """ # This initializes statistics. stats = {'num_customers': 0, 'total_time': 0, 'max_wait': -1} # This fills self._events from file. event_list = create_event_list(file) while len(event_list) != 0: self._events.add(event_list.pop()) # This keeps track of customer start and end times. This is used to # calculate the maximum wait time. customers = {} while not self._events.is_empty(): event = self._events.remove() # This checks to see the event type. if isinstance(event, CustomerArrival): # This checks to see if the customer is in the customers # dictionary since the "max_wait" calculation is based on the # customer arriving at the wait area. if event.customer not in customers: customers[event.customer] = [event.timestamp, -1] stats['num_customers'] += 1 elif isinstance(event, CheckoutCompleted): customers[event.customer][1] = event.timestamp new_events = event.do(self._store) # This adds the new events. while not len(new_events) == 0: self._events.add(new_events.pop()) stats['total_time'] = event.timestamp # This calculates the maximum wait time. for key in customers: wait_time = customers[key][1] - customers[key][0] if wait_time > stats['max_wait']: stats['max_wait'] = wait_time return stats
class GroceryStoreSimulation: """A Grocery Store simulation. This is the class which is responsible for setting up and running a simulation. The API is given to you: your main task is to implement the two methods according to their docstrings. Of course, you may add whatever private attributes and methods you want. But because you should not change the interface, you may not add any public attributes or methods. This is the entry point into your program, and in particular is used for autotesting purposes. This makes it ESSENTIAL that you do not change the interface in any way! """ # === Private Attributes === # @type _events: PriorityQueue[Event] # A sequence of events arranged in priority determined by the event # sorting order. # @type _store: GroceryStore # The grocery store associated with the simulation. def __init__(self, store_file): """Initialize a GroceryStoreSimulation from a file. @type store_file: str A file containing the configuration of the grocery store. @rtype: None """ self._events = PriorityQueue() self._store = GroceryStore(store_file) def run(self, event_file): """Run the simulation on the events stored in <event_file>. Return a dictionary containing statistics of the simulation, according to the specifications in the assignment handout. @type self: GroceryStoreSimulation @type event_file: str A filename referring to a raw list of events. Precondition: the event file is a valid list of events. @type initial_events: list[event] @rtype: dict[str, object] """ # Initialize statistics stats = { 'num_customers': 0, #check 'total_time': 0, 'max_wait': -1 } initial_events = create_event_list(event_file) #counted number of customers from file directly # TODO: Process all of the events, collecting statistics along the way. #first, add event from initial_events to pq then sort using sort method for index in range (len(initial_events)): self._events.add(initial_events[index]) #second, pass sorted events which is inside PQ to store while not self._events.is_empty(): #trigger the do function which checks if new events spawn in the store #new events are returned #setup simulation clock, advance clock to first event current_event = self._events.remove() #when there is only one event left, equate the time if self._events.is_empty(): stats['total_time'] = current_event.timestamp #the event is triggered returned_tuple = current_event.do(self._store) if returned_tuple[1] == 'int': stats['max_wait'] = returned_tuple[0] elif returned_tuple[1] == 'one event': self._events.add(returned_tuple[0]) elif returned_tuple[1] == 'event list': for item in returned_tuple[0]: self._events.add(item) return stats def handle_new_event(self, item): self._events.add(item)