def batches_required( self, resource: str, quantity: Union[float, Fraction]) -> Union[float, Fraction]: """ Calculate how many batches would be required to produce a certain quantity of the specified resource if it is an input, otherwise how many batches would be required to consume that quantity of the specified resource. """ use_fractions = type(quantity) == Fraction e = self.efficiency() d = self._duration z = 0.0 if use_fractions: e = asfrac(e) d = asfrac(d) z = asfrac(z) if resource in self._inputs: # how many batches required to consume this much input i = self._inputs[resource] if use_fractions: i = asfrac(i) return quantity / (i * (e / d)) if resource in self._outputs: # how many batches required to produce this much output o = self._outputs[resource] if use_fractions: o = asfrac(o) return quantity / (o * (e / d)) # we don't produce or consume it, so no batches are required to consume it return z
def produced( self, resource: str, batches: Union[float, Fraction] = 1.0) -> Union[float, Fraction]: """ Calculate how much of a given resource would be produced given a certain number of batches are run. """ o = self._outputs.get(resource) or 0.0 e = self.efficiency() d = self._duration if type(batches) == Fraction: o = asfrac(o) e = asfrac(e) d = asfrac(d) return o * (e / d) * batches
def consumed( self, resource: str, batches: Union[float, Fraction] = 1.0) -> Union[float, Fraction]: """ Calculate how much of a given resource would be consumed given a certain number of batches are run. """ i = self._inputs.get(resource) or 0.0 e = self.efficiency() d = self._duration if type(batches) == Fraction: i = asfrac(i) e = asfrac(e) d = asfrac(d) return i * (e / d) * batches
def calculate(self, targets: Targets, available_resource: Optional[Targets]=None, use_fractions=False, round_batches=False, round_resources=False, max_iterations=10) -> Calculations: """ Calculate the number of resources and batches of each recipe are needed to meet all the user, production targets. If targets is of fractions, then all calculations will be done with fractions. Note: Production targets for resources define how many of the resource must be "left over" (i.e. not consumed by other recipes) while production targets for recipes define the minimum number of batches which must be run. Note: If a target is both listed as a recipe and a resource, the resource is assumed. :param targets: Production targets specified by the user. :param available_resource: Number of resources which are available without crafting. :param use_fractions: Whether calculations should be done with fractions, default is floating point. :param round_batches: If true, it will round up the number of batches required (and propagate the consequences). :param round_resources: If true, it will round up the number of resources required (and propagate the consequences). :param max_iterations: Should only take 2-3 total iterations if rounding is disabled, may want a higher value in some cases. :return: The total recipe batches and resource counts. """ z, zt = _zero(use_fractions) calcs = Calculations(self, targets, available_resource=available_resource) # set the demand for each target as the required quantities for target, required in targets.items(): if use_fractions: required = asfrac(required) if self.is_resource(target): # if some of this resource has already been produced, decrease the demand. required = calcs.ar.use(target, required) # find it's recipe and add that recipe = self.get_recipe_for(target) if recipe is None: # raw resource, not sure why it was requested, but give them what they want calcs.resources[target] = (required, required) else: calcs.resources[target] = (required, z()) calcs.recipes[recipe.name] = zt() elif self.is_recipe(target): calcs.recipes[target] = (required, z()) else: raise RuntimeError("Unrecognized identifier: " + target) changed = False for _ in range(max_iterations): # multiple iterations are required when recipes produces useful byproducts changed = self._propagate(calcs, round_batches, round_resources, use_fractions) if not changed: break if changed: print("May not have found an optimal solution, consider increasing the maximum iterations.", file=sys.stderr) return calcs