Apply Weirich block style and Enumerable idioms
Braces for functional blocks, do/end for side effects.
each_cons(3) replaces manual pad-and-zip in ladder_pairs.
zip replaces map-with-index-into-parallel-array throughout.
Assisted-by: Claude Opus 4.6 via pi
diff --git a/lib/open_skill/plackett_luce.rb b/lib/open_skill/plackett_luce.rb
index 0318081..a08e589 100644
--- a/lib/open_skill/plackett_luce.rb
+++ b/lib/open_skill/plackett_luce.rb
@@ -14,31 +14,31 @@ module OpenSkill
sum_q = Util.util_sum_q(team_ratings, c)
a = Util.util_a(team_ratings)
- team_ratings.each_with_index.map do |tr, i|
+ team_ratings.map.with_index { |tr, i|
mu_over_ce = Math.exp(tr.mu / c)
omega_sum = 0.0
delta_sum = 0.0
- team_ratings.each_with_index do |qr, q|
- next unless qr.rank <= tr.rank
-
- quotient = mu_over_ce / sum_q[q]
- omega_sum += ((i == q ? 1 : 0) - quotient) / a[q]
- delta_sum += (quotient * (1 - quotient)) / a[q]
- end
+ team_ratings.each.with_index
+ .select {|qr, _| qr.rank <= tr.rank }
+ .each do |_, q|
+ quotient = mu_over_ce / sum_q[q]
+ omega_sum += ((i == q ? 1 : 0) - quotient) / a[q]
+ delta_sum += (quotient * (1 - quotient)) / a[q]
+ end
g = Util.gamma(c, team_ratings.length, tr)
omega = omega_sum * (tr.sigma_sq / c)
delta = g * delta_sum * (tr.sigma_sq / c**2)
- tr.team.map do |player|
+ tr.team.map { |player|
share = player.sigma**2 / tr.sigma_sq
new_mu = player.mu + share * omega
new_sigma = player.sigma * Math.sqrt([1 - share * delta, epsilon].max)
Rating.new(new_mu, new_sigma)
- end
- end
+ }
+ }
end
end
end
diff --git a/lib/open_skill/rate.rb b/lib/open_skill/rate.rb
index 4cd2e92..e1a7c9f 100644
--- a/lib/open_skill/rate.rb
+++ b/lib/open_skill/rate.rb
@@ -11,31 +11,30 @@ module OpenSkill
# If tau is provided, use additive dynamics factor to keep ratings pliable
if options.key?(:tau)
tau_sq = env[:tau]**2
- processed_teams = teams.map do |team|
+ processed_teams = teams.map { |team|
team.map { |p| Rating.new(p.mu, Math.sqrt(p.sigma**2 + tau_sq)) }
- end
+ }
end
# Build rank from score (negated so higher score = lower rank) or default 1..n
rank = options[:rank] || options[:score]&.map { |s| -s } || (1..teams.length).to_a
# Sort by rank, run the model, then restore original order
- sort_order = rank.each_with_index.sort_by(&:first).map(&:last)
- ordered_teams = sort_order.map { |i| processed_teams[i] }
- sorted_rank = rank.sort
+ ordered = processed_teams.zip(rank).sort_by(&:last)
+ ordered_teams = ordered.map(&:first)
+ sorted_rank = ordered.map(&:last)
new_ratings = PlackettLuce.rate(ordered_teams, **options.merge(rank: sorted_rank))
- result = Array.new(teams.length)
- sort_order.each_with_index { |orig, sorted| result[orig] = new_ratings[sorted] }
+ result = rank.zip(new_ratings).sort_by(&:first).map(&:last)
# Cap sigma at pre-tau value so ordinal never drops after a win
if options.key?(:tau) && env[:limit_sigma]
- result = result.each_with_index.map do |team, i|
- team.each_with_index.map do |p, j|
+ result = result.map.with_index { |team, i|
+ team.map.with_index { |p, j|
Rating.new(p.mu, [p.sigma, teams[i][j].sigma].min)
- end
- end
+ }
+ }
end
result
diff --git a/lib/open_skill/util.rb b/lib/open_skill/util.rb
index 4f4c6f8..562ad4d 100644
--- a/lib/open_skill/util.rb
+++ b/lib/open_skill/util.rb
@@ -15,34 +15,30 @@ module OpenSkill
def self.rankings(teams, rank)
return [] if teams.empty?
- team_scores = teams.each_index.map { |i| rank&.at(i) || i }
+ team_scores = teams.map.with_index { |_, i| rank&.at(i) || i }
s = 0
- team_scores.each_with_index.map do |_, j|
+ team_scores.map.with_index { |_, j|
s = j if j > 0 && team_scores[j - 1] < team_scores[j]
s
- end
+ }
end
def self.ladder_pairs(ranks)
return [[]] if ranks.length <= 1
- padded_left = [nil, *ranks[...-1]]
- padded_right = [*ranks[1..], nil]
-
- padded_left.zip(padded_right).map { |pair| pair.compact }
+ [nil, *ranks, nil].each_cons(3).map { |l, _, r| [l, r].compact }
end
def self.team_rating(game, rank: nil, **)
- ranks = rankings(game, rank)
- game.each_with_index.map do |team, i|
+ game.zip(rankings(game, rank)).map { |team, rank|
TeamRating.new(
mu: team.sum(&:mu),
sigma_sq: team.sum { |p| p.sigma**2 },
team: team,
- rank: ranks[i],
+ rank: rank,
)
- end
+ }
end
def self.util_c(team_ratings, **)
@@ -51,11 +47,11 @@ module OpenSkill
end
def self.util_sum_q(team_ratings, c)
- team_ratings.map do |qr|
+ team_ratings.map { |qr|
team_ratings
.select { |ir| ir.rank >= qr.rank }
.sum { |ir| Math.exp(ir.mu / c) }
- end
+ }
end
def self.util_a(team_ratings)