/// <summary> /// Adds the given <paramref name="capability" /> to the role's capabilities to be applied. /// </summary> /// <exception cref="InvalidOperationException"> /// Thrown if the given capability is not the /// next required capability. /// </exception> public void AddCapabilityToApply(Capability capability) { if (_capabilitiesToApplyStart + _capabilitiesToApplyCount >= Recipe.RequiredCapabilities.Length) throw new InvalidOperationException("All required capabilities already applied."); if (!capability.Equals(Recipe.RequiredCapabilities[_capabilitiesToApplyStart + _capabilitiesToApplyCount])) throw new InvalidOperationException("Cannot apply capability that is not required."); _capabilitiesToApplyCount++; }
/// <summary> /// Creates a new recipe with the specified sequence of ingredients. /// </summary> /// <param name="ingredients">The sequence of ingredients to add to the containers.</param> /// <param name="amount">The number of containers to produce for this recipe.</param> public Recipe(Ingredient[] ingredients, uint amount) { _activeContainers = new List<PillContainer>((int)amount); Amount = amount; RequiredCapabilities = new Capability[] { new ProduceCapability() } .Concat(ingredients) .Concat(new[] { new ConsumeCapability() }) .ToArray(); }
public static bool IsSatisfiable(Capability[] required, Capability[] available) { if (required.OfType<ProduceCapability>().Any() && !available.OfType<ProduceCapability>().Any()) return false; if (required.OfType<ConsumeCapability>().Any() && !available.OfType<ConsumeCapability>().Any()) return false; var requiredAmounts = GroupIngredientAmounts(required); var availableAmounts = GroupIngredientAmounts(available); foreach (var pair in requiredAmounts) { int value; if (!availableAmounts.TryGetValue(pair.Key, out value) || value < pair.Value) return false; } return true; }
/// <summary> /// Appends the given <see cref="Capability" /> to the <see cref="State" />. /// </summary> /// <param name="capability">The capability to append.</param> /// <exception cref="InvalidOperationException"> /// Thrown if the capability does not match /// the <see cref="Recipe" />'s next required capability. /// </exception> public void AppendToState(Capability capability) { if (_statePrefixLength >= Recipe.RequiredCapabilities.Length) throw new InvalidOperationException("Condition already has maximum state."); if (Recipe.RequiredCapabilities[_statePrefixLength] != capability) throw new InvalidOperationException("Capability must be next required capability."); _statePrefixLength++; }
private static Dictionary<IngredientType, int> GroupIngredientAmounts(Capability[] capabilities) { return capabilities.OfType<Ingredient>() .GroupBy(ingredient => ingredient.Type, ingredient => (int)ingredient.Amount) .ToDictionary(group => group.Key, group => group.Sum()); }