4 What drives popularity? Are Pareto popularity distributions possible? likely?
11 self[rand(self.length)]
16 # A Character has a name and nothing more
24 # A Star is just a Character, no special abilities
25 class Star < Character ; end
27 # A Commoner is a Character with one or more voting strategies
28 class Commoner < Character
29 # The simplest voting strategy: pick a random one
30 def random_vote(popularity, total)
31 popularity.keys.pick_one
34 # A voting strategy that picks a random star, weighting
35 # more popular ones more
36 def popular_vote(popularity, total)
37 # if nobody voted yet, pick a random one
38 return random_vote(popularity, total) if total == 0
40 popularity.each do |star, pop|
41 return star if pick < pop
56 raise ArgumentError, "#{n} is neither a String nor an Integer"
59 @stars[name.intern] = Star.new(name)
68 name = "Commoner #%u" % n
70 raise ArgumentError, "#{n} is neither a String nor an Integer"
73 @commoners[name.intern] = Commoner.new(name)
77 def today ; @day ; end
84 # Initialize a new popularity day
86 @popularity << Hash.new do |h, k|
87 raise ArgumentError, "no such Star '#{k}'" unless @stars.key? k
110 def stars ; @stars.keys ; end
111 def commoners ; @commoners.keys ; end
113 # Get :day's [default: today] popularity for :stars [default: all stars].
115 # a hash star => number of commoners that voted for it that day
117 pop = @popularity[o[:day] || today]
119 [o[:stars] || stars].flatten.each do |s|
120 sel[s] = pop[s].length
125 # an Array of [star, popularity] ordered by popularity
127 popularity(o).to_a.sort { |s1, s2| s2.last <=> s1.last }
131 pop_org = popularity(:day => yesterday)
132 # to allow giving stars with no popularity a chance,
133 # we allow a :mul and :add option to the voting session.
138 pop_org.each do |star, p|
139 pop[star] = p*mul + add
142 @commoners.each do |name, commoner|
143 star = commoner.popular_vote(pop, tot)
144 @popularity[today][star] << name
152 5.times do |i| pop.add_star(i) end
153 100.times do |i| pop.add_commoner(i) end
155 puts pop.grade.map { |s, p| "#{s} (#{p})" }.join(', ')
161 puts pop.grade.map { |s, p| "#{s} (#{p})" }.join(', ')
169 puts pop.grade.map { |s, p| "#{s} (#{p})" }.join(', ')
176 pop.vote(:mul => 10, :add => 1)
177 puts pop.grade.map { |s, p| "#{s} (#{p})" }.join(', ')