lib/active_genie/ranking/players_collection.rb
# frozen_string_literal: true require_relative 'player' module ActiveGenie module Ranking class PlayersCollection def initialize(param_players) @players = build(param_players) end attr_reader :players def coefficient_of_variation mean = score_mean return nil if mean.zero? variance = all_scores.map { |num| (num - mean)**2 }.sum / all_scores.size standard_deviation = Math.sqrt(variance) (standard_deviation / mean) * 100 end def all_scores eligible.map(&:score).compact end def score_mean return 0 if all_scores.empty? all_scores.sum.to_f / all_scores.size end def calc_relegation_tier eligible[(tier_size * -1)..] end def calc_defender_tier eligible[(tier_size * -2)...(tier_size * -1)] end def eligible sorted.reject(&:eliminated) end def eligible_size @players.reject(&:eliminated).size end def elo_eligible? eligible.size > 15 end def sorted sorted_players = @players.sort_by { |p| -p.sort_value } sorted_players.each_with_index { |p, i| p.rank = i + 1 } sorted_players end def to_json(*_args) to_h.to_json end def to_h sorted.map(&:to_h) end def method_missing(...) @players.send(...) end def respond_to_missing?(method_name, include_private = false) @players.respond_to?(method_name, include_private) end private def build(param_players) param_players.map { |p| Player.new(p) } end # Returns the number of players to battle in each round # based on the eligible size, start fast and go slow until top 10 # Example: # - 50 eligible, tier_size: 15 # - 35 eligible, tier_size: 11 # - 24 eligible, tier_size: 10 # - 14 eligible, tier_size: 4 # 4 rounds to reach top 10 with 50 players def tier_size size = (eligible_size / 3).ceil size.clamp(10, eligible_size - 10) end end end end