The algorithm will now give higher rankings to items containing multiple sequential letters which match, and higher rankings to those whose length more closely matches the given term.
104 lines
3.3 KiB
CoffeeScript
104 lines
3.3 KiB
CoffeeScript
#
|
|
# Crafting Guide - item_selector.coffee
|
|
#
|
|
# Copyright © 2014-2016 by Redwood Labs
|
|
# All rights reserved.
|
|
#
|
|
|
|
BaseModel = require '../base_model'
|
|
ItemSlug = require '../game/item_slug'
|
|
|
|
########################################################################################################################
|
|
|
|
module.exports = class ItemSelector extends BaseModel
|
|
|
|
constructor: (attributes={}, options={})->
|
|
if not options.modPack? then throw new Error 'options.modPack is required'
|
|
options.isAcceptable ?= (item)-> return true # accept everything by default
|
|
super attributes, options
|
|
|
|
@_isAcceptable = options.isAcceptable
|
|
@_maxResults = 100
|
|
@_minHintLength = 3
|
|
@_modPack = options.modPack
|
|
@_results = []
|
|
|
|
# Property Methods #############################################################################
|
|
|
|
Object.defineProperties @prototype,
|
|
|
|
hint:
|
|
get: ->
|
|
return @_hint
|
|
|
|
set: (newHint)->
|
|
oldHint = @_hint
|
|
return if newHint is oldHint
|
|
|
|
@_hint = newHint.toLowerCase()
|
|
|
|
@trigger c.event.change + ':hint', this, oldHint, newHint
|
|
@_refreshResults()
|
|
@trigger c.event.change, this
|
|
|
|
results:
|
|
get: ->
|
|
return @_results
|
|
|
|
# Private Methods ##############################################################################
|
|
|
|
_computeScore: (name, itemSlug)->
|
|
hintIndex = 0
|
|
hintLetter = @_hint[hintIndex]
|
|
name = name.toLowerCase()
|
|
nextScore = 1
|
|
totalScore = 0
|
|
|
|
for nameIndex in [0...name.length] by 1
|
|
if name.charAt(nameIndex) is hintLetter
|
|
totalScore += nextScore
|
|
nextScore += 1
|
|
hintIndex += 1
|
|
if hintIndex is @_hint.length
|
|
item = @_modPack.findItem itemSlug
|
|
return 0 unless item?
|
|
return 0 unless @_isAcceptable item
|
|
break
|
|
|
|
hintLetter = @_hint[hintIndex]
|
|
else
|
|
nextScore = 1
|
|
|
|
return 0 if hintIndex < @_hint.length
|
|
|
|
totalScore *= @_hint.length / name.length
|
|
return totalScore
|
|
|
|
_refreshResults: ->
|
|
oldResults = @_results
|
|
scoredItems = []
|
|
count = 0
|
|
|
|
logger.verbose => "Looking for items which match: #{@_hint}"
|
|
if @_hint.length >= @_minHintLength
|
|
@_modPack.eachMod (mod)=>
|
|
return if count >= @_maxResults
|
|
return unless mod.enabled
|
|
|
|
mod.eachName (name, itemSlug)=>
|
|
return if scoredItems.length >= @_maxResults
|
|
return unless itemSlug.isQualified
|
|
|
|
score = @_computeScore name, itemSlug
|
|
if score >= @_hint.length
|
|
scoredItems.push score:score, itemSlug:itemSlug
|
|
|
|
scoredItems.sort (a, b)->
|
|
if a.score isnt b.score
|
|
return if a.score > b.score then -1 else +1
|
|
return ItemSlug.compare a.itemSlug, b.itemSlug
|
|
|
|
newResults = (e.itemSlug for e in scoredItems)
|
|
@_results = newResults
|
|
@trigger c.event.change + ':results', this, oldResults, newResults
|