コード例 #1
0
ファイル: truck.py プロジェクト: dumaas/c950
 def __init__(self, id: int) -> None:
     self.id = id
     self.capacity = 16
     self.mph = 18
     # Initialize the truck departure time to the start of the delivery day
     self.departure_time = Clock(8)
     self.current_time = Clock()
     self.packages: List[Package] = []
コード例 #2
0
    def load_packages(cls) -> Packages:
        """Loads the package data from a file.

        Returns
        -------
            HashSet[int, str]
                The mapping of package identifiers to package objects.

        Space Complexity
        ---------------
            O(n)

        Time Complexity
        ---------------
            O(n)
        """
        data = cls.load_json('data/package_data.json')
        size = len(data)
        packages = HashSet(size)

        for key, value in data.items():
            identifier = int(key)

            (hours, minutes) = map(int, value['deadline'].split(':'))
            deadline = Clock(hours, minutes)

            package = Package(
                identifier,
                value['address'],
                value['city'],
                value['state'],
                value['zip'],
                value['kg'],
                deadline,
            )

            # Delayed packages - will not arrive at depot until 09:05
            if package.id in [6, 25, 28, 32]:
                package.arrival_time = Clock(9, 5)

            # Incorrect address - will be corrected at 10:20
            if package.id == 9:
                package.street = '410 S State St'
                package.arrival_time = Clock(10, 20)

            # Package must be delivered via truck two
            if package.id in [3, 18, 36, 38]:
                package.deliverable_by = [2]
                package.is_priority = True

            # Package must be delivered with linked packages
            if package.id in [13, 14, 15, 16, 19, 20]:
                package.linked = True
                package.is_priority = True

            packages.set(identifier, package)

        return packages
コード例 #3
0
ファイル: application.py プロジェクト: dumaas/c950
    def package_report(self) -> None:
        """Prints a report of a single package at a specific time.

        Space Complexity
        ---------------
            O(n)

        Time Complexity
        ---------------
            O(n)
        """
        package_id = self.prompter.prompt('package')
        try:
            package_id = int(package_id)
        except:
            print('\nInvalid package identifier\n')
            return

        if package_id not in self.depot.package_table.packages:
            print('\nInvalid package identifier\n')
            return

        time = self.prompter.prompt('time')
        if match(r'^\d{2}:\d{2}:\d{2}$', time) is None:
            print('\nInvalid time format\n')
            return

        (hours, minutes, seconds) = map(int, time.split(':'))
        package = self.depot.package_table.get(package_id)

        print('\nWGUPS Individual Package Report\n')
        print(f'Package: {package_id}')
        print(f'Time: {time}')
        print(package.inline_report(Clock(hours, minutes)))
        print('\n')
コード例 #4
0
ファイル: application.py プロジェクト: dumaas/c950
    def packages_report(self) -> None:
        """Prints a report of the status of all packages at a specific time.

        Time Complexity
        ---------------
            O(n)

        Time Complexity
        ---------------
            O(n*log(n))
        """
        time = self.prompter.prompt('time')
        if match(r'^\d{2}:\d{2}:\d{2}$', time) is None:
            print('\nInvalid time format\n')
            return

        (hours, minutes, seconds) = map(int, time.split(':'))
        packages = sorted(self.depot.package_table.all(), key=lambda p: p.id)

        reports = [
            package.delivery_report(Clock(hours, minutes))
            for package in packages
        ]
        col_width = max(len(item) for report in reports
                        for item in report) + 2  # Padding

        print('\nWGUPS Comprehensive Package Report\n')
        print(f'Time: {time}\n')
        for report in reports:
            print(''.join(item.ljust(col_width) for item in report))
        print('\n')
コード例 #5
0
ファイル: truck.py プロジェクト: dumaas/c950
    def deliver_packages(self, distance_table: DistanceTable,
                         return_to_depot: bool) -> None:
        """Delivers all packages currently loaded on the truck.

        Parameters
        ----------
            distance_table : DistanceTable
                A table of addresses and the distances between them.
            return_to_depot : bool
                Whether or not the truck should return to the depot after finishing
                its deliveries.

        Space Complexity
        ---------------
            O(n^2)

        Time Complexity
        ---------------
            O(n^2*log(n))
        """
        current_location = distance_table.depot_address
        destinations = self.destinations()
        total_time = self.departure_time
        total_distance = 0

        while self.packages:
            destinations = sorted(
                destinations,
                key=lambda x: distance_table.distance(current_location, x))
            closest = destinations.pop(0)

            distance = distance_table.distance(current_location, closest)
            travel_time = self.travel_time(distance)
            total_time.add_minutes(travel_time)

            deliveries = [
                package for package in self.packages
                if package.street == closest
            ]

            for package in deliveries:
                self.packages.remove(package)
                package.deliver(total_time.clone())

            current_location = closest
            total_distance += distance

        if return_to_depot:
            distance = distance_table.to_depot(current_location)
            travel_time = self.travel_time(distance)

            total_distance += distance
            total_time.add_minutes(travel_time)

        self.current_time = Clock(
            self.current_time.hours + total_time.hours,
            self.current_time.minutes + total_time.minutes)
        return total_distance
