satisfactory/plan.py

115 lines
3.3 KiB
Python
Raw Normal View History

2019-04-28 17:23:21 +10:00
#!/usr/bin/env python3
2019-04-28 18:02:57 +10:00
import math
2019-04-28 17:23:21 +10:00
import collections
2019-07-14 11:36:54 +10:00
from fractions import Fraction
from typing import Dict, Iterable
2019-07-14 11:35:09 +10:00
2019-04-28 18:02:57 +10:00
import satisfactory
2019-07-14 11:35:09 +10:00
2019-07-14 11:36:54 +10:00
def calculate_rates(recipes: Iterable[str], remain: Dict[str,Fraction]):
required_items = collections.defaultdict(Fraction)
2019-04-28 17:23:21 +10:00
while remain:
for dst_name, dst_rate in remain.pop().items():
2019-04-28 18:02:57 +10:00
required_items[dst_name] += dst_rate
2019-04-28 17:23:21 +10:00
dst = recipes[dst_name]
2019-04-28 18:59:31 +10:00
if not recipes.is_component(dst_name):
2019-04-28 17:23:21 +10:00
continue
dst_recipe = recipes[dst_name]['recipes'][0]
src_recipe = recipes[dst_name]['recipes'][0]
2019-07-14 11:36:54 +10:00
normal_rate = Fraction(
2019-04-28 17:23:21 +10:00
dst_recipe['output'][dst_name],
dst_recipe['crafting_time']
)
scale = dst_rate / normal_rate
for src_name, src_count in src_recipe['input'].items():
2019-07-14 11:36:54 +10:00
src_rate = Fraction(
2019-04-28 17:23:21 +10:00
src_count,
dst_recipe['crafting_time']
) * scale
remain.append({src_name: src_rate})
2019-04-28 18:59:31 +10:00
return required_items
2019-07-14 11:36:54 +10:00
def basic_rate(recipe: Dict) -> Fraction:
2019-07-14 11:35:09 +10:00
"""
Calculate the rate at which the item is crafted with the default recipe.
:param recipe:
:return:
"""
for output, count in recipe['output'].items():
2019-07-14 11:36:54 +10:00
return Fraction(
count, recipe['crafting_time']
)
2019-04-28 18:59:31 +10:00
2019-07-14 11:35:22 +10:00
# The number of items per minute that each tier of conveyor can carry
conveyor_rates = [0, 60, 120, 270, 480, 780, 900]
def main():
2019-04-28 18:59:31 +10:00
recipes = satisfactory.Cookbook('data/recipes')
2019-07-14 11:36:54 +10:00
required_items = collections.defaultdict(Fraction)
2019-04-28 18:59:31 +10:00
2019-07-14 11:35:22 +10:00
# Create a list of items we want to make
2019-04-28 18:59:31 +10:00
#targets = [ 'supercomputer' ]
targets = recipes.components()
2019-07-14 11:35:22 +10:00
# Create an initial name:rate request for all of the target items, then
# create a plan for their creation.
remain = [{n: basic_rate(recipes[n]['recipes'][0]) for n in targets}]
2019-04-28 18:59:31 +10:00
required_items = calculate_rates(recipes, remain)
2019-07-14 11:35:22 +10:00
# Note if any particular item is (in aggregate) going to exceed the
# highest conveyor belt capacity.
2019-04-28 18:02:57 +10:00
for name, rate in required_items.items():
print(name, rate, float(rate * 60))
2019-07-14 10:09:13 +10:00
if rate * 60 > 780:
2019-07-14 11:35:22 +10:00
print("Rate exceeds mk5 conveyor")
2019-04-28 18:02:57 +10:00
2019-07-14 11:35:22 +10:00
# Calculate the number of machines required to build each item at the
# calculated rates.
2019-04-28 18:02:57 +10:00
def numberdict():
return collections.defaultdict(int)
required_machines = collections.defaultdict(numberdict)
for name, requested_rate in required_items.items():
if recipes.is_resource(name):
continue
descriptor = recipes[name]
2019-07-14 11:36:54 +10:00
normal_rate = Fraction(
2019-04-28 18:02:57 +10:00
descriptor['recipes'][0]['output'][name],
descriptor['recipes'][0]['crafting_time']
)
machine = descriptor['machine']
required_machines[machine][name] += requested_rate / normal_rate
2019-07-14 11:35:22 +10:00
# Calculate the power requirements for all the machines
2019-04-28 18:02:57 +10:00
required_power = 0
for machine, buckets in required_machines.items():
for result, rate in buckets.items():
count = int(math.ceil(rate))
required_power += count * recipes[machine]['power_usage']
print(machine, result, math.ceil(rate))
2019-04-28 17:23:21 +10:00
2019-04-28 18:02:57 +10:00
print(required_power)
print(math.ceil(required_power / 150), "fuel generators")
if __name__ == '__main__':
main()