class MajorityJudgment @values = nil include Comparable attr_reader :ratings, :count, :n, :majority class << self attr_accessor :values end def initialize(arg) if arg.is_a?(Array) @ratings = arg @count = { } self.class.values.each do |v| @count[v[:id]] = 0 end @n = 0 ratings.each do |r| @count.has_key?(r) ? @count[r] = @count[r] + 1 : @count[r] = 1 @n = @n + 1 end elsif arg.is_a?(Hash) @count = arg @n = 0 @count.collect { |r, c| @n = @n + c } end @majority = ( @n.to_f / 2 ).floor + 1 end def mj s = 0 (1..self.class.values.length).to_a.reverse.each do |r| s = s + @count[r] if @count[r] return r if s >= @majority end return 0 end def proponents(rating = self.mj) p = 0 (rating+1..self.class.values.length).to_a.reverse.each do |r| p = p + @count[r] if @count[r] end return p end def opponents(rating = self.mj) o = 0 (1..rating-1).to_a.reverse.each do |r| o = o + @count[r] if @count[r] end return o end def <=> (other) return 1 if self.mj > other.mj return -1 if self.mj < other.mj return 0 if self.mj == 0 counta = self.count.dup counta[self.mj] = counta[self.mj] - 1 countb = other.count.dup countb[other.mj] = countb[other.mj] - 1 return MajorityJudgment.new(counta) <=> MajorityJudgment.new(countb) end def break_tie(other) rounds = [ ] s = MajorityJudgment.new(self.count.dup) o = MajorityJudgment.new(other.count.dup) rounds << [s, o] while s.mj == o.mj and not s.mj == 0 new_s_count = s.count.dup new_o_count = o.count.dup new_s_count[s.mj] = new_s_count[s.mj] - 1 new_o_count[o.mj] = new_o_count[o.mj] - 1 s = MajorityJudgment.new(new_s_count) o = MajorityJudgment.new(new_o_count) rounds << [s, o] end return rounds end def to_s puts "#{@count}: {M=>#{self.mj}, P=>#{self.proponents}, O=>#{self.opponents}}" end end