raylu 4 napja
szülő
commit
978578e1e4
1 módosított fájl, 82 hozzáadás és 0 törlés
  1. 82 0
      shipbuilding.py

+ 82 - 0
shipbuilding.py

@@ -0,0 +1,82 @@
+from __future__ import annotations
+
+import collections
+import typing
+
+import cache
+import roi
+
+def main() -> None:
+	blueprint = {
+		'FFC': 1,
+		'FSE': 1,
+		'LFE': 2,
+		'MFE': 2,
+		'QCR': 1,
+		'SFE': 1,
+		'LCB': 1,
+		'MFL': 1,
+		'MSL': 1,
+		'LHP': 94,
+		'SSC': 128,
+		'BR1': 1,
+		'CQM': 1,
+	}
+	prices: typing.Mapping[str, RawPrice] = {p['MaterialTicker']: p
+			for p in cache.get('https://refined-prun.github.io/refined-prices/all.json') if p['ExchangeCode'] == 'IC1'}
+	recipes = recipe_for_mats()
+
+	buildings: dict[str, set[str]] = collections.defaultdict(set)
+	cost = 0.0
+	for mat, amount in blueprint.items():
+		cost += analyze_mat(0, mat, amount, buildings, prices, recipes)
+		print()
+	print(f'total cost: {cost:,}')
+	for building, mats in buildings.items():
+		print(f'{building:3}: {", ".join(mats)}')
+
+def recipe_for_mats() -> dict[str, roi.Recipe]:
+	all_recipes: list[roi.Recipe] = cache.get('https://api.prunplanner.org/data/recipes/')
+	mat_recipes = collections.defaultdict(list) # all ways to make a mat
+	for recipe in all_recipes:
+		for output in recipe['outputs']:
+			mat_recipes[output['material_ticker']].append(recipe)
+
+	mat_recipe: dict[str, roi.Recipe] = {} # mats for which there's only one recipe to make
+	for mat, recipes in mat_recipes.items():
+		if len(recipes) == 1:
+			mat_recipe[mat] = recipes[0]
+	return mat_recipe
+
+def analyze_mat(level: int, mat: str, amount: float, buildings: dict[str, set[str]],
+		prices: typing.Mapping[str, RawPrice], recipes: dict[str, roi.Recipe]) -> float:
+	price = prices[mat]
+	traded = price['AverageTraded30D'] or 0
+	if (price['Supply'] > amount * 10 and traded > 0) or (price['Supply'] > amount * 4 and amount < traded):
+		print('\t' * level + f'{amount:g}×{mat} buy: {price["Ask"]:9,}, daily traded {traded:5.1f}, supply {price["Supply"]:4}')
+		assert price['Ask'] is not None
+		return price['Ask'] * amount
+	else:
+		if (recipe := recipes.get(mat)) is None:
+			print('\t' * level + f'{amount:g}×{mat} make (unknown recipe)')
+			return 0
+		else:
+			building = recipe['building_ticker']
+			print('\t' * level + f'{amount:g}×{mat} make ({building})')
+			buildings[building].add(mat)
+			total_cost = 0.0
+			for input_mat in recipe['inputs']:
+				input_amount = input_mat['material_amount'] * amount / recipe['outputs'][0]['material_amount']
+				total_cost += analyze_mat(level + 1, input_mat['material_ticker'], input_amount, buildings, prices, recipes)
+			print('\t' * level + f'\tcost: {total_cost:9,.2f}')
+		return total_cost
+
+class RawPrice(typing.TypedDict):
+	MaterialTicker: str
+	ExchangeCode: str
+	Ask: float | None
+	AverageTraded30D: float | None # averaged daily traded volume over last 30 days
+	Supply: int
+
+if __name__ == '__main__':
+	main()