Compare commits

..
4 changed files with 9 additions and 161 deletions

View file

@ -1,23 +1,10 @@
# Navigation computer of the SS Probably Fine # Navigation computer of the SS Probably Fine
Computes flight plans for the *SS Probably Fine*: route, distance, Computes flight plans for the *SS Probably Fine*: route, distance,
travel time, and the amount of fuel required. travel time, and the amout of fuel required.
```console ```console
$ python3 nav.py mars $ python3 nav.py mars
``` ```
Requires Python 3.9 or newer; no further dependencies. Requires Python 3.9 or newer; no further dependencies.
All routes start at Earth. Getting back is your own problem.
## Contributing
Use Conventional Commits. Do not push broken code.
(Yes, Dr. Honk, this means you.)
## Maintenance
All maintenance is recorded in `maintenance.md`.
To list all known destinations, run `python3 nav.py --list`.

View file

@ -3,10 +3,5 @@
| Name | Role | | Name | Role |
|------|------| |------|------|
| Captain Vega | Captain | | Captain Vega | Captain |
| Dr. Honk | Chief medical officer | | Dr. Honk | Ship's doctor |
| Lt. Byte | Chief engineer | | Lt. Byte | Chief engineer |
| Cmdr. Nova | Pilot |
| Ensign Pixel | Navigator |
| Quackers, the debugging duck | Morale officer |
| `coffeed` | Beverage officer |
| Mission control | Remote support (does not accept pushes) |

View file

@ -1,64 +1,3 @@
# Maintenance log # Maintenance log
Newest entries at the bottom. Newest entries at the bottom.
- 2026-09-01: Escape pod batteries charged.
- 2026-09-02: Antenna realigned.
- 2026-09-02: Fire extinguishers checked.
- 2026-09-04: Gyroscopes recalibrated.
- 2026-09-04: Escape pod batteries charged.
- 2026-09-04: Oxygen scrubbers replaced.
- 2026-09-05: Water recycling filters replaced.
- 2026-09-05: Antenna realigned.
- 2026-09-06: Fuel lines checked for leaks.
- 2026-09-07: Solar panels cleaned.
- 2026-09-07: Coffee machine descaled.
- 2026-09-07: Hull inspection, no leaks.
- 2026-09-09: Antenna realigned.
- 2026-09-09: Solar panels cleaned.
- 2026-09-10: Escape pod batteries charged.
- 2026-09-10: Debugging duck accounted for.
- 2026-09-11: Comms backup tested.
- 2026-09-14: Water recycling filters replaced.
- 2026-09-15: Airlock seals checked.
- 2026-09-15: Water recycling filters replaced.
- 2026-09-16: Coffee machine descaled.
- 2026-09-16: Antenna realigned.
- 2026-09-17: Cabin pressure sensors tested.
- 2026-09-18: Radiation shielding inspected.
- 2026-09-18: Debugging duck accounted for.
- 2026-09-18: Fire extinguishers checked.
- 2026-09-20: Fire extinguishers checked.
- 2026-09-20: Oxygen scrubbers replaced.
- 2026-09-21: Solar panels cleaned.
- 2026-09-21: Gyroscopes recalibrated.
- 2026-09-22: Fuel lines checked for leaks.
- 2026-09-23: Escape pod batteries charged.
- 2026-09-24: Galley fridge defrosted.
- 2026-09-27: Escape pod batteries charged.
- 2026-09-27: Comms backup tested.
- 2026-09-28: Gyroscopes recalibrated.
- 2026-09-28: Hull inspection, no leaks.
- 2026-09-30: Navigation lights checked.
- 2026-10-01: Cabin pressure sensors tested.
- 2026-10-02: Escape pod batteries charged.
- 2026-10-03: Navigation lights checked.
- 2026-10-05: Fuel lines checked for leaks.
- 2026-10-05: Fire extinguishers checked.
- 2026-10-05: Hull inspection, no leaks.
- 2026-10-06: Water recycling filters replaced.
- 2026-10-06: Debugging duck accounted for.
- 2026-10-07: Oxygen scrubbers replaced.
- 2026-10-07: Coffee machine descaled.
- 2026-10-08: Cabin pressure sensors tested.
- 2026-10-08: Thrusters test-fired.
- 2026-10-09: Galley fridge defrosted.
- 2026-10-10: Airlock seals checked.
- 2026-10-10: Galley fridge defrosted.
- 2026-10-11: Thrusters test-fired.
- 2026-10-11: Cabin pressure sensors tested.
- 2026-10-11: Antenna realigned.
- 2026-10-12: Thrusters test-fired.
- 2026-10-13: Fuel lines checked for leaks.
- 2026-10-14: Fuel lines checked for leaks.
- 2026-10-14: Hull inspection, no leaks.
- 2026-10-15: Escape pod batteries charged.

