init commit
This commit is contained in:
@@ -0,0 +1,138 @@
|
|||||||
|
from DeliveryObject import DeliveryObject
|
||||||
|
|
||||||
|
# Names from the Data Tables provided
|
||||||
|
xyNames = [
|
||||||
|
"Western Governors University 4001 South 700 East, Salt Lake City, UT 84107",
|
||||||
|
"International Peace Gardens 1060 Dalton Ave S",
|
||||||
|
"Sugar House Park 1330 2100 S",
|
||||||
|
"Taylorsville-Bennion Heritage City Gov Off 1488 4800 S",
|
||||||
|
"Salt Lake City, Division of Health Services 177 W Price Ave",
|
||||||
|
"South Salt Lake Public Works 195 W Oakland Ave",
|
||||||
|
"Salt Lake City, Streets and Sanitation 2010 W 500 S",
|
||||||
|
"Deker Lake 2300 Parkway Blvd",
|
||||||
|
"Salt Lake City,Ottinger Hall 233 Canyon Rd",
|
||||||
|
"Columbus Library 2530 S 500 E",
|
||||||
|
"Taylorsville City Hall 2600 Taylorsville Blvd",
|
||||||
|
"South Salt Lake Police 2835 Main St",
|
||||||
|
"Council Hall 300 State St",
|
||||||
|
"Redwood Park 3060 Lester St",
|
||||||
|
"Salt Lake County Mental Health 3148 S 1100 W",
|
||||||
|
"Salt Lake County/United Police Dept 3365 S 900 W",
|
||||||
|
"West Valley Prosecutor 3575 W Valley Central Sta bus Loop",
|
||||||
|
"Housing Auth. of Salt Lake County 3595 Main St",
|
||||||
|
"Utah DMV Administrative Office 380 W 2880 S",
|
||||||
|
"Third District Juvenile Court 410 S State St",
|
||||||
|
"Cottonwood Regional Softball Complex 4300 S 1300 E",
|
||||||
|
"Holiday City Office 4580 S 2300 E",
|
||||||
|
"Murray City Museum 5025 State St",
|
||||||
|
"Valley Regional Softball Complex 5100 South 2700 West",
|
||||||
|
"City Center of Rock Springs 5383 South 900 East #104",
|
||||||
|
"Rice Terrace Pavilion Park 600 E 900 South",
|
||||||
|
"Wheeler Historic Farm 6351 South 900 East",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Names from the Data Tables provided
|
||||||
|
xyNames2 = [
|
||||||
|
"HUB",
|
||||||
|
"1060 Dalton Ave S (84104)",
|
||||||
|
"1330 2100 S (84106)",
|
||||||
|
"1488 4800 S (84123)",
|
||||||
|
"177 W Price Ave (84115)",
|
||||||
|
"195 W Oakland Ave (84115)",
|
||||||
|
"2010 W 500 S (84104)",
|
||||||
|
"2300 Parkway Blvd (84119)",
|
||||||
|
"233 Canyon Rd (84103)",
|
||||||
|
"2530 S 500 E (84106)",
|
||||||
|
"2600 Taylorsville Blvd (84118)",
|
||||||
|
"2835 Main St (84115)",
|
||||||
|
"300 State St (84103)",
|
||||||
|
"3060 Lester St (84119)",
|
||||||
|
"3148 S 1100 W (84119)",
|
||||||
|
"3365 S 900 W (84119)",
|
||||||
|
"3575 W Valley Central Station bus Loop (84119)",
|
||||||
|
"3595 Main St (84115)",
|
||||||
|
"380 W 2880 S (84115)",
|
||||||
|
"410 S State St (84111)",
|
||||||
|
"4300 S 1300 E (84117)",
|
||||||
|
"4580 S 2300 E (84117)",
|
||||||
|
"5025 State St (84107)",
|
||||||
|
"5100 South 2700 West (84118)",
|
||||||
|
"5383 S 900 East #104 (84117)",
|
||||||
|
"600 E 900 South (84105)",
|
||||||
|
"6351 South 900 East (84121)"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Data provided from assignment info
|
||||||
|
distanceChart = [
|
||||||
|
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[7.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[3.8, 7.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[11.0, 6.4, 9.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[2.2, 6.0, 4.4, 5.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[3.5, 4.8, 2.8, 6.9, 1.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[10.9, 1.6, 8.6, 8.6, 7.9, 6.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[8.6, 2.8, 6.3, 4.0, 5.1, 4.3, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[7.6, 4.8, 5.3, 11.1, 7.5, 4.5, 4.2, 7.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[2.8, 6.3, 1.6, 7.3, 2.6, 1.5, 8.0, 9.3, 4.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[6.4, 7.3, 10.4, 1.0, 6.5, 8.7, 8.6, 4.6, 11.9, 9.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[3.2, 5.3, 3.0, 6.4, 1.5, 0.8, 6.9, 4.8, 4.7, 1.1, 7.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[7.6, 4.8, 5.3, 11.1, 7.5, 4.5, 4.2, 7.7, 0.6, 5.1, 12.0, 4.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[5.2, 3.0, 6.5, 3.9, 3.2, 3.9, 4.2, 1.6, 7.6, 4.6, 4.9, 3.5, 7.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[4.4, 4.6, 5.6, 4.3, 2.4, 3.0, 8.0, 3.3, 7.8, 3.7, 5.2, 2.6, 7.8, 1.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[3.7, 4.5, 5.8, 4.4, 2.7, 3.8, 5.8, 3.4, 6.6, 4.0, 5.4, 2.9, 6.6, 1.5, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[7.6, 7.4, 5.7, 7.2, 1.4, 5.7, 7.2, 3.1, 7.2, 6.7, 8.1, 6.3, 7.2, 4.0, 6.4, 5.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[2.0, 6.0, 4.1, 5.3, 0.5, 1.9, 7.7, 5.1, 5.9, 2.3, 6.2, 1.2, 5.9, 3.2, 2.4, 1.6, 7.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[3.6, 5.0, 3.6, 6.0, 1.7, 1.1, 6.6, 4.6, 5.4, 1.8, 6.9, 1.0, 5.4, 3.0, 2.2, 1.7, 6.1, 1.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[6.5, 4.8, 4.3, 10.6, 6.5, 3.5, 3.2, 6.7, 1.0, 4.1, 11.5, 3.7, 1.0, 6.9, 6.8, 6.4, 7.2, 4.9, 4.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[1.9, 9.5, 3.3, 5.9, 3.2, 4.9, 11.2, 8.1, 8.5, 3.8, 6.9, 4.1, 8.5, 6.2, 5.3, 4.9, 10.6, 3.0, 4.6, 7.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[3.4, 10.9, 5.0, 7.4, 5.2, 6.9, 12.7, 10.4, 10.3, 5.8, 8.3, 6.2, 10.3, 8.2, 7.4, 6.9, 12.0, 5.0, 6.6, 9.3, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[2.4, 8.3, 6.1, 4.7, 2.5, 4.2, 10.0, 7.8, 7.8, 4.3, 4.1, 3.4, 7.8, 5.5, 4.6, 4.2, 9.4, 2.3, 3.9, 6.8, 2.9, 4.4, 0.0, 0.0, 0.0, 0.0],
|
||||||
|
[6.4, 6.9, 9.7, 0.6, 6.0, 9.0, 8.2, 4.2, 11.5, 7.8, 0.4, 6.9, 11.5, 4.4, 4.8, 5.6, 7.5, 5.5, 6.5, 11.4, 6.4, 7.9, 4.5, 0.0, 0.0, 0.0],
|
||||||
|
[2.4, 10.0, 6.1, 6.4, 4.2, 5.9, 11.7, 9.5, 9.5, 4.8, 4.9, 5.2, 9.5, 7.2, 6.3, 5.9, 11.1, 4.0, 5.6, 8.5, 2.8, 3.4, 1.7, 5.4, 0.0, 0.0],
|
||||||
|
[5.0, 4.4, 2.8, 10.1, 5.4, 3.5, 5.1, 6.2, 2.8, 3.2, 11.0, 3.7, 2.8, 6.4, 6.5, 5.7, 6.2, 5.1, 4.3, 1.8, 6.0, 7.9, 6.8, 10.6, 7.0, 0.0],
|
||||||
|
[3.6, 13.0, 7.4, 10.1, 5.5, 7.2, 14.2, 10.7, 14.1, 6.0, 6.8, 6.4, 14.1, 10.5, 8.8, 8.4, 13.6, 5.2, 6.9, 13.1, 4.1, 4.7, 3.1, 7.8, 1.3, 8.3]
|
||||||
|
]
|
||||||
|
|
||||||
|
# Data provided from assignment info [ wrapped in DeliveryObject's ]
|
||||||
|
packages = [
|
||||||
|
DeliveryObject(1, "195 W Oakland Ave", "Salt Lake City", "UT", 84115, "10:30 AM", 21),
|
||||||
|
DeliveryObject(2, "2530 S 500 E", "Salt Lake City", "UT", 84106, "EOD", 44),
|
||||||
|
DeliveryObject(3, "233 Canyon Rd", "Salt Lake City", "UT", 84103, "EOD", 2, "Can only be on truck 2"),
|
||||||
|
DeliveryObject(4, "380 W 2880 S", "Salt Lake City", "UT", 84115, "EOD", 4),
|
||||||
|
DeliveryObject(5, "410 S State St", "Salt Lake City", "UT", 84111, "EOD", 5),
|
||||||
|
DeliveryObject(6, "3060 Lester St", "West Valley City", "UT", 84119, "10:30 AM", 88, "Delayed on flight---will not arrive to depot until 9:05 am"),
|
||||||
|
DeliveryObject(7, "1330 2100 S", "Salt Lake City", "UT", 84106, "EOD", 8),
|
||||||
|
DeliveryObject(8, "300 State St", "Salt Lake City", "UT", 84103, "EOD", 9),
|
||||||
|
DeliveryObject(9, "300 State St", "Salt Lake City", "UT", 84103, "EOD", 2, "Wrong address listed"),
|
||||||
|
DeliveryObject(10, "600 E 900 South", "Salt Lake City", "UT", 84105, "EOD", 1),
|
||||||
|
DeliveryObject(11, "2600 Taylorsville Blvd", "Salt Lake City", "UT", 84118, "EOD", 1),
|
||||||
|
DeliveryObject(12, "3575 W Valley Central Station bus Loop", "West Valley City", "UT", 84119, "EOD", 1),
|
||||||
|
DeliveryObject(13, "2010 W 500 S", "Salt Lake City", "UT", 84104, "10:30 AM", 2),
|
||||||
|
DeliveryObject(14, "4300 S 1300 E", "Millcreek", "UT", 84117, "10:30 AM", 88, "Must be delivered with 15, 19"),
|
||||||
|
DeliveryObject(15, "4580 S 2300 E", "Holladay", "UT", 84117, "9:00 AM", 4),
|
||||||
|
DeliveryObject(16, "4580 S 2300 E", "Holladay", "UT", 84117, "10:30 AM", 88, "Must be delivered with 13, 19"),
|
||||||
|
DeliveryObject(17, "3148 S 1100 W", "Salt Lake City", "UT", 84119, "EOD", 2),
|
||||||
|
DeliveryObject(18, "1488 4800 S", "Salt Lake City", "UT", 84123, "EOD", 6, "Can only be on truck 2"),
|
||||||
|
DeliveryObject(19, "177 W Price Ave", "Salt Lake City", "UT", 84115, "EOD", 37),
|
||||||
|
DeliveryObject(20, "3595 Main St", "Salt Lake City", "UT", 84115, "10:30 AM", 37, "Must be delivered with 13, 15"),
|
||||||
|
DeliveryObject(21, "3595 Main St", "Salt Lake City", "UT", 84115, "EOD", 3),
|
||||||
|
DeliveryObject(22, "6351 South 900 East", "Murray", "UT", 84121, "EOD", 2),
|
||||||
|
DeliveryObject(23, "5100 South 2700 West", "Salt Lake City", "UT", 84118, "EOD", 5),
|
||||||
|
DeliveryObject(24, "5025 State St", "Murray", "UT", 84107, "EOD", 7),
|
||||||
|
DeliveryObject(25, "5383 South 900 East #104", "Salt Lake City", "UT", 84117, "10:30 AM", 7, "Delayed on flight---will not arrive to depot until 9:05 am"),
|
||||||
|
DeliveryObject(26, "5383 South 900 East #104", "Salt Lake City", "UT", 84117, "EOD", 25),
|
||||||
|
DeliveryObject(27, "1060 Dalton Ave S", "Salt Lake City", "UT", 84104, "EOD", 5),
|
||||||
|
DeliveryObject(28, "2835 Main St", "Salt Lake City", "UT", 84115, "EOD", 7, "Delayed on flight---will not arrive to depot until 9:05 am"),
|
||||||
|
DeliveryObject(29, "1330 2100 S", "Salt Lake City", "UT", 84106, "10:30 AM", 2),
|
||||||
|
DeliveryObject(30, "300 State St", "Salt Lake City", "UT", 84103, "10:30 AM", 1),
|
||||||
|
DeliveryObject(31, "3365 S 900 W", "Salt Lake City", "UT", 84119, "10:30 AM", 1),
|
||||||
|
DeliveryObject(32, "3365 S 900 W", "Salt Lake City", "UT", 84119, "EOD", 1, "Delayed on flight---will not arrive to depot until 9:05 am"),
|
||||||
|
DeliveryObject(33, "2530 S 500 E", "Salt Lake City", "UT", 84106, "EOD", 1),
|
||||||
|
DeliveryObject(34, "4580 S 2300 E", "Holladay", "UT", 84117, "10:30 AM", 2),
|
||||||
|
DeliveryObject(35, "1060 Dalton Ave S", "Salt Lake City", "UT", 84104, "EOD", 88),
|
||||||
|
DeliveryObject(36, "2300 Parkway Blvd", "West Valley City", "UT", 84119, "EOD", 88, "Can only be on truck 2"),
|
||||||
|
DeliveryObject(37, "410 S State St", "Salt Lake City", "UT", 84111, "10:30 AM", 2),
|
||||||
|
DeliveryObject(38, "410 S State St", "Salt Lake City", "UT", 84111, "EOD", 9, "Can only be on truck 2"),
|
||||||
|
DeliveryObject(39, "2010 W 500 S", "Salt Lake City", "UT", 84104, "EOD", 9),
|
||||||
|
DeliveryObject(40, "380 W 2880 S", "Salt Lake City", "UT", 84115, "10:30 AM", 45)
|
||||||
|
]
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import datetime
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
# This is just a DataType to store the package info
|
||||||
|
class DeliveryObject:
|
||||||
|
def __init__(self, id: str, address: str, city: str, state: str, zip: str, deadline: str, weight: float, specialNotes=""):
|
||||||
|
self.id: str = id
|
||||||
|
self.truckId = -1
|
||||||
|
self.deliveryNumber = 0
|
||||||
|
self.address: str = address
|
||||||
|
self.city: str = city
|
||||||
|
self.state: str = state
|
||||||
|
self.zipCode: str = zip
|
||||||
|
self.packageWeight: float = weight
|
||||||
|
self.notes = specialNotes
|
||||||
|
self.status: deliveryStatus = deliveryStatus.NO_STATUS
|
||||||
|
self.deadline: datetime.time = deadline
|
||||||
|
self.timeStart: datetime.time = None
|
||||||
|
self.timeEnd: datetime.time = None
|
||||||
|
if deadline != "EOD":
|
||||||
|
parts = deadline.replace(':', ' ').split()
|
||||||
|
self.deadline = datetime.time(int(parts[0]), int(parts[1]))
|
||||||
|
else:
|
||||||
|
self.deadline = datetime.time(23,59)
|
||||||
|
|
||||||
|
|
||||||
|
class deliveryStatus(Enum):
|
||||||
|
NO_STATUS = 0
|
||||||
|
AT_THE_HUB = 1
|
||||||
|
IN_ROUTE = 2
|
||||||
|
DELIVERED = 3
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
from MyLinkedList import DerekLinkedList
|
||||||
|
|
||||||
|
class DerekHashTable:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.backingStore = [DerekLinkedList() for _ in range(36)] # Create a linked list backing for the hash table
|
||||||
|
self.count = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for linkedList in self.backingStore: # Look at each linked list
|
||||||
|
for data in linkedList: # Look at each item in the linked list
|
||||||
|
yield data # Return the data from each cell
|
||||||
|
|
||||||
|
def _calcHash(self, key) -> int: # Use the built in hash function
|
||||||
|
return hash(key) % 36 # Modulo the size of the hash array
|
||||||
|
|
||||||
|
def addItem(self, key, value):
|
||||||
|
i = self._calcHash(key) # Calculate a hash/modulo and put in the correct list
|
||||||
|
self.backingStore[i].append(key, value)
|
||||||
|
self.count += 1
|
||||||
|
|
||||||
|
def getItem(self, key):
|
||||||
|
i = self._calcHash(key) # Calculate the hash/modulo to get the data from the linked list
|
||||||
|
return self.backingStore[i].get(key)
|
||||||
|
|
||||||
|
def remItem(self, key):
|
||||||
|
i = self._calcHash(key) # Calculate the hash/modulo to get the list
|
||||||
|
self.backingStore[i].remove(key) # Remove the item from the list
|
||||||
|
self.count -= 1
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# This is the node definition. Allowing each 'chain link' to hold data and point to the next
|
||||||
|
class DerekLinkedListNode:
|
||||||
|
def __init__(self, key, item) -> None:
|
||||||
|
self.key = key
|
||||||
|
self.data = item
|
||||||
|
self.next: DerekLinkedListNode | None = None
|
||||||
|
|
||||||
|
# This is the real meat of the linked list
|
||||||
|
class DerekLinkedList:
|
||||||
|
# On init point to the first node and hold the total length
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.head: DerekLinkedListNode | None = None
|
||||||
|
self.len: int = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
current = self.head # Set the head of the linked list
|
||||||
|
while current: # if the value exists
|
||||||
|
yield current.data # return the data
|
||||||
|
current = current.next # set the next link
|
||||||
|
|
||||||
|
# Appends an item to the end of the list
|
||||||
|
def append(self, key, item) -> None:
|
||||||
|
self.len += 1 # update the overall length
|
||||||
|
newNode = DerekLinkedListNode(key, item) # create the node to insert
|
||||||
|
if not self.head: # if the head doesnt exist
|
||||||
|
self.head = newNode # set the head as the node and return
|
||||||
|
return
|
||||||
|
cur = self.head # if the head exists set cur to the next node
|
||||||
|
while cur.next: # loop through the rest of the chain looking for the end
|
||||||
|
cur = cur.next
|
||||||
|
cur.next = newNode # add the new node to the end
|
||||||
|
|
||||||
|
# Removes an item at the index
|
||||||
|
def remove(self, key) -> None:
|
||||||
|
lastNode = self.head # previous node
|
||||||
|
curNode = self.head # current node
|
||||||
|
while key != curNode.key: # get to the node we are curious about
|
||||||
|
lastNode = curNode
|
||||||
|
if curNode.next == None:
|
||||||
|
return None
|
||||||
|
curNode = curNode.next
|
||||||
|
if curNode == self.head:
|
||||||
|
self.head = curNode.next
|
||||||
|
else:
|
||||||
|
lastNode.next = curNode.next # pull the current node out of the linked list
|
||||||
|
self.len -= 1 # remove the length by 1
|
||||||
|
|
||||||
|
# returns the data at the index
|
||||||
|
def get(self, key):
|
||||||
|
if self.head: # if the head exists
|
||||||
|
cur: DerekLinkedListNode | None = self.head # set the current searching for at the head
|
||||||
|
while key != cur.key: # go through the chain until we hit the index were looking for
|
||||||
|
if cur.next == None:
|
||||||
|
return
|
||||||
|
cur = cur.next
|
||||||
|
if isinstance(cur, DerekLinkedListNode): # since we made it here the data were on is a LinkedListNode
|
||||||
|
return cur.data # return the value out of the node
|
||||||
|
else:
|
||||||
|
return None
|
||||||
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,91 @@
|
|||||||
|
import sys
|
||||||
|
import AssignmentData
|
||||||
|
import datetime
|
||||||
|
from MyHashTable import DerekHashTable
|
||||||
|
from DeliveryObject import DeliveryObject
|
||||||
|
from DeliveryObject import deliveryStatus
|
||||||
|
|
||||||
|
class Truck:
|
||||||
|
def __init__(self, truckId: str):
|
||||||
|
self.id = truckId # This trucks ID
|
||||||
|
self.packages: list[DeliveryObject] = [] # The packages on the truck
|
||||||
|
self.hasLoad: bool = False # Status of if the truck was loaded
|
||||||
|
self.mileage = 0.0 # Mileage counter
|
||||||
|
self.deliveryCounter = 0 # Keep track of the delivery counter
|
||||||
|
self.current_location = "HUB" # Current location of the truck
|
||||||
|
self.speed = 18 # Set from the project instructions
|
||||||
|
self.startTime: datetime.time | None = None # The trucks start time
|
||||||
|
|
||||||
|
def addPkg(self, pkg: DeliveryObject): # Adds a package to the truck
|
||||||
|
if len(self.packages) < 16: # Check if we can fit another package
|
||||||
|
pkg.timeStart = self.getTimeOfDay() # Set the start time for the pkg
|
||||||
|
pkg.truckId = self.id # Set the truck ID for the end menu
|
||||||
|
pkg.status = deliveryStatus.IN_ROUTE # The package is on the truck
|
||||||
|
self.packages.append(pkg) # Add the package
|
||||||
|
else:
|
||||||
|
print("to many packages loaded on the truck") # If there are too many packages
|
||||||
|
sys.exit() # Crash the program
|
||||||
|
|
||||||
|
def getDriveTime(self) -> int: # Usefull outside this class
|
||||||
|
hourPercent = self.mileage / self.speed # Calculate the hour percentage
|
||||||
|
rounededMin = int(60 * hourPercent) # Average that into minutes
|
||||||
|
return rounededMin
|
||||||
|
|
||||||
|
def getTimeOfDay(self) -> datetime.time: # Get the time of day using offsets
|
||||||
|
truckStartMins = (self.startTime.hour * 60) + self.startTime.minute # Get the minutes past midnight when the truck left
|
||||||
|
offsetMinutes = truckStartMins + self.getDriveTime() # Add on the number of minutes the truck as been driving
|
||||||
|
pkgHours = (offsetMinutes // 60) % 24 # pull hours back out
|
||||||
|
pkgMins = offsetMinutes % 60 # pull minutes back out
|
||||||
|
return datetime.time(pkgHours, pkgMins) # return the time of day
|
||||||
|
|
||||||
|
def deliverPkgs(self): # Delivers any packeges that match the current location
|
||||||
|
for i in range(len(self.packages) - 1, -1, -1): # Loop backwards so removals dont index shift
|
||||||
|
if self.packages[i].address in self.current_location: # Check if the package is at the correct address
|
||||||
|
self.packages[i].status = deliveryStatus.DELIVERED # Mark as delivered
|
||||||
|
self.packages[i].timeEnd = self.getTimeOfDay() # Mark the delivered time
|
||||||
|
self.deliveryCounter += 1 # Incriment the delivery counter
|
||||||
|
self.packages[i].deliveryNumber = self.deliveryCounter # Mark the package number
|
||||||
|
self.packages.remove(self.packages[i]) # Remove the package from the truck
|
||||||
|
|
||||||
|
def getMatrixIndex(self, address_string: str) -> int: # Helper function to get x or y offset in the distance table
|
||||||
|
for i, full_name in enumerate(AssignmentData.xyNames2): # Loop through the names in the list
|
||||||
|
if address_string in full_name: # Check if the name matches
|
||||||
|
return i # Return the index
|
||||||
|
for i, full_name in enumerate(AssignmentData.xyNames): # Loop through the names in the list
|
||||||
|
if address_string in full_name: # Check if the name matches
|
||||||
|
return i # Return the index
|
||||||
|
print(f"Address {address_string} is not in Full List") # Report items not found in the list
|
||||||
|
return 0 # Default to Hub if not found
|
||||||
|
|
||||||
|
def driveNextClosest(self, priority: DerekHashTable) -> int: # The bread and butter of the algorithm
|
||||||
|
# deal with priority
|
||||||
|
priorityPkgs = [] # set the packages we currently want to look for
|
||||||
|
for cur in self.packages: # loop thorugh looking for priority matches
|
||||||
|
if priority.getItem(cur.id):
|
||||||
|
priorityPkgs.append(cur) # if a priority matches add it to the list
|
||||||
|
if not priorityPkgs: # if no priority matches just use the normal
|
||||||
|
priorityPkgs = self.packages
|
||||||
|
|
||||||
|
# get the next closest
|
||||||
|
shortest_dist = float('inf') # Start with a very long distance to work backwards from
|
||||||
|
next_pkg = None # Keep track of the closest pkg
|
||||||
|
|
||||||
|
current_idx = self.getMatrixIndex(self.current_location) # Get the trucks xyIndex
|
||||||
|
for pkg in priorityPkgs: # Loop through the packages
|
||||||
|
dest_idx = self.getMatrixIndex(pkg.address) # Get the package xyIndex
|
||||||
|
|
||||||
|
row = max(current_idx, dest_idx) # Becuase the distance table is a triange
|
||||||
|
col = min(current_idx, dest_idx) # Keep on the buttom left side
|
||||||
|
dist = AssignmentData.distanceChart[row][col] # Get the distance from the grid
|
||||||
|
|
||||||
|
if dist < shortest_dist: # If the distance is shorter than the one found
|
||||||
|
shortest_dist = dist # Update the distance and package
|
||||||
|
next_pkg = pkg
|
||||||
|
|
||||||
|
# drive
|
||||||
|
self.mileage += shortest_dist # Add this shortest distance to the truck
|
||||||
|
self.current_location = next_pkg.address # update the location
|
||||||
|
self.deliverPkgs() # deliver packages at this location
|
||||||
|
if len(self.packages) == 0: # if there is no packages
|
||||||
|
self.hasLoad = False # Set the load to empty
|
||||||
|
return len(self.packages) # return packages left to deliver
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
import datetime
|
||||||
|
|
||||||
|
class DataUI:
|
||||||
|
|
||||||
|
# Filter for selections that allow
|
||||||
|
def selectionChooser(self, fullList):
|
||||||
|
print("Please make a selection")
|
||||||
|
print(" [1]: Show all ")
|
||||||
|
print(" [2]: Show per truck")
|
||||||
|
print(" [3]: Show package")
|
||||||
|
SubMenuTreeSelection = input("")
|
||||||
|
selection = []
|
||||||
|
if "1" in SubMenuTreeSelection:
|
||||||
|
selection = fullList
|
||||||
|
if "2" in SubMenuTreeSelection:
|
||||||
|
print("Choose a truck ID [1,2,3]")
|
||||||
|
choice = input("")
|
||||||
|
for pkg in fullList:
|
||||||
|
if choice in pkg.truckId:
|
||||||
|
selection.append(pkg)
|
||||||
|
if "3" in SubMenuTreeSelection:
|
||||||
|
print("Choose a package ID [0..39]")
|
||||||
|
choice = input("")
|
||||||
|
for pkg in fullList:
|
||||||
|
if choice == str(pkg.id):
|
||||||
|
selection.append(pkg)
|
||||||
|
return selection
|
||||||
|
|
||||||
|
# Shows information about trucks
|
||||||
|
def Trucks(self, truck1, truck2, truck3):
|
||||||
|
trucks = [truck1, truck2, truck3]
|
||||||
|
print("")
|
||||||
|
for i,v in enumerate(trucks):
|
||||||
|
startTime = "Pending"
|
||||||
|
endTime = "Pending"
|
||||||
|
if v.startTime != None:
|
||||||
|
startTime = v.startTime.strftime('%H:%M')
|
||||||
|
if v.packages.count == 0:
|
||||||
|
endTime = v.getTimeOfDay().strftime('%H:%M')
|
||||||
|
|
||||||
|
print(f"Truck [{v.id}] | "
|
||||||
|
f"Mileage: {v.mileage:.2f} | "
|
||||||
|
f"Departure: {startTime} | "
|
||||||
|
f"Arrival: {endTime} | "
|
||||||
|
f"DriveTime: {v.getDriveTime()} mintes")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Shows information about packages
|
||||||
|
def Packages(self, package_hash):
|
||||||
|
selection = self.selectionChooser(package_hash)
|
||||||
|
print("")
|
||||||
|
for i,v in enumerate(selection):
|
||||||
|
print(f"[{v.id:2}] | "
|
||||||
|
f"[DeliveryNumber]: {v.deliveryNumber:2} | "
|
||||||
|
f"[onTruck]: {v.truckId:2} | "
|
||||||
|
f"[Address]: {v.address[:20]:20} | "
|
||||||
|
f"[Status]: {v.status:10} | "
|
||||||
|
f"[Note]: {v.notes:10}")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Shows information about delivery times and deadlines
|
||||||
|
def DeliveryTime(self, package_hash):
|
||||||
|
selection = self.selectionChooser(package_hash)
|
||||||
|
print("")
|
||||||
|
for i,v in enumerate(selection):
|
||||||
|
deadline = v.deadline
|
||||||
|
metDeadline = "False"
|
||||||
|
if isinstance(v.deadline, datetime.time):
|
||||||
|
deadline = v.deadline.strftime('%H:%M')
|
||||||
|
if v.timeStart != None and v.timeEnd != None:
|
||||||
|
if v.timeEnd <= v.deadline:
|
||||||
|
metDeadline = "True"
|
||||||
|
if v.deadline == datetime.time(23,59):
|
||||||
|
deadline = "EOD"
|
||||||
|
startTime = "Pending"
|
||||||
|
if v.timeStart != None:
|
||||||
|
startTime = v.timeStart.strftime('%H:%M')
|
||||||
|
endTime = "Pending"
|
||||||
|
if v.timeEnd != None:
|
||||||
|
endTime = v.timeEnd.strftime('%H:%M')
|
||||||
|
print(f"[{v.id:2}] | "
|
||||||
|
f"[StartTime]: {startTime:8} | "
|
||||||
|
f"[DelivedTime]: {endTime:8} | "
|
||||||
|
f"[Deadline]: {deadline:8} | "
|
||||||
|
f"[MetDeadline]: {metDeadline:5} | "
|
||||||
|
f"[Note]: {v.notes:10}")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Main prompt for the UI
|
||||||
|
def MainSelectionPrompt(self, truck1, truck2, truck3, package_hash):
|
||||||
|
while True:
|
||||||
|
print("Please make a selection")
|
||||||
|
print(" [1]: Show stats for trucks")
|
||||||
|
print(" [2]: Show stats for packages")
|
||||||
|
print(" [3]: Check delivery times")
|
||||||
|
print(" [4]: Total Mileage for trucks")
|
||||||
|
print(" [5]: Cancel")
|
||||||
|
MenuTreeSelection = input("")
|
||||||
|
if "1" in MenuTreeSelection:
|
||||||
|
self.Trucks(truck1, truck2, truck3)
|
||||||
|
elif "2" in MenuTreeSelection:
|
||||||
|
self.Packages(package_hash)
|
||||||
|
elif "3" in MenuTreeSelection:
|
||||||
|
self.DeliveryTime(package_hash)
|
||||||
|
elif "4" in MenuTreeSelection:
|
||||||
|
totalDistance = truck1.mileage + truck2.mileage + truck3.mileage
|
||||||
|
print(f"\nTotal Mileage for all trucks: {totalDistance:.2f} miles\n")
|
||||||
|
elif "5" in MenuTreeSelection:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Prompt for pausing the simulation and opening the menu for stats at specific times
|
||||||
|
def TimePrompt(self, currentTime: datetime.time, truck1, truck2, truck3, package_hash) -> datetime.time:
|
||||||
|
while True:
|
||||||
|
print(" [1]: Pause the simulation at a point in time")
|
||||||
|
print(" [2]: Run the simulation to the end")
|
||||||
|
print(" [3]: View stats for this moment in time")
|
||||||
|
|
||||||
|
selectionInput = input("")
|
||||||
|
if "1" in selectionInput:
|
||||||
|
while True:
|
||||||
|
print("Please input a time in format of [hh:mm] or type 'back' to return to menu")
|
||||||
|
timeInput = input("")
|
||||||
|
|
||||||
|
if timeInput.lower() == 'back':
|
||||||
|
break
|
||||||
|
|
||||||
|
try:
|
||||||
|
time = timeInput.split(":")
|
||||||
|
hour = int(time[0])
|
||||||
|
minute = int(time[1])
|
||||||
|
|
||||||
|
chosenTime = datetime.time(hour, minute)
|
||||||
|
if chosenTime > currentTime:
|
||||||
|
print(f"Simulation set to pause at {hour:02}:{minute:02}")
|
||||||
|
return chosenTime
|
||||||
|
else:
|
||||||
|
print(f"Error: Time must be later than {currentTime.strftime('%H:%M')}.")
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
print(f"Invalid format '{timeInput}'. Use HH:MM (e.g., 10:30).")
|
||||||
|
elif "2" in selectionInput:
|
||||||
|
print("Running simulation until the end of the day.")
|
||||||
|
return datetime.time(23, 59)
|
||||||
|
elif "3" in selectionInput:
|
||||||
|
self.MainSelectionPrompt(truck1, truck2, truck3, package_hash)
|
||||||
|
else:
|
||||||
|
print("Invalid selection. Please choose 1, 2, or 3.")
|
||||||
Binary file not shown.
@@ -0,0 +1,128 @@
|
|||||||
|
# Derek Holloway 010396173
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import AssignmentData
|
||||||
|
import UI
|
||||||
|
from MyHashTable import DerekHashTable
|
||||||
|
from Truck import Truck
|
||||||
|
from DeliveryObject import deliveryStatus
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
UserUI = UI.DataUI() # Load in the UI library
|
||||||
|
globalTime = datetime.time(8, 0)
|
||||||
|
|
||||||
|
package_hash = DerekHashTable() # Init the hash table
|
||||||
|
for pkg in AssignmentData.packages: # Load the packages into the hash table
|
||||||
|
pkg.status = deliveryStatus.AT_THE_HUB
|
||||||
|
package_hash.addItem(pkg.id, pkg)
|
||||||
|
|
||||||
|
truck1 = Truck("1") # Init truck 1 starting at 8:00
|
||||||
|
truck1.startTime = datetime.time(8, 0)
|
||||||
|
|
||||||
|
truck2 = Truck("2") # Init truck 2 starting at 9:15 -> Delayed for package 6
|
||||||
|
truck2.startTime = datetime.time(9, 5)
|
||||||
|
|
||||||
|
truck3 = Truck("3") # Init truck 3 starting as soon as the fastest truck returned
|
||||||
|
truck3.startTime = None
|
||||||
|
|
||||||
|
pauseTime = UserUI.TimePrompt(globalTime, truck1, truck2, truck3, package_hash) # start the first time prompt
|
||||||
|
|
||||||
|
noRequirements = [1,2,4,5,7,8,10,11,12,17,21,22,23,24,26,27,29,30,31,33,34,35,37,39,40]
|
||||||
|
truck2Only = [3,18,36,38]
|
||||||
|
delayed = [6,9,25,28,32]
|
||||||
|
sameTruck = [13,14,15,16,19,20]
|
||||||
|
|
||||||
|
# Package requirements
|
||||||
|
priority = [1,6,13,14,15,16,21,25,29,30,31,34,37,40]
|
||||||
|
priority_hash = DerekHashTable() # Load the priority packages into a hash for quick lookup
|
||||||
|
for cur in priority:
|
||||||
|
priority_hash.addItem(cur, cur)
|
||||||
|
|
||||||
|
# Sort the known packages
|
||||||
|
t1_load = sameTruck # Start with the packages that requrie the same truck
|
||||||
|
t2_load = truck2Only + delayed # add in the truck 2 only and the delays
|
||||||
|
t3_load = [] # create an empty list
|
||||||
|
|
||||||
|
# Sort the Unknown packages
|
||||||
|
for i, v in enumerate(noRequirements): # enumerate through all the packages not predefined
|
||||||
|
if priority_hash.getItem(v): # if the item is a priority item
|
||||||
|
if len(t1_load) < 16: # load priorities on truck 1 first as it leaves earlier
|
||||||
|
t1_load.append(v)
|
||||||
|
elif len(t2_load) < 16: # fallback to truck 2
|
||||||
|
t2_load.append(v)
|
||||||
|
else: # fallback again to truck 3
|
||||||
|
t3_load.append(v)
|
||||||
|
else:
|
||||||
|
if len(t3_load) < 16: # non priority pkgs default to truck 3 as it leaves last
|
||||||
|
t3_load.append(v)
|
||||||
|
elif len(t2_load) < 16: # fall back to truck 2
|
||||||
|
t2_load.append(v)
|
||||||
|
elif len(t1_load) < 16: # fallback again to truck 1
|
||||||
|
t1_load.append(v)
|
||||||
|
|
||||||
|
# Run the simulation until all the packages have been delivered
|
||||||
|
debounce1 = True
|
||||||
|
debounce2 = True
|
||||||
|
debounce3 = True
|
||||||
|
truck3LoadDebounce = True
|
||||||
|
while True:
|
||||||
|
|
||||||
|
# update global time
|
||||||
|
if globalTime >= datetime.time(10, 20): # If the time is correct for update
|
||||||
|
pkg9 = package_hash.getItem(9) # Handle the Package #9 address correction before Truck 3 starts
|
||||||
|
pkg9.address = "410 S State St"
|
||||||
|
|
||||||
|
# load packages for truck 1
|
||||||
|
if globalTime >= truck1.startTime and debounce1: # If its time to laod the packages, run once
|
||||||
|
debounce1 = False # set debounce for only one run
|
||||||
|
truck1.hasLoad = True # Set the truck load variable
|
||||||
|
for pkg_id in t1_load: # Load the packages in truck 1
|
||||||
|
truck1.addPkg(package_hash.getItem(pkg_id))
|
||||||
|
|
||||||
|
# load packages for truck 2
|
||||||
|
if globalTime >= truck2.startTime and debounce2: # If its time to laod the packages, run once
|
||||||
|
debounce2 = False # set debounce for only one run
|
||||||
|
truck2.hasLoad = True # Set the truck load variable
|
||||||
|
for pkg_id in t2_load: # Load the packages in truck 2
|
||||||
|
truck2.addPkg(package_hash.getItem(pkg_id))
|
||||||
|
|
||||||
|
# load packages for truck 3
|
||||||
|
if globalTime >= truck3.startTime and debounce3: # If its time to laod the packages, run once
|
||||||
|
debounce3 = False # set debounce for only one run
|
||||||
|
truck2.hasLoad = True # Set the truck load variable
|
||||||
|
for pkg_id in t2_load: # Load the packages in truck 2
|
||||||
|
truck2.addPkg(package_hash.getItem(pkg_id))
|
||||||
|
|
||||||
|
# deliver packages for truck 1
|
||||||
|
if truck1.hasLoad and globalTime >= truck1.getTimeOfDay(): # if there is more packages and the time has passed
|
||||||
|
packagesLeft = truck1.driveNextClosest(priority_hash) # deliver the next set of packages
|
||||||
|
if packagesLeft == 0 and truck3LoadDebounce: # if all the packages are delivered
|
||||||
|
truck3LoadDebounce = False # set the debouce
|
||||||
|
truck3.startTime = truck1.getTimeOfDay() # set truck3 start time
|
||||||
|
|
||||||
|
# deliver packages for truck 2
|
||||||
|
if truck2.hasLoad and globalTime >= truck2.getTimeOfDay(): # if there is more packages and the time has passed
|
||||||
|
packagesLeft = truck2.driveNextClosest(priority_hash) # deliver the next set of packages
|
||||||
|
if packagesLeft == 0 and truck3LoadDebounce: # if all the packages are delivered
|
||||||
|
truck3LoadDebounce = False # set the debouce
|
||||||
|
truck3.startTime = truck1.getTimeOfDay() # set truck3 start time
|
||||||
|
|
||||||
|
# deliver packages for truck 3
|
||||||
|
if truck3.hasLoad and globalTime >= truck3.getTimeOfDay(): # if there is more packages and the time has passed
|
||||||
|
truck3.driveNextClosest(priority_hash) # deliver the next set of packages
|
||||||
|
|
||||||
|
# Calculate new global time
|
||||||
|
totalMins = (globalTime.hour * 60) + globalTime.minute + 5 # Get total mins and add 30
|
||||||
|
offsetHour = (totalMins // 60) % 24 # pull hours back out
|
||||||
|
offsetMins = totalMins % 60 # pull minutes back out
|
||||||
|
globalTime = datetime.time(offsetHour, offsetMins) # return the time of day
|
||||||
|
|
||||||
|
# if we are done delivering
|
||||||
|
if (truck3.hasLoad == False and truck2.hasLoad == False and truck1.hasLoad == False):
|
||||||
|
break
|
||||||
|
|
||||||
|
UserUI.MainSelectionPrompt(truck1, truck2, truck3, package_hash) # Display the command prompt Menus
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user