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