from __future__ import annotations import sys import tomllib import typing import cache def main() -> None: planet = sys.argv[1].casefold() burn, raw_materials = fio_data(planet) inventory = {item['MaterialTicker']: item['MaterialAmount'] for item in burn['Inventory']} materials = {mat['Ticker']: mat for mat in raw_materials} producing = frozenset(item['MaterialTicker'] for item in burn['OrderProduction']) consumables = [c for c in burn['OrderConsumption'] + burn['WorkforceConsumption'] if c['MaterialTicker'] not in producing] vol_per_day = 0.0 weight_per_day = 0.0 target_days = float('inf') for consumption in consumables: ticker = consumption['MaterialTicker'] vol_per_day += materials[ticker]['Volume'] * consumption['DailyAmount'] weight_per_day += materials[ticker]['Weight'] * consumption['DailyAmount'] days = inventory.get(ticker, 0) / consumption['DailyAmount'] if days < target_days: target_days = days print(f'consuming {vol_per_day:.1f}㎥/d') print(f'consuming {weight_per_day:.1f}t/d') limiting = 'Volume' if weight_per_day > vol_per_day: limiting = 'Weight' target_days = round(target_days + 0.05, 1) while True: space_used = 0 buy: dict[str, float] = {} for consumption in consumables: ticker = consumption['MaterialTicker'] avail = inventory.get(ticker, 0) daily_consumption = consumption['DailyAmount'] days = avail / daily_consumption if days < target_days: buy[ticker] = (target_days - days) * daily_consumption space_used += buy[ticker] * materials[ticker][limiting] if space_used > 500: break optimal = buy target_days += 0.1 print('supply for', round(target_days, 1), 'days') for consumption in consumables: ticker = consumption['MaterialTicker'] avail = inventory.get(ticker, 0) daily_consumption = consumption['DailyAmount'] days = avail / daily_consumption print(f'{ticker:>3}: {avail:5d} ({daily_consumption:8.2f}/d) {days:4.1f} d', end='') if need := optimal.get(ticker): # pyright: ignore[reportPossiblyUnboundVariable] print(f' | {need:8.1f}') else: print() def fio_data(planet: str) -> tuple[PlanetData, typing.Sequence[Material]]: with open('config.toml', 'rb') as f: config = tomllib.load(f) planets: list[PlanetData] = cache.get('https://rest.fnar.net/fioweb/burn/user/' + config['username'], headers={'Authorization': config['fio_api_key']}) for planet_data in planets: name = planet_data['PlanetName'] if name.casefold() == planet: assert planet_data['Error'] is None break else: raise ValueError(planet + ' not found') materials: list[Material] = cache.get('https://rest.fnar.net/material/allmaterials') return planet_data, materials class PlanetData(typing.TypedDict): PlanetName: str Error: typing.Any OrderConsumption: list[Amount] WorkforceConsumption: list[Amount] Inventory: list[Inventory] OrderProduction: list[Amount] class Amount(typing.TypedDict): MaterialTicker: str DailyAmount: float class Inventory(typing.TypedDict): MaterialTicker: str MaterialAmount: int class Material(typing.TypedDict): Ticker: str Weight: float Volume: float if __name__ == '__main__': main()