-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
288 lines (235 loc) · 12.2 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# Teksong Eap, WGU ID:009489418
import csv
from datetime import datetime, timedelta
from HashTable import HashTable
from Package import Package
from Truck import Truck
# PACKAGE HANDLING
# loud package data
def load_package_data(hash_table):
with open('packageData.csv', 'r') as file: # get from package data
csv_reader = csv.reader(file, delimiter=',')
for row in csv_reader:
package_id = int(row[0])
address = row[1]
city = row[2]
state = row[3]
zip_code = row[4]
deadline = row[5]
kilo = row[6]
notes = row[7]
# create new package object with ALL data points
package = Package(package_id, address, city, state, zip_code, deadline, kilo, notes)
hash_table.insert(package.package_id, package)
package_hash_table = HashTable()
load_package_data(package_hash_table)
# ADDRESS HANDLING
# load address data
def load_address_data():
with open('addressData.csv', 'r', encoding='utf-8-sig') as file:
csv_reader = csv.reader(file, delimiter=',')
addresses = [row[1] for row in csv_reader] # Get the address from each row
return addresses
# DISTANCE HANDLING
# load distance data that is a triangular matrix
def load_distance_data():
# Determine the size of the matrix
with open('distanceData.csv', 'r', encoding='utf-8-sig') as file:
num_addresses = sum(1 for row in file)
# Create a zero-filled matrix of the right size
distance_matrix = [[0] * num_addresses for _ in range(num_addresses)]
# Fill the matrix with actual distances (making the triangle a square)
with open('distanceData.csv', 'r', encoding='utf-8-sig') as file:
csv_reader = csv.reader(file, delimiter=',')
for i, row in enumerate(csv_reader):
for j, value in enumerate(row):
if value: # Only convert non-empty strings
distance_matrix[i][j] = float(value)
distance_matrix[j][i] = float(value)
return distance_matrix
# get distance between two addresses within matrix
def distance_between(from_address, to_address, addresses, distances):
# Get the indices of the two addresses
index1 = addresses.index(from_address)
index2 = addresses.index(to_address)
# Return the distance between them
return distances[index1][index2]
# Load the distance data
distance_matrix = load_distance_data()
# Load the address data
address_list = load_address_data()
# PACKAGE LOADING
# load truck 1 manually
def load_truck1(truck1, hash_table):
packages_to_load = [1, 4, 5, 13, 14, 15, 16, 19, 20, 21, 29, 30, 31, 34, 39, 40]
for i in packages_to_load:
package = hash_table.lookup(i)
truck1.add_package(package)
# load truck 2 manually
def load_truck2(truck2, hash_table):
packages_to_load = [2, 3, 6, 7, 10, 11, 12, 17, 18, 25, 28, 32, 35, 36, 37, 38]
for i in packages_to_load:
package = hash_table.lookup(i)
truck2.add_package(package)
# load truck 3 manually
def load_truck3(truck3, hash_table):
packages_to_load = [8, 22, 23, 24, 26, 27, 33]
for i in packages_to_load:
package = hash_table.lookup(i)
truck3.add_package(package)
start_time = datetime.strptime('08:00:00', '%H:%M:%S') # Example start time
delayed_time = datetime.strptime('09:05:00', '%H:%M:%S')
# TRUCK HANDLING
truck1 = Truck(1, 18, start_time, start_time)
truck2 = Truck(2, 18, delayed_time, delayed_time)
truck3 = Truck(3, 18, None, None)
# load the previous ids to keep track of loaded packages
load_truck1(truck1, package_hash_table)
load_truck2(truck2, package_hash_table)
load_truck3(truck3, package_hash_table)
# simulate delivery of the packages using greedy algorithm with time complexity n^2
def deliver_packages(truck, addresses, distances):
current_location = truck.current_location
# Mark all packages on the truck as 'En route'
# for package in truck.packages:
# package.update_status("En route")
while truck.packages:
# Find the nearest unvisited package
nearest_distance = float('inf')
nearest_package = None
for package in truck.packages:
distance = distance_between(current_location, package.address, addresses, distances)
if distance < nearest_distance:
nearest_distance = distance
nearest_package = package
# Update the truck's and package's details
truck.add_distance(nearest_distance)
hours_traveled = nearest_distance / truck.speed
truck.current_time += timedelta(hours=hours_traveled)
nearest_package.delivery_time = truck.current_time.strftime('%H:%M:%S')
truck.deliver_package(nearest_package)
current_location = nearest_package.address
# Return to the hub and update the distance and time
distance_to_hub = distance_between(current_location, '4001 South 700 East', addresses, distances)
truck.add_distance(distance_to_hub)
hours_traveled = distance_to_hub / truck.speed
truck.current_time += timedelta(hours=hours_traveled)
# SIMULATE DELIVERY
deliver_packages(truck1, address_list, distance_matrix)
# print(truck1.total_distance)
deliver_packages(truck2, address_list, distance_matrix)
# print(truck2.total_distance)
# The correct address for package 9 has magically appeared!
truck3.current_time = datetime.strptime('10:20:00', '%H:%M:%S')
truck3.depart_time = datetime.strptime('10:20:00', '%H:%M:%S')
package = package_hash_table.lookup(9)
package.address = '410 S State St'
truck3.add_package(package)
deliver_packages(truck3, address_list, distance_matrix)
# Command line interface options and such
def show_menu():
print("****************************************************************************")
print("1. Show status of all packages for a specific time.")
print("2. Get a single package's status with a time.")
print("3. Show total mileage traveled by all trucks and status of packages at EOD.")
print("4. Exit the program.")
print("****************************************************************************")
# shows all package statuses with time info according to specified time (simulated)
def show_all_packages_status_for_time(time, trucks):
time_obj = datetime.strptime(time, '%H:%M:%S')
for truck in trucks:
print(f"\nTruck {truck.id} Status at {time}:")
for package in truck.all_packages:
package_status = package.status
status_time_str = time # Default to the provided time for non-delivered packages
# Check if package has id of 9
if package.package_id == 9 and datetime.strptime('10:20:00', '%H:%M:%S') > time_obj:
print(
f"Package ID: {package.package_id}, Address: 300 State St (wrong address), "
f"City: {package.city}, Zipcode: {package.zip_code}, Deadline: {package.delivery_deadline}, "
f"Weight: {package.weight_kilo}, Status: {package_status} at {status_time_str}, \n"
f"Address for Package ID: {package.package_id} will be corrected at 10:20 AM")
else:
# Check if the truck has not yet departed and or package delayed
if time_obj < truck.depart_time and "Delayed" in package.special_notes:
package_status = "Delayed"
elif time_obj < truck.depart_time:
package_status = "At Hub"
else: # Show delivered if time is at or after delivery time
if package.delivery_time and datetime.strptime(package.delivery_time, '%H:%M:%S') <= time_obj:
package_status = "Delivered"
status_time_str = package.delivery_time
elif package.delivery_time and datetime.strptime(package.delivery_time, '%H:%M:%S') > time_obj:
package_status = "En route" # Show en route if time is before delivery time
print(
f"Package ID: {package.package_id}, Address: {package.address}, City: {package.city}, "
f"Zipcode: {package.zip_code}, Deadline: {package.delivery_deadline}, "
f"Weight: {package.weight_kilo}, Status: {package_status} at {status_time_str}")
# shows single package status with time info according to specified time (simulated)
def get_single_package_status(package_id, time, trucks):
time_obj = datetime.strptime(time, '%H:%M:%S')
package_found = 0
for truck in trucks:
for package in truck.all_packages:
if package.package_id == package_id:
package_found = 1
package_status = package.status
status_time_str = time # Default to the provided time for non-delivered packages
# Check if the truck has not yet departed and or package delayed
if package.package_id == 9 and datetime.strptime('10:20:00', '%H:%M:%S') > time_obj:
print(
f"Package ID: {package.package_id}, Address: 300 State St (wrong address), "
f"City: {package.city}, Zipcode: {package.zip_code}, Deadline: {package.delivery_deadline}, "
f"Weight: {package.weight_kilo}, Status: {package_status} at {status_time_str}, \n"
f"Address for Package ID: {package.package_id} will be corrected at 10:20 AM")
else:
# Check if the truck has not yet departed and or package delayed
if time_obj < truck.depart_time and "Delayed" in package.special_notes:
package_status = "Delayed"
elif time_obj < truck.depart_time:
package_status = "At Hub"
else: # Show delivered if time is at or after delivery time
if package.delivery_time and datetime.strptime(package.delivery_time, '%H:%M:%S') <= time_obj:
package_status = "Delivered"
status_time_str = package.delivery_time
elif package.delivery_time and datetime.strptime(package.delivery_time, '%H:%M:%S') > time_obj:
package_status = "En route" # Show en route if time is before delivery time
print(
f"Package ID: {package.package_id}, Address: {package.address}, City: {package.city}, "
f"Zipcode: {package.zip_code}, Deadline: {package.delivery_deadline}, "
f"Weight: {package.weight_kilo}, Status: {package_status} at {status_time_str}")
# prints package not found if no package ID is found
if package_found == 0:
print("Package not found")
# shows all status of packages at end of day (simulated)
def show_total_mileage(trucks):
total_mileage = sum([truck.total_distance for truck in trucks])
print(f"Total mileage traveled by all trucks: {total_mileage} miles")
time_obj = datetime.strptime('17:00:00', '%H:%M:%S')
for truck in trucks:
print(f"\nTruck {truck.id} Status at EOD:")
for package in truck.all_packages:
if package.delivery_time and datetime.strptime(package.delivery_time, '%H:%M:%S') <= time_obj:
print(
f"Package ID: {package.package_id}, Address: {package.address}, "
f"City: {package.city}, Zipcode: {package.zip_code}, Deadline: {package.delivery_deadline}, "
f"Weight: {package.weight_kilo}, Status: Delivered at {package.delivery_time}")
def main():
while True:
show_menu()
choice = input("Enter your choice: ")
if choice == "1":
time = input("Enter the time in HH:MM:SS format: ")
show_all_packages_status_for_time(time, [truck1, truck2, truck3])
elif choice == "2":
package_id = int(input("Enter the package ID: "))
time = input("Enter the time in HH:MM:SS format: ")
get_single_package_status(package_id, time, [truck1, truck2, truck3])
elif choice == "3":
show_total_mileage([truck1, truck2, truck3])
elif choice == "4":
print("Exiting the program.")
break
else:
print("Invalid choice. Please try again.")
main()