126 lines
3.7 KiB
Python
126 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Navigation computer of the SS Probably Fine.
|
|
|
|
Usage: python3 nav.py DESTINATION
|
|
python3 nav.py --list
|
|
"""
|
|
|
|
import sys
|
|
|
|
# Distances between neighboring waypoints, in million km.
|
|
DISTANCES = {
|
|
("earth", "moon"): 0.4,
|
|
("earth", "gateway"): 0.4,
|
|
("gateway", "mars"): 225.0,
|
|
("gateway", "venus"): 41.0,
|
|
("mars", "phobos"): 0.01,
|
|
("mars", "deimos"): 0.02,
|
|
("venus", "mercury"): 50.0,
|
|
("mars", "ceres"): 263.0,
|
|
("gateway", "milliways"): 42.0,
|
|
("ceres", "vesta"): 96.0,
|
|
("ceres", "europa"): 404.0,
|
|
("europa", "io"): 0.25,
|
|
("europa", "ganymede"): 0.4,
|
|
("ganymede", "callisto"): 0.8,
|
|
("europa", "titan"): 655.0,
|
|
}
|
|
|
|
# Every route starts at Earth.
|
|
ROUTES = {
|
|
"moon": ["earth", "moon"],
|
|
"mars": ["earth", "gateway", "mars"],
|
|
"venus": ["earth", "gateway", "venus"],
|
|
"phobos": ["earth", "gateway", "mars", "phobos"],
|
|
"deimos": ["earth", "gateway", "mars", "deimos"],
|
|
"mercury": ["earth", "gateway", "venus", "mercury"],
|
|
"ceres": ["earth", "gateway", "mars", "ceres"],
|
|
"milliways": ["earth", "gateway", "milliways"],
|
|
"vesta": ["earth", "gateway", "mars", "ceres", "vesta"],
|
|
"europa": ["earth", "gateway", "mars", "ceres", "europa"],
|
|
"io": ["earth", "gateway", "mars", "ceres", "europa", "io"],
|
|
"ganymede": ["earth", "gateway", "mars", "ceres", "europa", "ganymede"],
|
|
"callisto": ["earth", "gateway", "mars", "ceres", "europa", "ganymede", "callisto"],
|
|
"titan": ["earth", "gateway", "mars", "ceres", "europa", "titan"],
|
|
}
|
|
|
|
NAMES = {
|
|
"earth": "Earth",
|
|
"moon": "Moon",
|
|
"gateway": "Lunar Gateway",
|
|
"mars": "Mars",
|
|
"venus": "Venus",
|
|
"phobos": "Phobos",
|
|
"deimos": "Deimos",
|
|
"mercury": "Mercury",
|
|
"ceres": "Ceres",
|
|
"milliways": "Restaurant at the End of the Universe",
|
|
"vesta": "Vesta",
|
|
"europa": "Europa",
|
|
"io": "Io",
|
|
"ganymede": "Ganymede",
|
|
"callisto": "Callisto",
|
|
"titan": "Titan",
|
|
}
|
|
|
|
CRUISE_SPEED = 0.87 # million km per day
|
|
FUEL_PER_MKM = 0.142 # tonnes of fuel per million km
|
|
LAUNCH_FUEL = 380.0 # tonnes of fuel to escape Earth's gravity
|
|
|
|
|
|
def distance(a, b):
|
|
"""Return the distance between two neighboring waypoints."""
|
|
if (a, b) in DISTANCES:
|
|
return DISTANCES[(a, b)]
|
|
return DISTANCES[(b, a)]
|
|
|
|
|
|
def legs(route):
|
|
"""Return the legs (pairs of consecutive waypoints) of a route."""
|
|
return [(route[i], route[i + 1]) for i in range(len(route) - 1)]
|
|
|
|
|
|
def plan(destination):
|
|
"""Return route, distance, travel time (days) and fuel (t)."""
|
|
route = ROUTES[destination]
|
|
total = 0.0
|
|
fuel = 0.0
|
|
for start, end in legs(route):
|
|
d = distance(start, end)
|
|
total += d
|
|
fuel += d * FUEL_PER_MKM
|
|
if start == "earth":
|
|
fuel += LAUNCH_FUEL
|
|
return route, total, total / CRUISE_SPEED, fuel
|
|
|
|
|
|
def asteroid_route(belt):
|
|
"""Return a route through the asteroid belt (currently: via Ceres)."""
|
|
return ROUTES["ceres"] + [belt]
|
|
|
|
|
|
def print_plan(destination):
|
|
"""Print the flight plan for a destination."""
|
|
route, total, days, fuel = plan(destination)
|
|
print("Route: " + " -> ".join(NAMES[w] for w in route))
|
|
print(f"Distance: {total:.1f} million km")
|
|
print(f"Travel time: {round(days)} days")
|
|
print(f"Fuel required: {round(fuel)} t")
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) != 2:
|
|
sys.exit(__doc__)
|
|
if sys.argv[1] == "--list":
|
|
for key in sorted(ROUTES):
|
|
print(f"{key:12} {NAMES[key]}")
|
|
return
|
|
destination = sys.argv[1].lower()
|
|
if destination not in ROUTES:
|
|
known = ", ".join(sorted(ROUTES))
|
|
sys.exit(f"Unknown destination: {destination} (known: {known})")
|
|
print_plan(destination)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|