lib/ceml/casting_criterion.rb in ceml-0.3.1 vs lib/ceml/casting_criterion.rb in ceml-0.4.0

- old
+ new

@@ -2,38 +2,84 @@ require "forwardable" module CEML class Candidate < Struct.new :uid, :tags, :matchables, :lat, :lng include Geokit::Mappable + attr_reader :criteria + + def load(criteria) + @criteria = criteria.select{ |c| c =~ self } + if @criteria.empty? then nil else self end + end + + def criteria_for_location(star) + criteria.select{ |c| c.fits?(self, star) } + end end + class CastingLocation < Struct.new :script, :hash, :created + attr_accessor :added + def star; hash.values.flatten.first; end + + def criteria + @criteria ||= script.awaited_criteria.sort_by{ |c| [-c.complexity, c.min_match] } + end + + def push candidate + matching_criteria = candidate.criteria_for_location(star) + return if matching_criteria.empty? + matching_criteria.each{ |c| (hash[c] ||= []) << candidate } + @added = true + end + + def self.create script, candidate + new(script, {}, true).tap{ |x| x.push candidate } + end + + # this method will miss possible castings and does not handle ranges at all + def cast + {}.tap do |casting| + criteria.each do |c| + return nil unless folks = hash[c].dup + folks -= casting.keys + return nil unless folks.size >= c.min_match + c.role_counts.each do |role, minct| + folks.shift(minct).each{ |guy| casting[guy.uid] = role.to_sym } + end + end + end + end + end + class CastingCriterion < Struct.new :script, :plus_tags, :minus_tags, :grouped_by, :radius, :role_counts - extend Forwardable - def_delegators :script, :locations def min_match; role_counts.values.reduce(:+); end def complexity; plus_tags.size; end def =~(candidate) (plus_tags - candidate.tags).empty? and (minus_tags & candidate.tags).empty? end - def satisfied_by_group?(people, already_used) - if (people - already_used).size >= min_match - already_used.concat((people - already_used).first(min_match)) - true - end + def fits?(candidate, star) + return true unless star + return unless grouped_by.all?{ |g| candidate.matchables[g] == star.matchables[g] } + p radius + !radius or candidate.distance_to(star, :meters) <= radius end - - def list_candidate(candidate) - locs = locations.select do |l| - star = l.values.flatten.first - next unless grouped_by.all?{ |g| candidate.matchables[g] == star.matchables[g] } - !radius or candidate.distance_to(star, :meters) <= radius - end - if locs.empty? - new_loc = {} - [locations, locs].each{ |l| l << new_loc } - end - locs.each{ |l| (l[hash] ||= []) << candidate } - end end end + +# def satisfied_by_group?(people, already_used) +# if (people - already_used).size >= min_match +# already_used.concat((people - already_used).first(min_match)) +# true +# end +# end + +# this method and the one below will miss possible +# castings and do not handle ranges at all +# def complete?(loc) +# people_used = [] +# @criteria.all? do |c| +# next unless folks = loc[c.hash] +# c.satisfied_by_group?(folks, people_used) +# end +# end