Add code to build crafting trees
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
###
|
||||
Crafting Guide - crafting_node.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class CraftingNode
|
||||
|
||||
constructor: (options={})->
|
||||
if not options.modPack? then throw new Error 'options.modPack is required'
|
||||
|
||||
@modPack = options.modPack
|
||||
|
||||
@_children = []
|
||||
@_complete = null
|
||||
@_valid = null
|
||||
|
||||
# Public Methods ###############################################################################
|
||||
|
||||
expand: (queue=[])->
|
||||
return queue if @children.length > 0
|
||||
|
||||
for child in @_createChildren()
|
||||
child.parent = this
|
||||
@_children.push child
|
||||
queue.push child
|
||||
return queue
|
||||
|
||||
getNode: (path)->
|
||||
return null unless _.isArray(path) and path.length > 0
|
||||
|
||||
child = @children[path[0]]
|
||||
return null unless child?
|
||||
|
||||
return child.getPath path[1..]
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
getChildren: ->
|
||||
return @_children
|
||||
|
||||
isComplete: ->
|
||||
if not @_complete?
|
||||
@_complete = @_checkCompleteness()
|
||||
return @_complete
|
||||
|
||||
getCompleteText: ->
|
||||
return if @complete then "✓" else "✗"
|
||||
|
||||
getDepth: ->
|
||||
maxDepth = 1
|
||||
for child in @children
|
||||
maxDepth = Math.max maxDepth, child.getDepth() + 1
|
||||
return maxDepth
|
||||
|
||||
getSize: ->
|
||||
size = 1
|
||||
for child in @children
|
||||
size += child.size
|
||||
return size
|
||||
|
||||
getNodeType: ->
|
||||
return @_nodeType
|
||||
|
||||
isValid: ->
|
||||
return @_valid if @_valid?
|
||||
|
||||
valid = @_checkValidity()
|
||||
@_valid = false if not valid
|
||||
|
||||
return valid
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
children: { get:@prototype.getChildren }
|
||||
complete: { get:@prototype.isComplete }
|
||||
completeText: { get:@prototype.getCompleteText }
|
||||
depth: { get:@prototype.getDepth }
|
||||
size: { get:@prototype.getSize }
|
||||
|
||||
|
||||
# Virtual Methods ##############################################################################
|
||||
|
||||
# Subclasses must override this method to create such children as are appropriate for that kind of node. The new
|
||||
# nodes should be appended to the given array.
|
||||
_createChildren: (result)->
|
||||
throw new Error "#{@constructor.name} must override the _createChildren method"
|
||||
|
||||
# Subclasses must override this method to indicate whether the node has at least one "complete" subtree rooted with
|
||||
# itself. Completeness may be defined differently by different subclasses.
|
||||
_checkCompleteness: ->
|
||||
throw new Error "#{@constructor.name} must override the _checkCompletness method"
|
||||
|
||||
# Subclasses must override this method to determine whether the subtree represented by a node should still be
|
||||
# explored for having a useful crafting plan.
|
||||
_checkValidity: ->
|
||||
throw new Error "#{@constructor.name} must override the _checkValidity method"
|
||||
@@ -0,0 +1,72 @@
|
||||
###
|
||||
Crafting Guide - graph_builder.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
Inventory = require '../inventory'
|
||||
InventoryNode = require './inventory_node'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class GraphBuilder
|
||||
|
||||
constructor: (options={})->
|
||||
if not options.modPack? then throw new Error 'options.modPack is required'
|
||||
|
||||
@modPack = options.modPack
|
||||
@_wanted = options.wanted ?= new Inventory
|
||||
|
||||
@_wanted.on 'change', => @reset()
|
||||
|
||||
@reset()
|
||||
|
||||
# Public Methods ###############################################################################
|
||||
|
||||
expandGraph: (steps=null)->
|
||||
maxSteps = if steps? then @_stepCount + steps else Number.MAX_VALUE
|
||||
@_queue ?= []
|
||||
|
||||
while true
|
||||
break if @_queue.length is 0
|
||||
break if @_stepCount >= maxSteps
|
||||
|
||||
node = @_queue.shift()
|
||||
break unless node?
|
||||
|
||||
node.expand @_queue
|
||||
@_stepCount += 1
|
||||
|
||||
reset: ->
|
||||
@_rootNode = new InventoryNode modPack:@modPack, inventory:@wanted
|
||||
@_queue = [@_rootNode]
|
||||
@_stepCount = 0
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
isComplete: ->
|
||||
return false unless @_rootNode?
|
||||
return false unless @_queue?
|
||||
return false unless @_queue.length is 0
|
||||
return true
|
||||
|
||||
getRootNode: ->
|
||||
return @_rootNode
|
||||
|
||||
getStepCount: ->
|
||||
return @_stepCount
|
||||
|
||||
getWanted: ->
|
||||
return @_wanted
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
complete: { get:@prototype.isComplete }
|
||||
rootNode: { get:@prototype.getRootNode }
|
||||
stepCount: { get:@prototype.getStepCount }
|
||||
wanted: { get:@prototype.getWanted }
|
||||
|
||||
# Object Overrides ############################################################################
|
||||
|
||||
toString: (indent='')->
|
||||
"Build Tree\n#{@_rootNode.toString(indent + ' ')}"
|
||||
@@ -0,0 +1,47 @@
|
||||
###
|
||||
Crafting Guide - crafting_plan_node.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
CraftingNode = require './crafting_node'
|
||||
ItemNode = require './item_node'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class InventoryNode extends CraftingNode
|
||||
|
||||
constructor: (options={})->
|
||||
if not options.inventory? then throw new Error 'options.inventory is required'
|
||||
super options
|
||||
|
||||
@inventory = options.inventory
|
||||
|
||||
# CraftingNode Overrides #######################################################################
|
||||
|
||||
_createChildren: (result=[])->
|
||||
@inventory.each (stack)=>
|
||||
item = @modPack.findItem stack.itemSlug
|
||||
if not item? then throw new Error "Could not find an item for slug: #{stack.itemSlug}"
|
||||
result.push new ItemNode modPack:@modPack, item:item
|
||||
return result
|
||||
|
||||
_checkCompleteness: ->
|
||||
for child in @children
|
||||
return false unless child.isComplete
|
||||
return true
|
||||
|
||||
_checkValidity: ->
|
||||
for child in @children
|
||||
return false unless child.isValid
|
||||
|
||||
# Object Overrides #############################################################################
|
||||
|
||||
toString: (indent='')->
|
||||
completeText = if @complete then 'complete' else 'incomplete'
|
||||
parts = ["#{indent}#{@completeText} InventoryNode for #{@inventory}"]
|
||||
nextIndent = indent + ' '
|
||||
for child in @children
|
||||
parts.push child.toString nextIndent
|
||||
return parts.join '\n'
|
||||
@@ -0,0 +1,69 @@
|
||||
###
|
||||
Crafting Guide - item_node.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
CraftingNode = require './crafting_node'
|
||||
RecipeNode = require './recipe_node'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class ItemNode extends CraftingNode
|
||||
|
||||
constructor: (options={})->
|
||||
if not options.item? then throw new Error 'options.item is required'
|
||||
super options
|
||||
|
||||
@item = options.item
|
||||
@_recipes = null
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
getRecipes: ->
|
||||
if not @_recipes?
|
||||
@_recipes = @modPack.findRecipes @item.slug
|
||||
return @_recipes or []
|
||||
|
||||
isGatherable: ->
|
||||
return true if @item.isGatherable
|
||||
return true unless @getRecipes().length > 0
|
||||
return false
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
gatherable: { get:@prototype.isGatherable }
|
||||
recipes: { get:@prototype.getRecipes }
|
||||
|
||||
# CraftingNode Overrides #######################################################################
|
||||
|
||||
_createChildren: (result=[])->
|
||||
recipes = @getRecipes()
|
||||
return [] unless recipes.length > 0
|
||||
|
||||
for recipe in recipes
|
||||
result.push new RecipeNode modPack:@modPack, recipe:recipe
|
||||
|
||||
return result
|
||||
|
||||
_checkCompleteness: ->
|
||||
return true if @gatherable
|
||||
return false unless @children?
|
||||
|
||||
for child in @children
|
||||
return true if child.isComplete
|
||||
return false
|
||||
|
||||
_checkValidity: ->
|
||||
for child in @children
|
||||
return true if child.isValid
|
||||
|
||||
# Object Overrides #############################################################################
|
||||
|
||||
toString: (indent)->
|
||||
completeText = if @complete then 'complete' else 'incomplete'
|
||||
parts = ["#{indent}#{@completeText} ItemNode for #{@item.name}"]
|
||||
nextIndent = indent + ' '
|
||||
for child in @children
|
||||
parts.push child.toString nextIndent
|
||||
return parts.join '\n'
|
||||
@@ -0,0 +1,61 @@
|
||||
###
|
||||
Crafting Guide - recipe_node.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
CraftingNode = require './crafting_node'
|
||||
# ItemNode = require './item_node' # don't include here, causes a cycle
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class RecipeNode extends CraftingNode
|
||||
|
||||
constructor: (options={})->
|
||||
if not options.recipe? then throw new Error 'options.recipe is required'
|
||||
super options
|
||||
|
||||
@recipe = options.recipe
|
||||
|
||||
# CraftingNode Overrides #######################################################################
|
||||
|
||||
_createChildren: (result=[])->
|
||||
ItemNode = require './item_node' # include here to avoid a cycle
|
||||
|
||||
for stack in @recipe.input
|
||||
item = @modPack.findItem stack.itemSlug
|
||||
result.push new ItemNode modPack:@modPack, item:item
|
||||
return result
|
||||
|
||||
_checkCompleteness: ->
|
||||
for child in @children
|
||||
return false unless child.isComplete
|
||||
return true
|
||||
|
||||
_checkValidity: ->
|
||||
for child in @children
|
||||
return false unless child.isValid
|
||||
|
||||
return false if @_isRepeatedRecipe()
|
||||
return true
|
||||
|
||||
# Private Methods ##############################################################################
|
||||
|
||||
_isRepeatedRecipe: ->
|
||||
nextParent = @parent
|
||||
while nextParent?
|
||||
return true if nextParent.recipe is @recipe
|
||||
nextParent = nextParent.parent
|
||||
|
||||
return false
|
||||
|
||||
# Object Overrides ############################################################################
|
||||
|
||||
toString: (indent)->
|
||||
completeText = if @complete then 'complete' else 'incomplete'
|
||||
parts = ["#{indent}#{@completeText} RecipeNode for #{@recipe.slug}"]
|
||||
nextIndent = indent + ' '
|
||||
for child in @children
|
||||
parts.push child.toString nextIndent
|
||||
return parts.join '\n'
|
||||
@@ -170,7 +170,7 @@ module.exports = class Inventory extends BaseModel
|
||||
# Object Overrides #############################################################################
|
||||
|
||||
toString: ->
|
||||
result = [@constructor.name, " (", @cid, ") { items: ["]
|
||||
result = [@constructor.name, " (", @cid, ") {items: ["]
|
||||
|
||||
needsDelimiter = false
|
||||
@each (stack)->
|
||||
|
||||
Reference in New Issue
Block a user