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.
- checksums.yaml +7 -0
- checksums.yaml.gz.asc +11 -0
- data.tar.gz.asc +11 -0
- data/.gitignore +0 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +41 -0
- data/LICENSE +14 -0
- data/Rakefile +0 -0
- data/crafting_table.gemspec +19 -0
- data/data/items/thermal_expansion.yml +64 -0
- data/data/items/vanilla.yml +1152 -0
- data/data/recipes/thermal_expansion.yml +97 -0
- data/data/recipes/vanilla.yml +25 -0
- data/data/test/items/vanilla.yml +1149 -0
- data/data/test/recipes/vanilla.yml +25 -0
- data/examples/interactive_table.rb +98 -0
- data/features/item_differentiation.feature +18 -0
- data/features/loading_items.feature +10 -0
- data/features/resolving_recipes.feature +26 -0
- data/features/searching_items.feature +83 -0
- data/features/searching_recipes.feature +42 -0
- data/features/step_definitions/item_manager_steps.rb +88 -0
- data/features/step_definitions/item_steps.rb +23 -0
- data/features/step_definitions/recipe_manager_steps.rb +42 -0
- data/features/support/env.rb +29 -0
- data/lib/crafting_table.rb +19 -0
- data/lib/crafting_table/item.rb +61 -0
- data/lib/crafting_table/item_manager.rb +171 -0
- data/lib/crafting_table/recipe.rb +36 -0
- data/lib/crafting_table/recipe_manager.rb +216 -0
- data/lib/crafting_table/search/damage_search.rb +51 -0
- data/lib/crafting_table/search/fuzzy_name_search.rb +39 -0
- data/lib/crafting_table/search/input_search.rb +47 -0
- data/lib/crafting_table/search/item_id_search.rb +51 -0
- data/lib/crafting_table/search/name_search.rb +71 -0
- data/lib/crafting_table/search/output_search.rb +47 -0
- data/lib/crafting_table/search/search_builder.rb +85 -0
- data/spec/crafting_table/item_manager_spec.rb +421 -0
- data/spec/crafting_table/item_spec.rb +67 -0
- data/spec/crafting_table/recipe_manager_spec.rb +353 -0
- data/spec/crafting_table/recipe_spec.rb +25 -0
- data/spec/crafting_table/search/search_builder.rb +105 -0
- data/spec/crafting_table/search/search_spec.rb +383 -0
- data/spec/spec_helper.rb +6 -0
- metadata +145 -0
- 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
|