CSC110 / lectures / Simplified / Building a Simulation / events.py
events.py
Raw
"""print(event) calls event.__str__()
"""
from __future__ import annotations
import datetime
import random

from entities import Order
from food_delivery_system import FoodDeliverySystem


class Event:
    timestamp: datetime.datetime

    def __init__(self, timestamp: datetime.datetime) -> None:
        self.timestamp = timestamp

    def handle_event(self, system: FoodDeliverySystem) -> list[Event]:  # None (before)
        raise NotImplementedError


class NewOrderEvent(Event):
    _order: Order

    def __init__(self, order: Order) -> None:
        self._order = order
        Event.__init__(self, order.start_time)   # This initializes self.timestamp
        # This works, but is not the best practice
        # self.timestamp = order.start_time

    def handle_event(self, system: FoodDeliverySystem) -> list[Event]:
        success = system.place_order(self._order)
        if success:
            completion_time = self.timestamp + datetime.timedelta(minutes=10)
            return [CompleteOrderEvent(completion_time, self._order)]
        else:
            self._order.start_time = self.timestamp + datetime.timedelta(minutes=5)  # Try again after 5m
            return [NewOrderEvent(self._order)]


class CompleteOrderEvent(Event):
    _order: Order

    def __init__(self, timestamp: datetime.datetime, order: Order) -> None:
        Event.__init__(self, timestamp)
        self._order = order

    def handle_event(self, system: FoodDeliverySystem) -> list[Event]:
        system.complete_order(self._order, self.timestamp)
        return []


class GenerateOrdersEvent(Event):
    """
    Private Instance Attributes:
    - _duration: the number of hours to generate orders for
    Private Representation Invariants:
        - self._duration > 0
    """
    _duration: int

    def __init__(self, timestamp: datetime.datetime, duration: int) -> None:
        """
        Preconditions:
            - duration > 0
        """
        Event.__init__(self, timestamp)
        self._duration = duration

    def handle_event(self, system: FoodDeliverySystem) -> list[Event]:
        customers = system.get_customers()
        vendors = system.get_vendors()

        events = []

        current_time = self.timestamp
        end_time = self.timestamp + datetime.timedelta(hours=self._duration)

        while current_time < end_time:
            customer = random.choice(customers)
            vendor = random.choice(vendors)
            food_items = {}
            new_order = Order(customer=customer, vendor=vendor, food_items=food_items,
                              start_time=current_time)

            new_order_event = NewOrderEvent(new_order)
            events.append(new_order_event)

            current_time = current_time + datetime.timedelta(minutes=random.randint(1, 60))

        return events