crafting_table 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.asc +11 -0
  3. data.tar.gz.asc +11 -0
  4. data/.gitignore +0 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +41 -0
  7. data/LICENSE +14 -0
  8. data/Rakefile +0 -0
  9. data/crafting_table.gemspec +19 -0
  10. data/data/items/thermal_expansion.yml +64 -0
  11. data/data/items/vanilla.yml +1152 -0
  12. data/data/recipes/thermal_expansion.yml +97 -0
  13. data/data/recipes/vanilla.yml +25 -0
  14. data/data/test/items/vanilla.yml +1149 -0
  15. data/data/test/recipes/vanilla.yml +25 -0
  16. data/examples/interactive_table.rb +98 -0
  17. data/features/item_differentiation.feature +18 -0
  18. data/features/loading_items.feature +10 -0
  19. data/features/resolving_recipes.feature +26 -0
  20. data/features/searching_items.feature +83 -0
  21. data/features/searching_recipes.feature +42 -0
  22. data/features/step_definitions/item_manager_steps.rb +88 -0
  23. data/features/step_definitions/item_steps.rb +23 -0
  24. data/features/step_definitions/recipe_manager_steps.rb +42 -0
  25. data/features/support/env.rb +29 -0
  26. data/lib/crafting_table.rb +19 -0
  27. data/lib/crafting_table/item.rb +61 -0
  28. data/lib/crafting_table/item_manager.rb +171 -0
  29. data/lib/crafting_table/recipe.rb +36 -0
  30. data/lib/crafting_table/recipe_manager.rb +216 -0
  31. data/lib/crafting_table/search/damage_search.rb +51 -0
  32. data/lib/crafting_table/search/fuzzy_name_search.rb +39 -0
  33. data/lib/crafting_table/search/input_search.rb +47 -0
  34. data/lib/crafting_table/search/item_id_search.rb +51 -0
  35. data/lib/crafting_table/search/name_search.rb +71 -0
  36. data/lib/crafting_table/search/output_search.rb +47 -0
  37. data/lib/crafting_table/search/search_builder.rb +85 -0
  38. data/spec/crafting_table/item_manager_spec.rb +421 -0
  39. data/spec/crafting_table/item_spec.rb +67 -0
  40. data/spec/crafting_table/recipe_manager_spec.rb +353 -0
  41. data/spec/crafting_table/recipe_spec.rb +25 -0
  42. data/spec/crafting_table/search/search_builder.rb +105 -0
  43. data/spec/crafting_table/search/search_spec.rb +383 -0
  44. data/spec/spec_helper.rb +6 -0
  45. metadata +145 -0
  46. metadata.gz.asc +11 -0
