Files
website/src/coffee/models/crafting/craftsman.coffee
T
2015-10-31 13:21:14 -07:00

141 lines
4.4 KiB
CoffeeScript

###
Crafting Guide - craftsman.coffee
Copyright (c) 2015 by Redwood Labs
All rights reserved.
###
_ = require 'underscore'
BaseModel = require '../base_model'
{Event} = require '../../constants'
GraphBuilder = require './graph_builder'
Inventory = require '../inventory'
PlanBuilder = require './plan_builder'
PlanEvaluator = require './plan_evaluator'
w = require 'when'
########################################################################################################################
module.exports = class Craftsman extends BaseModel
@::ANALYZE_STEP_INCREMENT = 100
@::GRAPH_STEP_INCREMENT = 10
@::PLAN_STEP_INCREMENT = 50
@::STAGE =
WAITING: 'waiting'
GRAPHING: 'examining recipes'
PLANNING: 'computing plans'
ANALYZING: 'analyzing plans'
COMPLETE: 'complete'
constructor: (modPack)->
if not modPack? then throw new Error 'modPack is required'
attributes =
paused: false
stage: @STAGE.WAITING
stageCount: 0
super attributes, {}
@_modPack = modPack
reset = _.throttle (=> @reset()), 100
@_have = new Inventory
@_have.on Event.change, reset
@_want = new Inventory
@_want.on Event.change, reset
@on Event.change + ':paused', reset
@on Event.change + ':stage', => logger.info "Craftsman has started #{@stage}..."
@reset()
# Public Methods ###############################################################################
work: ->
return if @_want.isEmpty
logger.verbose => "stage: #{@stage}(#{@stageCount}) working..."
if not @_graphBuilder?
want = new Inventory {modPack:@_modPack}, clone:@_want
want.localize()
have = new Inventory {modPack:@_modPack}, clone:@_have
have.localize()
logger.info -> "Craftsman starting to build #{want} from #{have}"
@_graphBuilder = new GraphBuilder modPack:@_modPack, want:want, have:have
@stage = @STAGE.GRAPHING
@stageCount = 0
else if not @_graphBuilder.complete
@_graphBuilder.expandGraph @GRAPH_STEP_INCREMENT
@stageCount = @_graphBuilder.stepCount
else if not @_planBuilder?
logger.debug => "Craftsman finished computing graph:\n#{@_graphBuilder.rootNode}"
@_planBuilder = new PlanBuilder @_graphBuilder.rootNode, @_modPack, want:@_graphBuilder.want
@stage = @STAGE.PLANNING
@stageCount = 0
else if not @_planBuilder.complete
@_planBuilder.producePlans @PLAN_STEP_INCREMENT
@stageCount = @_planBuilder.plans.length
else if not @_planEvaluator?
@_planEvaluator = new PlanEvaluator @_planBuilder.plans
@stage = @STAGE.ANALYZING
@stageCount = 0
else if not @_planEvaluator.complete
@_planEvaluator.scorePlans @ANALYZE_STEP_INCREMENT
@stageCount = @_planEvaluator.lastScored
else
@_plans = [
@_planEvaluator.findBestPlan PlanEvaluator::CRITERIA.FEWEST_STEPS
@_planEvaluator.findBestPlan PlanEvaluator::CRITERIA.LEAST_MATERIALS
]
@_plans[0].computeRequired()
logger.info => "Craftsman has finished with plans: #{(p.toString() for p in @_plans).join('\n')}"
@trigger Event.change + ':complete', this
@trigger Event.change, this
@_scheduleNextWork()
return @complete
reset: ->
@_graphBuilder = null
@_planBuilder = null
@_planEvaluator = null
@_plans = null
@stage = @STAGE.WAITING
@stageCount = 0
@_scheduleNextWork()
# Property Methods #############################################################################
Object.defineProperties @prototype,
complete:
get: -> @_plans?
have:
get: -> @_have
plan:
get: -> @_plans?[0]
want:
get: -> @_want
# Private Methods ##############################################################################
_scheduleNextWork: ->
return if @paused
return if @want.isEmpty
return if @complete
_.defer => @work()