コード例 #6
0
ファイル: package.py プロジェクト: dumaas/c950
 def __init__(self,
              id: int,
              street: str,
              city: str,
              state: str,
              zip_code: str,
              weight: int,
              deadline: Clock,
              arrival_time: Clock = Clock(8)) -> None:
     self.id = id
     self.street = street
     self.city = city
     self.state = state
     self.zip_code = zip_code
     self.weight = weight
     self.deadline = deadline
     self.status = PackageStatus.AWAITING_DELIVERY
     self.linked = False
     self.deliverable_by = [1, 2]
     self.is_priority = False
     self.arrival_time = Clock(8)
     self.pickup_time = None
     self.delivery_time = None
コード例 #7
0
ファイル: package.py プロジェクト: dumaas/c950
    def is_high_priority(self) -> bool:
        """Determines if the package is high priority or not.

        Returns
        -------
            bool
                Returns `True` if the package is high priority, otherwise returns `False`.

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        return self.deadline < Clock(17) or self.is_priority
コード例 #8
0
ファイル: truck.py プロジェクト: dumaas/c950
class Truck:
    """A class which represents a truck delivering packages for the WGUPS.

    Attributes
    ----------
        id : int
            The identifier for the truck.
        capacity : int
            The total number of possible packages that can be carried by the truck.
        mph : int
            The speed of the truck.
        departure_time : Clock
            The earliest time that the truck can leave the hub.
        packages : List[Package]
            The packages that have been loaded onto the truck.
    """

    id: int
    capacity: int
    mph: int
    departure_time: Clock
    packages: List[Package]

    def __init__(self, id: int) -> None:
        self.id = id
        self.capacity = 16
        self.mph = 18
        # Initialize the truck departure time to the start of the delivery day
        self.departure_time = Clock(8)
        self.current_time = Clock()
        self.packages: List[Package] = []

    def is_full(self) -> bool:
        """Determines if the truck is full.

        Returns
        -------
            bool
                Returns `True` if the truck is full, otherwise returns `False`.

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        return len(self.packages) >= self.capacity

    def depart_at(self, time: Clock) -> None:
        """Sets the departure time of the truck.

        Parameters
        ----------
            time : Clock
                The departure time to set.

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        self.departure_time = time
        self.current_time = self.departure_time if self.departure_time > self.current_time else self.current_time

    def destinations(self) -> List[str]:
        """Gets the list of destinations that will be visited by the truck.

        Returns
        -------
            List[str]
                The list of destinations that will be visited by the truck.

        Space Complexity
        ---------------
            O(n)

        Time Complexity
        ---------------
            O(n)
        """
        return [package.street for package in self.packages]

    def can_load(self, n: int) -> bool:
        """Determines if the truck can accept `n` number of packages without
        exceeding its capacity.

        Parameters
        ----------
            n : int
                The number of packages.

        Returns
        -------
            bool
                Returns `True` if the truck can accept all `n` packages, otherwise
                returns `False`.

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        return len(self.packages) + n <= self.capacity

    def load_package(self, package: Package) -> None:
        """Loads a package onto the truck.

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        package.pickup(self.departure_time.clone())
        self.packages.append(package)

    def load_packages(self, packages: List[Package]) -> None:
        """Loads several packages onto the truck.

        Space Complexity
        ---------------
            O(n)

        Time Complexity
        ---------------
            O(n)
        """
        for package in packages:
            self.load_package(package)

    def unload_package(self, package: Package) -> None:
        """Unloads a package from the truck.

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        if package in self.packages:
            self.packages.remove(package)

    def unload_packages(self, packages: List[Package]) -> None:
        """Unloads several packages from the truck.

        Space Complexity
        ---------------
            O(n)

        Time Complexity
        ---------------
            O(n)
        """
        for package in packages:
            if package in self.packages:
                self.packages.remove(package)

    def has_package(self, package: Package) -> bool:
        """Determines if the truck contains the specified package.

        Returns
        -------
            bool
                True if the truck contains the specified package, otherwise False

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        return package in self.packages

    def can_deliver(self, package: Package) -> bool:
        """Determines if the truck can deliver the specified package.

        Parameters
        ----------
            package : Package
                The package to check.

        Returns
        -------
            bool
                Returns `True` if the truck can deliver the package, otherwise returns
                `False`.

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        return self.id in package.deliverable_by and self.departure_time >= package.arrival_time

    def deliver_packages(self, distance_table: DistanceTable,
                         return_to_depot: bool) -> None:
        """Delivers all packages currently loaded on the truck.

        Parameters
        ----------
            distance_table : DistanceTable
                A table of addresses and the distances between them.
            return_to_depot : bool
                Whether or not the truck should return to the depot after finishing
                its deliveries.

        Space Complexity
        ---------------
            O(n^2)

        Time Complexity
        ---------------
            O(n^2*log(n))
        """
        current_location = distance_table.depot_address
        destinations = self.destinations()
        total_time = self.departure_time
        total_distance = 0

        while self.packages:
            destinations = sorted(
                destinations,
                key=lambda x: distance_table.distance(current_location, x))
            closest = destinations.pop(0)

            distance = distance_table.distance(current_location, closest)
            travel_time = self.travel_time(distance)
            total_time.add_minutes(travel_time)

            deliveries = [
                package for package in self.packages
                if package.street == closest
            ]

            for package in deliveries:
                self.packages.remove(package)
                package.deliver(total_time.clone())

            current_location = closest
            total_distance += distance

        if return_to_depot:
            distance = distance_table.to_depot(current_location)
            travel_time = self.travel_time(distance)

            total_distance += distance
            total_time.add_minutes(travel_time)

        self.current_time = Clock(
            self.current_time.hours + total_time.hours,
            self.current_time.minutes + total_time.minutes)
        return total_distance

    def travel_time(self, miles: int) -> int:
        """Returns the time in minutes that it will take the truck to travel the
        specified number of miles.

        Parameters
        ----------
            miles : int
                The number of miles that will be traveled.

        Returns
        -------
            int
                The time in minutes that it takes to travel the specified number
                of miles.

        Space Complexity
        ---------------
            O(1)

        Time Complexity
        ---------------
            O(1)
        """
        return round((miles / self.mph) * 60)