@@ -0,0 +1,25 @@
1
+ ---
2
+ - name: Stone
3
+ input:
4
+ "4:0": 1
5
+ output:
6
+ "1:0": 1
7
+
8
+ - name: Oak Wood Planks
9
+ input:
10
+ "17:0": 1
11
+ output:
12
+ "5:0": 4
13
+
14
+ - name: Sticks
15
+ input:
16
+ "5:0": 2
17
+ output:
18
+ "280:0": 4
19
+
20
+ - name: Torch
21
+ input:
22
+ "280:0": 1
23
+ "263:0": 1
24
+ output:
25
+ "50:0": 4
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ require 'crafting_table'
5
+
6
+ class InteractiveTable
7
+ attr_reader :item_manager, :recipe_manager
8
+
9
+ def initialize(opts)
10
+ @item_manager = CraftingTable::ItemManager.new
11
+ @recipe_manager = CraftingTable::RecipeManager.new(item_manager)
12
+
13
+ opts.fetch(:items, []).each do |file|
14
+ @item_manager.add_from_file(file)
15
+ end
16
+
17
+ opts.fetch(:recipes, []).each do |file|
18
+ @recipe_manager.add_from_file(file)
19
+ end
20
+ end
21
+
22
+ def run
23
+ loop do
24
+ input = gets.chomp
25
+
26
+ exit(0) if ['exit', 'close'].include? input
27
+
28
+ handle(input)
29
+ end
30
+ end
31
+
32
+ def item_search(cmd)
33
+ cmd.match(/item (.*)/) do |match|
34
+ name = match[1].strip
35
+ results = item_manager.find_by_name(name, exact: false, case_sensitive: false)
36
+
37
+ if results.empty?
38
+ puts 'No results found'
39
+ else
40
+ puts results.map { |item| "- #{ item.name } (#{ item.item_id }:#{ item.damage_value })" }.join("\n")
41
+ end
42
+ end
43
+ end
44
+
45
+ def recipe_search(cmd)
46
+ cmd.match(/recipe (.*)/) do |match|
47
+ name = match[1].strip
48
+ results = recipe_manager.find_by_name(name, exact: false, case_sensitive: false).each_with_index.to_a
49
+ if results.empty?
50
+ puts 'No results found'
51
+ return
52
+ else
53
+ puts results.map { |recipe, index| "[#{ index }] #{ recipe.name }" }.join("\n")
54
+ print 'Select recipe: '
55
+ index = gets.chomp
56
+ return if index == 'exit'
57
+ recipe = results[index.to_i].first
58
+ print 'Amount: '
59
+ amount = gets.chomp.to_i
60
+ components = recipe_manager.resolve_recipe(recipe, amount)
61
+ puts "To craft #{ amount } of #{ recipe.name } you need:"
62
+ puts components.map { |item, amount| "- #{ amount } of #{ item.name }" }.join("\n")
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ def usage
69
+ puts 'Commands:'
70
+ puts '`item <item_name>` - Search for items.'
71
+ puts '`recipe <recipe_name>` - Search for, and resolve. recipes.'
72
+ end
73
+
74
+ def handle(cmd)
75
+ if cmd.start_with?('item')
76
+ item_search(cmd)
77
+ elsif cmd.start_with?('recipe')
78
+ recipe_search(cmd)
79
+ else
80
+ usage
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+ def main
87
+
88
+ table = InteractiveTable.new(:items => ['../data/items/vanilla.yml',
89
+ '../data/items/thermal_expansion.yml'],
90
+ :recipes => ['../data/recipes/vanilla.yml',
91
+ '../data/recipes/thermal_expansion.yml'])
92
+
93
+ table.run
94
+
95
+ end
96
+
97
+ main
98
+
@@ -0,0 +1,18 @@
1
+ Feature: Differentiating between several versions of an item
2
+ In order to distinguish between several versions of an item, like several types of wood, or damaged and undamaged tools
3
+ As a developer
4
+ I want to be able to specify a meta value of an item.
5
+
6
+ Scenario: Damage value defaults to 0
7
+ Given I created a new item without damage value
8
+ When I query its damage value
9
+ Then it should be 0
10
+
11
+ Scenario: Same base items with different damage values are not equal
12
+ Given I have these items:
13
+ | name | item_id | damage_value |
14
+ | Axe | 123 | 0 |
15
+ | Axe | 123 | 1 |
16
+
17
+ When I query them for equality
18
+ Then none of them should be equal
@@ -0,0 +1,10 @@
1
+ Feature: Loading items from a data source (file, database, web API, ...)
2
+ In order to be able to store items permanently
3
+ As a developer
4
+ I want to load them from a data source
5
+
6
+ Scenario: Loading an item from a YAML file
7
+ Given I have a YAML file containing multiple items
8
+ When I tell the item manager to load the file
9
+ Then it should contain "371" items
10
+ And it should contain the following items: "Stone, Grass Block, Sand, Gold Ore, Note Block, Piston"
@@ -0,0 +1,26 @@
1
+ Feature: Resolving recipes into their base components
2
+ In order to help me with crafting
3
+ As a user
4
+ I want to be able to resolve recipes into their base components.
5
+
6
+ Background:
7
+ Given I have the vanilla items loaded
8
+ And I have the vanilla recipes loaded
9
+
10
+ Scenario Outline: Resolving the torch recipe
11
+ Given I want <amount_torch> of torches
12
+ When I resolve the recipe
13
+ Then it should require <amount_wood> of wood
14
+ And it should require <amount_coal> of coal
15
+
16
+ # 1 Wood => 4 Planks => 8 Sticks => 32 Torches
17
+ # 1 Coal => 4 Torches
18
+ Examples: Resolving the torch recipe
19
+ | amount_torch | amount_wood | amount_coal |
20
+ | 1 | 1 | 1 |
21
+ | 4 | 1 | 1 |
22
+ | 16 | 1 | 4 |
23
+ | 17 | 1 | 5 |
24
+ | 32 | 1 | 8 |
25
+ | 33 | 2 | 9 |
26
+ | 100 | 4 | 25 |
@@ -0,0 +1,83 @@
1
+ Feature: Searching items by various criteria
2
+ In order to easily retrieve items
3
+ As a developer
4
+ I want to be able to search for items based on various criteria.
5
+
6
+ Background:
7
+ Given I have the following items loaded:
8
+ | Name | Item ID | Damage |
9
+ | Stone | 1 | |
10
+ | Dirt | 3 | |
11
+ | Sand | 12 | |
12
+ | Gold Ore | 14 | |
13
+ | Iron Ore | 15 | |
14
+ | Coal Ore | 16 | |
15
+ | Oak Wood | 17 | 0 |
16
+ | Spruce Wood | 17 | 1 |
17
+ | Birch Wood | 17 | 2 |
18
+ | Jungle Wood | 17 | 3 |
19
+ | Sandstone | 24 | |
20
+
21
+ Scenario Outline: Searching for item's name
22
+ Given I use exact matching: <exact_match>
23
+ And use case sensitivity: <case_sensitive>
24
+ When I search for its name: <name>
25
+ Then it should return the following items: <item_names>
26
+
27
+ Examples: Case-sensitive, exact matching
28
+ | name | exact_match | case_sensitive | item_names |
29
+ | Stone | yes | yes | Stone |
30
+ | Gold Ore | yes | yes | Gold Ore |
31
+ | Ore | yes | yes | |
32
+ | stone | yes | yes | |
33
+
34
+ Examples: Case-insensitive, exact matching
35
+ | name | exact_match | case_sensitive | item_names |
36
+ | Stone | yes | no | Stone |
37
+ | Gold Ore | yes | no | Gold Ore |
38
+ | Ore | yes | no | |
39
+ | stone | yes | no | Stone |
40
+
41
+ Examples: Case-sensitive, non-exact matching
42
+ | name | exact_match | case_sensitive | item_names |
43
+ | Stone | no | yes | Stone |
44
+ | Gold Ore | no | yes | Gold Ore |
45
+ | Ore | no | yes | Gold Ore, Iron Ore, Coal Ore |
46
+ | iron ore | no | yes | |
47
+
48
+ Examples: Case-insensitive, non-exact matching
49
+ | name | exact_match | case_sensitive | item_names |
50
+ | Stone | no | no | Stone, Sandstone |
51
+ | Gold Ore | no | no | Gold Ore |
52
+ | Ore | no | no | Gold Ore, Iron Ore, Coal Ore |
53
+ | stone | no | no | Stone, Sandstone |
54
+
55
+
56
+ Scenario Outline: Searching for item's ID
57
+ When I search for item ID <id>
58
+ Then it should return the following items: <item_names>
59
+
60
+ Examples: Using an integer
61
+ | id | item_names |
62
+ | 1 | Stone |
63
+ | 17 | Oak Wood, Spruce Wood, Birch Wood, Jungle Wood |
64
+
65
+ Examples: Using a range
66
+ | id | item_names |
67
+ | 3..14 | Dirt, Sand, Gold Ore |
68
+
69
+ Scenario Outline: Searching for item's damage value
70
+ When I search for damage value <damage_value>
71
+ Then it should return the following items: <item_names>
72
+
73
+ Examples: Using an integer
74
+ | damage_value | item_names |
75
+ | 2 | Birch Wood |
76
+ | 3 | Jungle Wood |
77
+ | 2..3 | Birch Wood, Jungle Wood |
78
+
79
+ Scenario: Searching for multiple conditions
80
+ When I search for the name 'Wood', using fuzzy matching, and for damage value 3
81
+ Then it should return the following items: Jungle Wood
82
+
83
+
@@ -0,0 +1,42 @@
1
+ Feature: Searching recipes by various criteria
2
+ In order to easily look up recipes
3
+ As a developer
4
+ I want to be able to search for recipes based on various criteria.
5
+
6
+ Background:
7
+ Given I have the vanilla items loaded
8
+ And I have the vanilla recipes loaded
9
+
10
+ Scenario Outline: Searching for recipe's name
11
+ Given I use exact matching: <exact_match>
12
+ And use case sensitivity: <case_sensitive>
13
+ When I search for the recipe's name: <name>
14
+ Then the result should contain the following recipe: <recipe_name>
15
+
16
+ Examples: Case-sensitive, exact matching
17
+ | name | exact_match | case_sensitive | recipe_name |
18
+ | Stone | yes | yes | Stone |
19
+ | Torch | yes | yes | Torch |
20
+ | torch | yes | yes | |
21
+ | Tor | yes | yes | |
22
+
23
+ Examples: Case-insensitive, exact matching
24
+ | name | exact_match | case_sensitive | recipe_name |
25
+ | Stone | yes | no | Stone |
26
+ | Torch | yes | no | Torch |
27
+ | torch | yes | no | Torch |
28
+ | Tor | yes | no | |
29
+
30
+ Examples: Case-sensitive, non-exact matching
31
+ | name | exact_match | case_sensitive | recipe_name |
32
+ | Stone | no | yes | Stone |
33
+ | Torch | no | yes | Torch |
34
+ | torch | no | yes | |
35
+ | Tor | no | yes | Torch |
36
+
37
+ Examples: Case-insensitive, non-exact matching
38
+ | name | exact_match | case_sensitive | recipe_name |
39
+ | Stone | no | no | Stone |
40
+ | Torch | no | no | Torch |
41
+ | torch | no | no | Torch |
42
+ | Tor | no | no | Torch |
@@ -0,0 +1,88 @@
1
+ require 'pry'
2
+
3
+ Given(/^I have the following items loaded:$/) do |table|
4
+ @manager = CraftingTable::ItemManager.new
5
+
6
+ table.raw[1..-1].each do |name, id, damage_value|
7
+ if damage_value.empty?
8
+ damage_value = :any
9
+ else
10
+ damage_value = damage_value.to_i
11
+ end
12
+
13
+ @manager.add(CraftingTable::Item.new(name, id.to_i, damage_value))
14
+ end
15
+ end
16
+
17
+
18
+ Given(/^I have the vanilla items loaded$/) do
19
+ @item_manager = CraftingTable::ItemManager.new
20
+ @item_manager.add_from_file ITEM_FILE
21
+ end
22
+
23
+
24
+ Given(/^(?:I )?use exact matching: (.*)$/) do |exact_match|
25
+ @exact_match = string_to_boolean(exact_match)
26
+ end
27
+
28
+ Given(/^(?:I )?use case sensitivity: (.*)$/) do |case_sensitive|
29
+ @case_sensitive = string_to_boolean(case_sensitive)
30
+ end
31
+
32
+ When(/^I search for its name: (.*)$/) do |name|
33
+ @results = @manager.find do |search|
34
+ search.name = name
35
+ search.case_sensitive = @case_sensitive
36
+ search.exact = @exact_match
37
+ end
38
+ end
39
+
40
+ When(/^I search for item ID (.*)$/) do |item_id|
41
+ @results = @manager.find do |search|
42
+ search.item_id = string_to_range_or_integer(item_id)
43
+ end
44
+ end
45
+
46
+ When(/^I search for damage value (.*)$/) do |damage_value|
47
+ @results = @manager.find do |search|
48
+ search.damage_value = string_to_range_or_integer(damage_value)
49
+ end
50
+ end
51
+
52
+ When(/^I search for the name '([^']*)', using fuzzy matching, and for damage value (\d+)$/) do |name, damage|
53
+ @results = @manager.find do |search|
54
+ search.name = name
55
+ search.damage_value = string_to_range_or_integer(damage)
56
+ search.exact = false
57
+ end
58
+ end
59
+
60
+ Then(/^it should return the following items: (.*)$/) do |item_names|
61
+ expect(@results.map(&:name).sort).to eq (item_names.split(', ').sort)
62
+ end
63
+
64
+
65
+ Then(/^it should return "([^"]*)"$/) do |item_names|
66
+ expect(@results.map(&:name).sort).to eq (item_names.split(', ').sort)
67
+ end
68
+
69
+ Given(/^I have a YAML file containing multiple items$/) do
70
+ expect(File.exist? ITEM_FILE).to be_true
71
+ end
72
+
73
+ When(/^I tell the item manager to load the file$/) do
74
+ @manager = CraftingTable::ItemManager.new
75
+ @manager.add_from_file(ITEM_FILE)
76
+ end
77
+
78
+ Then(/^it should contain "([^"]*)" items$/) do |arg|
79
+ expect(@manager).to have(arg.to_i).items
80
+ end
81
+
82
+ When(/^it should contain the following items: "([^"]*)"$/) do |arg|
83
+ item_names = @manager.items.map(&:name)
84
+
85
+ arg.split(', ').each do |item_name|
86
+ expect(item_names).to include item_name
87
+ end
88
+ end
@@ -0,0 +1,23 @@
1
+ Given(/^I created a new item without damage value$/) do
2
+ @item = CraftingTable::Item.new('Stone', 1)
3
+ end
4
+
5
+ When(/^I query its damage value$/) do
6
+ @result = @item.damage_value
7
+ end
8
+
9
+ Then(/^it should be 0$/) do
10
+ expect(@result).to eq 0
11
+ end
12
+
13
+ Given(/^I have these items:$/) do |table|
14
+ @items = table.raw[1..-1].map { |name, id, damage| CraftingTable::Item.new(name, id, damage) }
15
+ end
16
+
17
+ When(/^I query them for equality$/) do
18
+ @results = @items.combination(2).map { |item_1, item_2| item_1 == item_2 }
19
+ end
20
+
21
+ Then(/^none of them should be equal$/) do
22
+ expect(@results.any?).to be_false
23
+ end
@@ -0,0 +1,42 @@
1
+ When(/^I have the vanilla recipes loaded$/) do
2
+ @recipe_manager = CraftingTable::RecipeManager.new(@item_manager)
3
+ @recipe_manager.add_from_file RECIPE_FILE
4
+ end
5
+
6
+ When(/^I search for the recipe's name: (.*)$/) do |name|
7
+ @results = @recipe_manager.find do |search|
8
+ search.name = name
9
+ search.case_sensitive = @case_sensitive
10
+ search.exact = @exact_match
11
+ end
12
+ end
13
+
14
+ Then(/^the result should contain the following recipe: (.*)$/) do |recipe_name|
15
+ if recipe_name.empty?
16
+ expect(@results).to be_empty
17
+ else
18
+ expect(@results.map(&:name)).to include recipe_name
19
+ end
20
+ end
21
+
22
+
23
+ Given(/^I want (\d+) of torches$/) do |amount_torch|
24
+ @amount = amount_torch.to_i
25
+ end
26
+
27
+ When(/^I resolve the recipe$/) do
28
+ recipe_torch = @recipe_manager.find_by_name('Torch').first
29
+ @result = @recipe_manager.resolve_recipe(recipe_torch, @amount)
30
+ end
31
+
32
+ Then(/^it should require (\d+) of wood$/) do |amount_wood|
33
+ item_wood = @item_manager.find_by_name('Wood').select { |item| item.damage_value == 0 }.first
34
+
35
+ expect(@result[item_wood]).to eq amount_wood.to_i
36
+ end
37
+
38
+ Then(/^it should require (\d+) of coal$/) do |amount_coal|
39
+ item_coal = @item_manager.find_by_name('Coal').first
40
+
41
+ expect(@result[item_coal]).to eq amount_coal.to_i
42
+ end