crafting_table 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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