コード例 #9
0
    def deliver_packages(self) -> float:
        """Returns the total distance traveled by trucks during package delivery.

        Returns
        -------
            float
                The total distance.

        Space Complexity
        ---------------
            O(n^3)

        Time Complexity
        ---------------
            O(n^3*log(n))
        """
        packages = self.package_table.all()

        # Obtain separate lists of the high and low priority packages that must be delivered
        # and sort them by deadline (if applicable) and their distance to the depot
        high_priority = sorted(
            [package for package in packages if package.is_high_priority()],
            key=lambda x: (x.deadline, self.distance_table.to_depot(x.street)))
        regular_priority = sorted(
            [
                package
                for package in packages if not package.is_high_priority()
            ],
            key=lambda x: self.distance_table.to_depot(x.street))

        # Initialize loop parameters
        trip = 0
        truck_index = 0
        delivered = 0
        total_distance = 0
        departure_times = [Clock(8), Clock(9, 5), Clock(10, 20)]

        # Continue delivering packages while the number of packages that have been delivered
        # is less than the total number of packages that need to be delivered. The loop will
        # iterate three times in total given that our truck capacity is 16 and the trucks are
        # always loaded to capacity
        while delivered < len(packages):
            # Obtain the truck and set its departure time
            truck: Truck = self.trucks.get(truck_index)
            truck.depart_at(departure_times[trip].clone())

            # Obtain the priority packages that are deliverable by the truck
            priority_deliveries = [
                package for package in high_priority
                if truck.can_deliver(package)
            ]

            # Obtain the regular priority packages that are deliverable by the truck
            regular_deliveries = [
                package for package in regular_priority
                if truck.can_deliver(package)
            ]

            # First, load all priority deliveries that fit on the truck
            for package in priority_deliveries:
                if not truck.is_full() and not truck.has_package(package):
                    high_priority.remove(package)
                    truck.load_package(package)
                    delivered += 1

            # Then, load all regular priority deliveries that fit on the truck
            for package in regular_deliveries:
                if not truck.is_full() and not truck.has_package(package):
                    regular_priority.remove(package)
                    truck.load_package(package)
                    delivered += 1

            # Calculate the total distance traveled by the truck in addition to the
            # distance to return to the depot, if necessary
            remaining_packages = len(packages) - delivered
            return_to_depot = remaining_packages > 0
            total_distance += truck.deliver_packages(self.distance_table,
                                                     return_to_depot)

            # Increment the trip index and the truck index
            trip += 1
            truck_index = trip % len(self.trucks)

        return total_distance