class CraftingTable::RecipeManager
A class which contains recipes, and allows to search through them.
@author Michael Senn <morrolan@morrolan.ch> @since 0.2
Attributes
Public Class Methods
Create a new RecipeManager
@param [ItemManager] item_manager
ItemManager
which contains the items
on which this manager's recipes are based.
# File lib/crafting_table/recipe_manager.rb, line 17 def initialize(item_manager) @item_manager = item_manager @recipes = [] end
Public Instance Methods
Add a new recipe to the internal collection.
@param [Recipe] recipe Recipe
which to add to the collection. @return [void]
# File lib/crafting_table/recipe_manager.rb, line 26 def add(recipe) @recipes << recipe end
Add new recipes by reading them from a YAML file.
@param [String] path The path to the file from which to read
recipes from.
@return [void]
# File lib/crafting_table/recipe_manager.rb, line 35 def add_from_file(path) YAML.load_file(path).each do |recipe_hash| raw_input = recipe_hash.fetch('input', {}) raw_output = recipe_hash.fetch('output', {}) name = recipe_hash.fetch('name', 'UNKNOWN') input = {} output = {} raw_input.each do |identifier_string, amount| identifier = identifier_string.split(':').map(&:to_i) item = item_manager.find_by_identifier(identifier).first input[item] = amount end raw_output.each do |identifier_string, amount| identifier = identifier_string.split(':').map(&:to_i) item = item_manager.find_by_identifier(identifier).first output[item] = amount end @recipes << Recipe.new(name, input, output) end end
Clear the internal collection of recipes. @return [void]
# File lib/crafting_table/recipe_manager.rb, line 62 def clear @recipes.clear end
Find recipes.
@since 0.3
@example Searching for name.
results = manager.find do |search| search.name = 'slab' search.exact = false search.case_sensitive = false end results.map(&:name) #=> ['Cobblestone slab', 'Wooden slab', 'Stone slab', '...']
@example Searching for recipes which result in torch(es).
manager.find do |search| manager.output = Item.new('Torch', 50) end
@example Searching for recipes which require oak planks.
results = manager.find do |search| manager.input = Item.new('Oak Wood Planks', 5) end results.map(&:name) #=> ['Sticks', 'Crafting Table', 'Chest', 'Bed', '...']
@yieldparam builder [SearchBuilder]
An instance of the SearchBuilder class which allows to easily specify multiple search conditions.
@return [Array<Recipe>] Recipes which matched the search conditions.
# File lib/crafting_table/recipe_manager.rb, line 96 def find(&block) builder = Search::SearchBuilder.new yield builder builder.searches.inject(recipes) { |recipes, search| search.apply_to(recipes) } end
Find recipes by their input.
@deprecated Use {#find} instead.
@example Searching for recipes which require planks.
manager.find_by_input(Item.new('Oak Wood Planks', 5, 0)).map(&:name) #=> ['Sticks', 'Crafting Table', 'Chest', 'Bed', '...']
@param [Item] item Item
for which to search. @return [Array<Recipe>] Collection of recipes which matched the search condition.
# File lib/crafting_table/recipe_manager.rb, line 147 def find_by_input(item) recipes.select { |recipe| recipe.input.key? item } end
Find recipes by their name.
@deprecated Use {#find} instead.
@example Search
using default parameters.
manager.find_by_name('Torch').first.input.map(&:name) #=> ['Wooden Planks', 'Coal']
@example Case-insensitive search, non-exact matching.
manager.find_by_name('slab').map(&:name) #=> ['Cobblestone Slab', 'Wooden slab', 'Stone slab', '...']
@param [String] name The name for which to search. @param [Hash] options Options which influence the search. @option options [Boolean] :exact (true) Whether to match names exactly. @option options [Boolean] :case_sensitive (true) Whether to search case-sensitively. @return [Array<Recipe>] Collection of recipes which matched the search condition.
# File lib/crafting_table/recipe_manager.rb, line 118 def find_by_name(name, options = {}) default_options = { exact: true, case_sensitive: true } default_options.update(options) if default_options[:case_sensitive] if default_options[:exact] recipes.select { |recipe| recipe.name == name } else recipes.select { |recipe| recipe.name.include? name } end else if default_options[:exact] recipes.select { |recipe| recipe.name.downcase == name.downcase } else recipes.select { |recipe| recipe.name.downcase.include? name.downcase } end end end
Find recipes by their output.
@deprecated Use {#find} instead.
@example Searching for recipes which result in Coal.
manager.find_by_output(Item.new('Coal', 263, 0)).map(&:name) #=> ['Coal']
@return [Array<Recipe>]
Collection of recipes which matched the search condition.
# File lib/crafting_table/recipe_manager.rb, line 160 def find_by_output(item) recipes.select { |recipe| recipe.output.key? item } end
Resolve a recipe into its base components.
@since 0.3
@example Components required to craft 50 torches.
torch = recipe_manager.find_by_name('Torch').first components = recipe_manager.resolve_recipe(recipe_torch, 50) components.map { |item, amount| item.name => amount } #=> { "Wood" => 2, "Coal" => 13 }
@param [Recipe] recipe
The recipe which to resolve to its components.
@param [Integer] amount Desired amount of the recipe. @return [Hash{Item => Integer}]
A hash mapping the base components to the required amount of each.
# File lib/crafting_table/recipe_manager.rb, line 180 def resolve_recipe(recipe, amount) # Todo: Allow to specify arbitrary outputs. # Todo: Fail if the specified output is not part of the recipe. desired_output = recipe.output.keys.first amount_per_iteration = recipe.output[desired_output] # If we get four items per iteration, and want 21 items in # total, we'll need 6 iterations. iterations = (amount.to_f / amount_per_iteration).ceil requirements = Hash.new(0) recipe.input.each do |input, amount| # Finding potential recipes for the input. recipes_for_input = find_by_output(input) # Todo: Allow for other criteria where the recipe should be ignored. if recipes_for_input.empty? requirements[input] += amount * iterations else recipe_for_input = recipes_for_input.first requirements_for_input = resolve_recipe(recipe_for_input, amount * iterations) requirements.merge!(requirements_for_input) do |key, old_amount, new_amount| old_amount + new_amount end end end requirements end