You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

341 lines
11 KiB

import time, datetime, math
from copy import deepcopy
from enum import Enum
def now():
return datetime.datetime.now().timestamp()
class DroneState(Enum):
Grounded = 0
InTheAir = 1
WaitingForTakeOff = 2
class StopType(Enum):
City = 0
Factory = 1
class Position:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return(f"[{self.x}, {self.y}]")
class Drone:
def __init__(self, name, position, route, rate, capacity):
self.__name = name
self.__position = position
self.__route = route
self.__rate = rate # per second
self.__capacity = capacity
self.__cargo = {}
self.__state = DroneState.Grounded
self.__prevousStop = -1
self.__nextStop = 0
self.__lastDeparture = 0
self.__lastDeparturePosition = deepcopy(position)
def set_position(self, position):
self.__position = position
# returns how much was accepted from the load
def load_cargo(self, product, quantity):
cargoTotal = self.get_cargo_total()
if not product in self.__cargo:
self.__cargo[product] = 0
spaceRemaining = (self.__capacity - cargoTotal)
acceptedQuantity = quantity
# if the quantity is more than space remaining then just return the space remaining
if(quantity > spaceRemaining):
acceptedQuantity = spaceRemaining
self.__cargo[product] += acceptedQuantity
return acceptedQuantity
def get_cargo_total(self):
total = 0
for key in self.__cargo:
total += self.__cargo[key]
return total
def takeOff(self):
self.__state = DroneState.InTheAir
self.__lastDeparture = now()
self.__lastDeparturePosition = deepcopy(self.__position)
positionFound = False
for idx, stop in enumerate(self.__route.get_stops()):
stopPosition = stop.get_position()
if (stopPosition.x == self.__position.x) and (stopPosition.y == self.__position.y):
positionFound = True
self.__prevousStop = idx
# if the next stop is out of range, loop back home
if(idx + 1 == len(self.__route.get_stops())):
self.__nextStop = 0
else:
self.__nextStop = idx + 1
if(not positionFound):
self.__prevousStop = -1
self.__nextStop = 0
print(f"{self.__name}: Taking off from: {self.__position}")
else:
print(f"{self.__name}: Taking off from: {self.__route.get_stops()[self.__prevousStop]}")
def cargo_report(self):
str = ""
for product in self.__cargo:
str += f"{product}: {self.__cargo[product]}"
return
def update(self):
state = DroneState.Grounded.name
position = f"Position: {self.__position}"
prevousStop = self.__route.get_stops()[self.__prevousStop]
nextStop = self.__route.get_stops()[self.__nextStop]
# print cargo levels
print(f"{self.__name}: On Board {self.__cargo}")
# are we at a unknown location?
if(self.__prevousStop == -1):
location = self.__lastDeparturePosition
else:
location = prevousStop
# is the drone in the air?
if(self.__state == DroneState.Grounded):
print(f"{self.__name}: {state}: {location}")
elif(self.__state == DroneState.WaitingForTakeOff):
currentStop = prevousStop
print(f"{self.__name}: Waiting For Take Off: {location}")
# load cargo/receive_supplies if at a factory
if(currentStop.get_stop_type() == StopType.Factory):
print(f"{self.__name}: Loading Inventory")
products = currentStop.get_output_quantity()
for key in products:
acceptedQuantity = self.load_cargo(key, products[key])
# adjust inventory by accepted quantity
currentStop.update_inventory(-acceptedQuantity)
currentStop.receive_supplies(self.__cargo)
if(self.__nextTakeOff <= now()):
self.takeOff()
else:
print(f"{self.__name}: Traveling Between: {location} and {nextStop}")
# time in the air since take off
timeDifference = math.floor(now() - self.__lastDeparture)
x2 = float(nextStop.get_position().x)
y2 = float(nextStop.get_position().y)
if(self.__prevousStop == -1):
x1 = float(self.__lastDeparturePosition.x)
y1 = float(self.__lastDeparturePosition.y)
else:
x1 = prevousStop.get_position().x
y1 = prevousStop.get_position().y
#print(f"{self.__name}: {x1},{y1} -> {x2},{y2}")
# total distance: d=√((x2 – x1)² + (y2 – y1)²)
totalDistance = (math.sqrt(abs(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)))))
# d = rt
distanceTraveled = self.__rate * (now() - self.__lastDeparture)
#print(f"{self.__name}: Distance Traveled: {distanceTraveled}, Total Distance: {totalDistance}")
# slope m = (y2 - y1) / (x2 - x1)
if(x2 == x1):
m = 0
else:
m = (y2 - y1) / (x2 - x1)
travelingEast = x2 > x1
travelingNorth = y2 > y1
# if traveled the distance, ground the drone and update stops
if(distanceTraveled >= totalDistance):
# force position
self.__position.x = nextStop.get_position().x
self.__position.y = nextStop.get_position().y
self.__state = DroneState.WaitingForTakeOff
self.__nextTakeOff = now() + 5
self.__prevousStop = self.__nextStop
self.__nextStop += 1
# if next stop out of range, sent back to first stop
if(self.__nextStop >= len(self.__route.get_stops())):
self.__nextStop = 0
else:
# what percentage of the journey has passed?
per = (distanceTraveled/totalDistance)
# compute X
if(travelingEast):
x = x1 + ((x2 - x1) * per)
else:
x = x1 - ((x1 - x2) * per)
# compute y
if(m > 0):
# if there is a slope
#(y – y1) = m(x – x1)
y = (m * (x - x1)) + y1
else:
if(travelingNorth):
y = y1 + ((y2 - y1) * per)
else:
y = y1 - ((y1 - y2) * per)
# if no slope, either x or y is constant
if(x1 == x2):
x = x1
if(y1 == y2):
y = y1
self.__position.x = x
self.__position.y = y
print(f"{self.__name} {position}")
def get_state(self):
return self.__state
class Route:
def __init__(self, name, stops):
self.__name = name
self.__stops = stops
def get_stops(self):
return self.__stops
class Product():
def __init__(self, name):
self.__name = name
def __str__(self):
return f"{self.__name}"
def get_name(self):
return self.__name
class Stop:
def __init__(self, stopType, name, position):
self.__stopType = stopType
self.__name = name
self.__position = position
def __str__(self):
return f"{self.__name} {self.__position}"
def get_position(self):
return self.__position
def get_name(self):
return self.__name
def get_stop_type(self):
return self.__stopType
class Factory(Stop):
def __init__(self, name, position, product, buildRate, acceptedSupplies):
super().__init__(StopType.Factory, name, position)
#product name
self.__product = product
#build rate (units per second)
self.__buildRate = buildRate
#units ready to ship
self.__inventory = {product: 0}
#last time inventory was updated
self.__lastCheck = 0
#acceptedSupplies = products accepted by this factory
self.__acceptedSupplies = acceptedSupplies
# returns a dictionary of the product and inventory level
def get_output_quantity(self):
# only return finished goods
return {self.__product: math.floor(self.__inventory[self.__product])}
# adds to inventory level
def update_inventory(self, quantity):
self.__inventory[self.__product] += quantity
def update_supply_inventory(self, product, quantity):
if product not in self.__inventory:
self.__inventory[product] = 0
self.__inventory[product] += quantity
def receive_supplies(self, supplies):
for supply in supplies:
if supply in self.__acceptedSupplies:
self.update_supply_inventory(supply, supplies[supply])
def inventory_report(self):
str = f"{self.get_name()}: "
for product in self.__inventory:
str += f"{product}: {self.__inventory[product]} "
return str
# runs on timer tick
def update(self):
now = datetime.datetime.now().timestamp()
if(self.__lastCheck > 0):
timeDifference = (now - self.__lastCheck)
self.update_inventory(timeDifference * self.__buildRate)
print(self.inventory_report())
self.__lastCheck = datetime.datetime.now().timestamp()
chicago = Stop(StopType.City, "Chicago", Position(1, 45))
miami = Stop(StopType.City, "Miami", Position(50, 1))
newYork = Stop(StopType.City, "New York", Position(50, 50))
widget = Product("Widget")
gizmo = Product("Gizmo")
widgetFactory = Factory("Widget Inc", Position(50, 25), widget, .25, [])
gizmoSupplies = [widget]
gizmoFactory = Factory("Gizmo Inc", Position(50, 30), gizmo, .25, gizmoSupplies)
factories = [widgetFactory, gizmoFactory]
route = Route(name="Express Route", stops=(widgetFactory, gizmoFactory))
routeRev = Route(name="Express Route Reverse", stops=(miami, newYork, chicago, widgetFactory))
alphaDrone = Drone("Alpha", Position(25, 25), route, 1, 10)
betaDrone = Drone("Beta", Position(35, 25), routeRev, 5, 10)
drones = [alphaDrone]
while(True):
for drone in drones:
if(drone.get_state() == DroneState.Grounded):
drone.takeOff()
else:
drone.update()
for factory in factories:
factory.update()
pass
time.sleep(1)

Powered by TurnKey Linux.