Major updates to the crafting algo.

* Update crafting algo. to favor highest output recipes for making
  items, and to be more flexible about trying a variety of recipes if
  some one recipe doesn't work.
* Modify crafting algo. to allow crafting of "gatherable" items.
* Update logger to support indent/outdent for clearer formatting
* Convert IC2 Forge Hammer / Cutter recipes to treat them as tools
This commit is contained in:
Andrew Miner
2015-02-18 21:29:21 -08:00
parent aab3baec1a
commit b1a6637005
6 changed files with 148 additions and 111 deletions
@@ -566,9 +566,9 @@ group: Energy: Transmission
item: Copper Cable
recipe:
extras: Cutter
input: Copper Plate, Cutter
pattern: ... 01. ...
tools: Cutter
input: Copper Plate
pattern: ... .0. ...
quantity: 2
recipe:
input: Copper Ingot
@@ -607,9 +607,9 @@ group: Energy: Transmission
item: Gold Cable
recipe:
extras: Cutter
input: Cutter, Gold Plate
pattern: ... 10. ...
tools: Cutter
input: Gold Plate
pattern: ... .0. ...
quantity: 4
recipe:
input: Gold Ingot
@@ -674,9 +674,9 @@ group: Energy: Transmission
item: Tin Cable
recipe:
extras: Cutter
input: Cutter, Tin Plate
pattern: ... 10. ...
tools: Cutter
input: Tin Plate
pattern: ... .0. ...
quantity: 3
recipe:
input: Tin Ingot
@@ -735,9 +735,9 @@ group: Machine Parts
item: Bronze Item Casing
recipe:
extras: Forge Hammer
input: Bronze Plate, Forge Hammer
pattern: ... 01. ...
tools: Forge Hammer
input: Bronze Plate
pattern: ... .0. ...
quantity: 2
recipe:
input: Bronze Plate
@@ -747,9 +747,9 @@ group: Machine Parts
item: Bronze Plate
recipe:
extras: Forge Hammer
input: Bronze Ingot, Forge Hammer
pattern: ... 01. ...
tools: Forge Hammer
input: Bronze Ingot
pattern: ... .0. ...
recipe:
input: Bronze Ingot
pattern: ... .0. ...
@@ -786,9 +786,9 @@ group: Machine Parts
item: Copper Item Casing
recipe:
extras: Forge Hammer
input: Copper Plate, Forge Hammer
pattern: ... 01. ...
tools: Forge Hammer
input: Copper Plate
pattern: ... .0. ...
quantity: 2
recipe:
input: Copper Plate
@@ -798,9 +798,9 @@ group: Machine Parts
item: Copper Plate
recipe:
extras: Forge Hammer
input: Copper Ingot, Forge Hammer
pattern: ... 01. ...
tools: Forge Hammer
input: Copper Ingot
pattern: ... .0. ...
recipe:
input: Copper Ingot
pattern: ... .0. ...
@@ -909,9 +909,9 @@ group: Machine Parts
item: Gold Item Casing
recipe:
extras: Forge Hammer
input: Forge Hammer, Gold Plate
pattern: ... 10. ...
tools: Forge Hammer
input: Gold Plate
pattern: ... .0. ...
quantity: 2
recipe:
input: Gold Plate
@@ -921,9 +921,9 @@ group: Machine Parts
item: Gold Plate
recipe:
extras: Forge Hammer
input: Forge Hammer, Gold Ingot
pattern: ... 10. ...
tools: Forge Hammer
input: Gold Ingot
pattern: ... .0. ...
recipe:
input: Gold Ingot
pattern: ... .0. ...
@@ -941,9 +941,9 @@ group: Machine Parts
item: Iron Item Casing
recipe:
extras: Forge Hammer
input: Forge Hammer, Iron Plate
pattern: ... 10. ...
tools: Forge Hammer
input: Iron Plate
pattern: ... .0. ...
quantity: 2
recipe:
input: Iron Plate
@@ -953,9 +953,9 @@ group: Machine Parts
item: Iron Plate
recipe:
extras: Forge Hammer
input: Forge Hammer, Iron Ingot
pattern: ... 10. ...
tools: Forge Hammer
input: Iron Ingot
pattern: ... .0. ...
recipe:
input: Iron Ingot
pattern: ... .0. ...
@@ -1026,9 +1026,9 @@ group: Machine Parts
item: Lead Item Casing
recipe:
extras: Forge Hammer
input: Forge Hammer, Lead Plate
pattern: ... 10. ...
tools: Forge Hammer
input: Lead Plate
pattern: ... .0. ...
quantity: 2
recipe:
input: Lead Plate
@@ -1038,9 +1038,9 @@ group: Machine Parts
item: Lead Plate
recipe:
extras: Forge Hammer
input: Forge Hammer, Lead Ingot
pattern: ... 10. ...
tools: Forge Hammer
input: Lead Ingot
pattern: ... .0. ...
recipe:
input: Lead Ingot
pattern: ... .0. ...
@@ -1230,9 +1230,9 @@ group: Machine Parts
item: Tin Item Casing
recipe:
extras: Forge Hammer
input: Forge Hammer, Tin Plate
pattern: ... 10. ...
tools: Forge Hammer
input: Tin Plate
pattern: ... .0. ...
quantity: 2
recipe:
input: Tin Plate
@@ -1242,9 +1242,9 @@ group: Machine Parts
item: Tin Plate
recipe:
extras: Forge Hammer
input: Forge Hammer, Tin Ingot
pattern: ... 10. ...
tools: Forge Hammer
input: Tin Ingot
pattern: ... .0. ...
recipe:
input: Tin Ingot
pattern: ... .0. ...
@@ -1859,31 +1859,6 @@ group: Minerals
tools: Furnace
item: Slag
recipe:
extras: Reinforced Iron Ingot, Empty Cell
input: Compressed Air Cell, Iron Ore
pattern: ... .1. .0.
tools: Blast Furnace
recipe:
extras: Reinforced Iron Ingot, Empty Cell
input: Compressed Air Cell, Iron Dust
pattern: ... .1. .0.
tools: Blast Furnace
recipe:
extras: Reinforced Iron Ingot, Empty Cell
input: Compressed Air Cell, Iron Ingot
pattern: ... .1. .0.
tools: Blast Furnace
recipe:
extras: Reinforced Iron Ingot, Empty Cell
input: Compressed Air Cell, Crushed Iron Ore
pattern: ... .1. .0.
tools: Blast Furnace
recipe:
extras: Reinforced Iron Ingot, Empty Cell
input: Compressed Air Cell, Purified Crushed Iron Ore
pattern: ... .1. .0.
tools: Blast Furnace
item: Steam
@@ -3135,3 +3110,9 @@ update: Iron Ingot
input: Iron Dust, furnace fuel
pattern: .0. ... .1.
tools: Furnace
update: Diamond
recipe:
input: Coal Chunk
pattern: ... .0. ...
tools: Compressor
+14 -3
View File
@@ -21,16 +21,23 @@ module.exports = class Logger
constructor: (options={})->
options.level ?= Logger.FATAL
@formatText = if options.format? then options.format else "<%= timestamp %> | <%= level %> | <%= message %>"
@formatText = options.format
@formatText ?= "<%= timestamp %> | <%= level %> | <%= indent %><%= message %>"
@level = @_parseLevel options
@_format = _.template @formatText
@_format = _.template @formatText
@_indent = ''
# Public Methods ###############################################################################
indent: ->
@_indent += ' '
log: (level, message)->
return unless level.value >= @level.value
message = message() if _.isFunction message
entry = {timestamp:new Date(), level:level, message:message}
entry = {timestamp:new Date(), level:level, message:message, indent:@_indent}
entry.level ?= @level
lines = @_formatEntry entry
@@ -39,6 +46,9 @@ module.exports = class Logger
else
console.error(line) for line in lines
outdent: ->
@_indent = @_indent[0...@_indent.length - 4]
# Log Methods ##################################################################################
trace: (message)-> @log Logger.TRACE, message
@@ -67,6 +77,7 @@ module.exports = class Logger
timestamp: "#{entry.timestamp}"
level: entry.level.name
message: line
indent: entry.indent
lines.push result.join ''
return lines
+50 -20
View File
@@ -8,6 +8,7 @@ All rights reserved.
BaseModel = require './base_model'
{Event} = require '../constants'
Inventory = require './inventory'
ItemSlug = require './item_slug'
########################################################################################################################
@@ -53,14 +54,12 @@ module.exports = class CraftingPlan extends BaseModel
@result.addInventory @have
@steps = {}
@_reservedSteps = {}
@want.each (stack)=>
@_findSteps stack.itemSlug
@_findSteps stack.itemSlug, {}, ignoreGatherable:true
item = @modPack.findItem stack.itemSlug
@need.add item.slug, stack.quantity
@_reservedSteps = null
@steps = _.values @steps
@steps = (recipe:recipe for recipeSlug, recipe of @steps)
@_resolveNeeds()
@_removeExtraSteps()
@@ -99,38 +98,69 @@ module.exports = class CraftingPlan extends BaseModel
# Private Methods ##############################################################################
_addStep: (recipe)->
logger.verbose -> "adding step: #{recipe.itemSlug}"
@steps[recipe.itemSlug] = recipe:recipe
logger.verbose -> "adding step for: #{recipe.slug}"
@steps[recipe.slug] = recipe
_chooseRecipe: (item)->
recipes = @modPack.findRecipes item.slug
return null unless recipes? and recipes.length > 0
return recipes[0]
_findSteps: (itemSlug)->
_findSteps: (itemSlug, parentSteps={})->
item = @modPack.findItem itemSlug
return unless item?
return unless item.isCraftable
return if item.isGatherable
recipe = @_chooseRecipe item
ignoreGatherable = @want.hasAtLeast itemSlug, 1
if (not item.isGatherable) or ignoreGatherable
recipes = @modPack.findRecipes item.slug
recipes ?= []
if @includingTools
for toolStack in recipe.tools
if not @_hasStep toolStack.itemSlug
@_findSteps toolStack.itemSlug
if parentSteps[item.slug]?
logger.verbose -> "found cycle at #{item.slug}"
throw new Error 'invalid recipe path'
parentSteps[item.slug] = item
return if @_hasStep item.slug
@_reservedSteps[item.slug] = recipe
logger.verbose -> "exploring: #{item.slug}"
logger.indent()
for inputStack in recipe.input
@_findSteps inputStack.itemSlug
currentSteps = _.clone @steps
foundValidRecipe = false
for i in [0...recipes.length] by 1
recipe = recipes[i]
logger.verbose -> "trying recipe #{i+1} of #{recipes.length}: #{recipe.slug}"
if @steps[recipe.slug]?
logger.verbose -> "already accepted this recipe"
foundValidRecipe = true
break
@_addStep recipe
try
if @includingTools
for toolStack in recipe.tools
if not @_hasStep toolStack.itemSlug
@_findSteps toolStack.itemSlug, parentSteps
for inputStack in recipe.input
@_findSteps inputStack.itemSlug, parentSteps
@_addStep recipe
foundValidRecipe = true
break
catch error
logger.verbose -> "recipe didn't work out: #{recipe.slug}"
if error.message isnt 'invalid recipe path' then throw error
@steps = _.clone currentSteps
delete parentSteps[item.slug]
logger.outdent()
if not (foundValidRecipe or item.isGatherable)
logger.verbose -> "could not find a valid recipe for #{item.slug}"
throw new Error 'invalid recipe path'
_hasStep: (itemSlug)->
return true if @steps[itemSlug]?
return true if @_reservedSteps[itemSlug]?
for recipeSlug, recipe of @steps
return true if recipe.produces itemSlug
return false
_qualifyItemSlug: (itemSlug)->
+4 -8
View File
@@ -84,14 +84,10 @@ module.exports = class ModPack extends BaseModel
findRecipes: (itemSlug, result=[])->
return null unless itemSlug?
if itemSlug.isQualified
mod = @getMod itemSlug.mod
if mod? then mod.findRecipes itemSlug, result
if result.length is 0
for mod in @_mods
continue unless mod.enabled
mod.findRecipes itemSlug, result
for mod in @_mods
continue unless mod.enabled
continue if itemSlug.isQualified and itemSlug.mod isnt mod.slug
mod.findRecipes itemSlug, result
result.sort (a, b)-> Recipe.compareFor a, b, itemSlug
+22 -3
View File
@@ -5,8 +5,9 @@ Copyright (c) 2014-2015 by Redwood Labs
All rights reserved.
###
BaseModel = require './base_model'
Stack = require './stack'
BaseModel = require './base_model'
Stack = require './stack'
StringBuilder = require './string_builder'
########################################################################################################################
@@ -43,7 +44,7 @@ module.exports = class Recipe extends BaseModel
aValue = a.getQuantityProducedOf itemSlug
bValue = b.getQuantityProducedOf itemSlug
if aValue isnt bValue
return if aValue < bValue then -1 else +1
return if aValue > bValue then -1 else +1
aValue = a.getInputCount()
bValue = b.getInputCount()
@@ -102,6 +103,24 @@ module.exports = class Recipe extends BaseModel
return true
return false
# Property Methods #############################################################################
getSlug: ->
if not @_slug?
builder = new StringBuilder
builder
.loop(@input, delimiter:',', onEach:(b, stack)-> b.push stack.itemSlug.qualified)
.onlyIf @tools.length > 0, (b)=>
b.push(' + ').loop(@tools, delimiter:',', onEach:(b, stack)-> b.push stack.itemSlug.qualified)
.push(' => ')
.loop(@output, delimiter:',', onEach:(b, stack)-> b.push stack.itemSlug.qualified)
@_slug = builder.toString()
return @_slug
Object.defineProperties @prototype,
slug: {get:@prototype.getSlug}
# Object Overrides #############################################################################
toString: ->
+7 -7
View File
@@ -45,25 +45,25 @@ describe 'crafting_plan.coffee', ->
plan.want.add ItemSlug.slugify 'oak_plank'
plan.craft()
plan.need.unparse().should.equal 'oak_log'
plan.result.unparse().should.equal '4.minecraft__oak_plank'
plan.result.unparse().should.equal '4.oak_plank'
it 'can craft a multi-step recipe', ->
plan.want.add ItemSlug.slugify 'crafting_table'
plan.craft()
plan.need.unparse().should.equal 'oak_log'
plan.result.unparse().should.equal 'minecraft__crafting_table'
plan.result.unparse().should.equal 'crafting_table'
it 'can craft a multi-step recipe using tools', ->
plan.want.add ItemSlug.slugify 'furnace'
plan.craft()
plan.need.unparse().should.equal '8.cobblestone'
plan.result.unparse().should.equal 'minecraft__furnace'
plan.result.unparse().should.equal 'furnace'
it 'can craft a multi-step recipe re-using tools', ->
plan.want.add ItemSlug.slugify 'iron_sword'
plan.craft()
plan.need.unparse().should.equal '2.furnace_fuel:2.iron_ore:oak_log'
plan.result.unparse().should.equal 'minecraft__iron_sword:2.minecraft__oak_plank:3.minecraft__stick'
plan.result.unparse().should.equal 'iron_sword:2.oak_plank:3.stick'
describe 'with building tools', ->
@@ -72,7 +72,7 @@ describe 'crafting_plan.coffee', ->
plan.want.add ItemSlug.slugify 'furnace'
plan.craft()
plan.need.unparse().should.equal '8.cobblestone:oak_log'
plan.result.unparse().should.equal 'minecraft__crafting_table:minecraft__furnace'
plan.result.unparse().should.equal 'crafting_table:furnace'
it 'can craft a multi-step recipe re-using tools', ->
plan.includingTools = true
@@ -80,5 +80,5 @@ describe 'crafting_plan.coffee', ->
plan.craft()
plan.need.unparse().should.eql '8.cobblestone:2.furnace_fuel:2.iron_ore:2.oak_log'
plan.result.unparse().should.equal 'minecraft__crafting_table:minecraft__furnace:' +
'minecraft__iron_sword:2.minecraft__oak_plank:3.minecraft__stick'
plan.result.unparse().should.equal 'crafting_table:furnace:' +
'iron_sword:2.oak_plank:3.stick'