Skip to content

Instantly share code, notes, and snippets.

@lolobosse
Created February 4, 2019 07:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lolobosse/4dcbc39373709cbd56be0e22e138dbe7 to your computer and use it in GitHub Desktop.
Save lolobosse/4dcbc39373709cbd56be0e22e138dbe7 to your computer and use it in GitHub Desktop.
Airline Manager Plane combination calculator
import math
# from constraint import *
#
# problem = Problem()
#
# problem.addVariable("Q400 Eco", [80, 0, 0])
# problem.addVariable("Q400 Aff", [0, 44, 0])
# problem.addVariable("Q400 First", [0, 0, 19])
# problem.addVariable("ORY", [368, 107, 19, 4.25])
# problem.addConstraint(lambda a, b)
from itertools import chain, combinations
class Plane:
def __init__(self, name, eco, affaire, first, speed, range, price):
self.name = name
self.eco = eco
self.affaire = affaire
self.first = first
self.speed = speed
self.range = range
self.price = price
def __repr__(self):
return self.name
@staticmethod
def round_to_upper_quarter(time):
return math.ceil(time*4)/4
def required_time(self, point):
if isinstance(point, Airport):
point = point.distance
if point > self.range:
return None
exact_flight_time = float(point) * float(2.0) / float(self.speed)
flight_time = exact_flight_time+2
return self.round_to_upper_quarter(flight_time)
def capacity(self):
return self.eco + self.affaire + self.first
class Airport:
def __init__(self, name, eco, affaire, first, distance):
factor = 1.0
self.name = name
self.eco = int(eco * factor)
self.affaire = int(affaire * factor)
self.first = int(first * factor)
self.distance = distance
def __repr__(self):
return self.name
class Planning:
def __init__(self, planes, airports):
self.planes = planes
self.airports = airports
def planification(self):
flights = []
lost = []
for a in airports:
for p in planes:
if p.range < a.distance:
continue
if p.eco > 0:
need_a_plane = a.eco // (p.eco*2)
_lost = a.eco % (p.eco*2)
lost.append((a, _lost))
if need_a_plane > 0:
for i in range(1, need_a_plane+1):
flights.append((p,a))
if p.affaire > 0:
need_a_plane = a.affaire // (p.affaire * 2)
_lost = a.affaire % (p.affaire * 2)
lost.append((a, _lost))
if need_a_plane > 0:
for i in range(1, need_a_plane + 1):
flights.append((p, a))
if p.first > 0:
need_a_plane = a.first // (p.first * 2)
_lost = a.first % (p.first * 2)
lost.append((a, _lost))
if need_a_plane > 0:
for i in range(1, need_a_plane + 1):
flights.append((p, a))
return flights, lost
@staticmethod
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return list(chain.from_iterable(combinations(s, r) for r in range(len(s) + 1)))
def order_per_plane(self, flights):
flights_per_plane = {}
for f in flights:
is_in_list = flights_per_plane.get(f[0], False)
if is_in_list:
flights_per_plane[f[0]].append(f[1])
else:
flights_per_plane[f[0]]=[f[1]]
planes = []
left = []
for item, values in flights_per_plane.items():
remaining_values = values
remaining_time = sum([item.required_time(x) for x in remaining_values])
while remaining_time > 0:
powerset = self.powerset(values)
exact = False
for _set in powerset:
sum_flights = sum([item.required_time(x) for x in _set])
if sum_flights == 24:
exact = True
planes.append((item, _set, sum_flights))
for sset in _set:
remaining_values.remove(sset)
remaining_time = sum([item.required_time(x) for x in remaining_values])
break
if exact:
continue
remaining = [(_set, sum([item.required_time(x) for x in _set])) for _set in powerset if sum([item.required_time(x) for x in _set]) < 24]
selected = max(remaining, key=lambda x: x[1])
sum_flights = selected[1]
_set = selected[0]
if sum_flights >= 22:
planes.append((item, _set, sum_flights))
for sset in _set:
remaining_values.remove(sset)
remaining_time = sum([item.required_time(x) for x in remaining_values])
else:
left.append((item, remaining_values, remaining_time))
remaining_time = 0
return planes, left
q400 = [Plane("Q400 Eco", 80, 0, 0, 667, 2400, 26500000), Plane("Q400 Aff", 0, 44, 0, 667, 2400, 26500000), Plane("Q400 First", 0, 0, 18, 667, 2400, 26500000)]
sukkoi = [Plane("Sukkoi eco", 98, 0, 0, 828, 4578, 42500000), Plane("Sukkoi Aff", 0, 54, 0, 828, 4578,42500000), Plane("Sukkoi First", 0, 0, 23, 828, 4578,42500000)]
mix = [Plane("Sukkoi eco", 98, 0, 0, 828, 4578,42500000), Plane("Q400 Aff", 0, 44, 0, 667, 2400, 26500000), Plane("Q400 First", 0, 0, 18, 667, 2400, 26500000)]
plane_choices = [q400, sukkoi, mix]
for planes in plane_choices:
print('*'*50)
# Airport("GIB",1028,249,90,1949), Airport("ALP", 1537, 202,56,2475)
airports = [Airport("ORY", 72, 107, 19, 694), Airport("BCN", 147, 117, 132, 1095), Airport("ATH", 327, 163, 127, 1518),
Airport("HAM", 16, 65, 12, 600), Airport("MXP", 0, 312, 8, 381), Airport("AER", 536, 167, 81, 2233),
Airport("LGW", 81, 56, 102, 913), Airport("BMA", 1116, 297, 108, 1287)]
planning = Planning(planes, airports)
p, lost = planning.planification()
plan, remaining = planning.order_per_plane(p)
print(str(len(plan))+" "+str(plan))
print("Not scheduled " +str(remaining))
lost_via_schedule = sum([x[0].capacity()*len(x[1]) for x in remaining]) *2
lost_via_dividend = sum([x[1] for x in lost])
price = int(sum([p[0].price for p in plan]))
pax = sum([x[0].capacity()*len(x[1]) for x in plan]) * 2
print("Lost %d (Scheduled: %d, Dividend: %d)" % (lost_via_schedule+lost_via_dividend, lost_via_schedule, lost_via_dividend))
print("Price %d M; PAX %d $/PAX %d" % (price /1000000, pax, int(price/pax)))
print('*'*50)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment