From 07a37a4240d75465b0cc481bb3468fcd7d66af2e Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 14 Jul 2019 11:49:49 +1000 Subject: [PATCH] plan: document the calculate_rates function --- plan.py | 80 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/plan.py b/plan.py index 33f007d..d10d354 100755 --- a/plan.py +++ b/plan.py @@ -4,42 +4,11 @@ import math import collections from fractions import Fraction -from typing import Dict, Iterable +from typing import Dict, List import satisfactory -def calculate_rates(recipes: Iterable[str], remain: Dict[str,Fraction]): - required_items = collections.defaultdict(Fraction) - - while remain: - for dst_name, dst_rate in remain.pop().items(): - required_items[dst_name] += dst_rate - - dst = recipes[dst_name] - if not recipes.is_component(dst_name): - continue - - dst_recipe = recipes[dst_name]['recipes'][0] - src_recipe = recipes[dst_name]['recipes'][0] - - normal_rate = Fraction( - dst_recipe['output'][dst_name], - dst_recipe['crafting_time'] - ) - - scale = dst_rate / normal_rate - - for src_name, src_count in src_recipe['input'].items(): - src_rate = Fraction( - src_count, - dst_recipe['crafting_time'] - ) * scale - remain.append({src_name: src_rate}) - - return required_items - - def basic_rate(recipe: Dict) -> Fraction: """ Calculate the rate at which the item is crafted with the default recipe. @@ -52,6 +21,49 @@ def basic_rate(recipe: Dict) -> Fraction: ) +def calculate_rates( + recipes: satisfactory.Cookbook, + remain: List[Dict[str, Fraction]] +) -> Dict[str, Fraction]: + """ + Calculate the total production rates needed to produce items at the rates + listed in 'remain' using the provided recipes. + :param recipes: The source Cookbook + :param remain: A mapping from requested items to their desired rate. + :return: A mapping from all required items to their required output rates. + """ + + # Iteratively accumulate a mapping from items to required rates + required_items = collections.defaultdict(Fraction) + + while remain: + for dst_name, dst_rate in remain.pop().items(): + # Append the requested item + required_items[dst_name] += dst_rate + + # We can't craft resources, so just ignore them. + if not recipes.is_component(dst_name): + assert recipes.is_resource(dst_name) + continue + + # Assume we're using the default recipe + dst_recipe = recipes[dst_name]['recipes'][0] + + # Calculate the fraction of the base rate we need to satisfy, and + # append our (scaled) inputs to the request queue. + normal_rate = basic_rate(dst_recipe) + scale = dst_rate / normal_rate + + for src_name, src_count in dst_recipe['input'].items(): + src_rate = Fraction( + src_count, + dst_recipe['crafting_time'] + ) * scale + remain.append({src_name: src_rate}) + + return required_items + + # The number of items per minute that each tier of conveyor can carry conveyor_rates = [0, 60, 120, 270, 480, 780, 900] @@ -59,10 +71,8 @@ conveyor_rates = [0, 60, 120, 270, 480, 780, 900] def main(): recipes = satisfactory.Cookbook('data/recipes') - required_items = collections.defaultdict(Fraction) - # Create a list of items we want to make - #targets = [ 'supercomputer' ] + # targets = [ 'supercomputer' ] targets = recipes.components() # Create an initial name:rate request for all of the target items, then