87
nav.py
View file

@ -2,52 +2,21 @@
"""Navigation computer of the SS Probably Fine. """Navigation computer of the SS Probably Fine.
Usage: python3 nav.py DESTINATION Usage: python3 nav.py DESTINATION
python3 nav.py --list
python3 nav.py --all
""" """
import sys import sys
from collections.abc import Iterator
# Distances between neighboring waypoints, in million km. # Distances between neighboring waypoints, in million km.
DISTANCES = { DISTANCES = {
("earth", "moon"): 0.4, ("earth", "moon"): 0.4,
("earth", "gateway"): 0.4, ("earth", "gateway"): 0.4,
("gateway", "mars"): 225.0, ("gateway", "mars"): 225.0,
("gateway", "venus"): 41.0,
("mars", "phobos"): 0.01,
("mars", "deimos"): 0.02,
("venus", "mercury"): 48.0,
("mars", "ceres"): 265.0,
("gateway", "milliways"): 42.0,
("ceres", "vesta"): 96.0,
("ceres", "europa"): 399.0,
("europa", "io"): 0.25,
("europa", "ganymede"): 0.4,
("ganymede", "callisto"): 0.8,
("europa", "titan"): 655.0,
("titan", "enceladus"): 1.0,
("titan", "pluto"): 4387.0,
} }
# Every route starts at Earth. # Every route starts at Earth.
ROUTES = { ROUTES = {
"moon": ["earth", "moon"], "moon": ["earth", "moon"],
"mars": ["earth", "gateway", "mars"], "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"],
"enceladus": ["earth", "gateway", "mars", "ceres", "europa", "titan", "enceladus"],
"pluto": ["earth", "gateway", "mars", "ceres", "europa", "titan", "pluto"],
} }
NAMES = { NAMES = {
@ -55,20 +24,6 @@ NAMES = {
"moon": "Moon", "moon": "Moon",
"gateway": "Lunar Gateway", "gateway": "Lunar Gateway",
"mars": "Mars", "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",
"enceladus": "Enceladus",
"pluto": "Pluto",
} }
CRUISE_SPEED = 0.87 # million km per day CRUISE_SPEED = 0.87 # million km per day
@ -76,21 +31,17 @@ FUEL_PER_MKM = 0.142 # tonnes of fuel per million km
LAUNCH_FUEL = 380.0 # tonnes of fuel to escape Earth's gravity LAUNCH_FUEL = 380.0 # tonnes of fuel to escape Earth's gravity
def distance(a: str, b: str) -> float: def distance(a, b):
"""Return the distance between two neighboring waypoints."""
if (a, b) in DISTANCES: if (a, b) in DISTANCES:
return DISTANCES[(a, b)] return DISTANCES[(a, b)]
return DISTANCES[(b, a)] return DISTANCES[(b, a)]
def legs(route: list[str]) -> Iterator[tuple[str, str]]: def legs(route):
"""Yield the legs (pairs of consecutive waypoints) of a route.""" return [(route[i], route[i + 1]) for i in range(len(route) - 1)]
for i in range(1, len(route) - 1):
yield route[i], route[i + 1]
def plot_course(destination: str) -> tuple[list[str], float, float, float]: def plan(destination):
"""Return route, distance, travel time (days) and fuel (t)."""
route = ROUTES[destination] route = ROUTES[destination]
total = 0.0 total = 0.0
fuel = 0.0 fuel = 0.0
@ -103,38 +54,14 @@ def plot_course(destination: str) -> tuple[list[str], float, float, float]:
return route, total, total / CRUISE_SPEED, fuel return route, total, total / CRUISE_SPEED, fuel
def asteroid_route(belt: str) -> list[str]: def main():
"""Return a route through the asteroid belt (currently: via Ceres).""" destination = sys.argv[1]
return ROUTES["ceres"] + [belt] route, total, days, fuel = plan(destination)
def print_plan(destination: str) -> None:
"""Print the flight plan for a destination."""
route, total, days, fuel = plot_course(destination)
print("Route: " + " -> ".join(NAMES[w] for w in route)) print("Route: " + " -> ".join(NAMES[w] for w in route))
print(f"Distance: {total:.1f} million km") print(f"Distance: {total:.1f} million km")
print(f"Travel time: {round(days)} days") print(f"Travel time: {round(days)} days")
print(f"Fuel required: {round(fuel)} t") print(f"Fuel required: {round(fuel)} t")
def main() -> None:
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
if sys.argv[1] == "--all":
for key in sorted(ROUTES):
print_plan(key)
print()
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__": if __name__ == "__main__":
main() main()