#!/usr/bin/env python3 """Rank planets for a resource, with founding cost (environment extras straight from FIO's BuildRequirements - real game data, not guessed thresholds) and optional jump distance from a base you already have. tools/planet.py FEO --top 10 tools/planet.py LST --min-factor 0.5 --from ZV-759c --top 5 """ import argparse, sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from puga import config, market, planet, route def main(): ap = argparse.ArgumentParser() ap.add_argument("resource", help="raw resource ticker, e.g. LST, FEO, SEA") ap.add_argument("--min-factor", type=float, default=0.0) ap.add_argument("--top", type=int, default=10) ap.add_argument("--from", dest="from_", help="planet/system to measure jump distance from (e.g. an existing base)") ap.add_argument("--cx", default=config.DEFAULT_CX) a = ap.parse_args() rows = planet.candidates(a.resource, a.min_factor) if not rows: print(f"no planets found with {a.resource.upper()} (factor >= {a.min_factor})") return rows = rows[:a.top] src = route.resolve_system(a.from_) if a.from_ else None graph = route.load_graph() if src else None for p in rows: env_cost = 0.0 env_items = [] for br in p["build_requirements"]: w = market.walk(br["MaterialTicker"], a.cx, br["MaterialAmount"], "buy") env_cost += w["total"] env_items.append(f"{br['MaterialAmount']}{br['MaterialTicker']}") dist = "" if src: r = route.shortest_path(src, p["system_id"], graph=graph) if p["system_id"] != src else {"jumps": 0, "distance_ly": 0.0} dist = f" {r['jumps']} jumps ({r['distance_ly']:.0f} ly)" if r else " unreachable" print(f"{p['natural_id']:8} {p['name']:16} factor {p['factor']:.3f} T {p['temperature']:6.1f}C P {p['pressure']:.2f}bar " f"G {p['gravity']:.2f} fert {p['fertility']:5.2f} faction {p['faction'] or '-':4} env-cost {env_cost:8,.0f} AIC ({', '.join(env_items) or 'none'}){dist}") if __name__ == "__main__": main()