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
Beispiel #2
0
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'
Beispiel #3
0
 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
Beispiel #4
0
    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()
Beispiel #5
0
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()
Beispiel #6
0
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
Beispiel #8
0
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
Beispiel #9
0
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()
Beispiel #10
0
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()
Beispiel #11
0
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
Beispiel #12
0
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
Beispiel #13
0
    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
Beispiel #14
0
    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
Beispiel #15
0
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)
Beispiel #17
0
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
Beispiel #18
0
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
Beispiel #19
0
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()
Beispiel #20
0
    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)
Beispiel #21
0
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)
        }
Beispiel #22
0
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
Beispiel #23
0
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)
Beispiel #24
0
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
Beispiel #25
0
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)
Beispiel #26
0
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
Beispiel #27
0
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)
        }
Beispiel #28
0
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)
Beispiel #31
0
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()
Beispiel #32
0
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
Beispiel #33
0
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)