module Scoring class Rules Side = Struct.new(:home, :away, keyword_init: true) def self.from_match(match) rules = match.effective_scoring_rules board = match.effective_board_type case board when "volley", "racket" new( sets_to_win: rules["sets_to_win"].to_i, points_per_set: rules["points_per_set"].to_i, points_deciding_set: rules["points_deciding_set"].to_i, min_point_lead: rules["min_point_lead"].to_i ) when "basket", "timed" PeriodRules.new( periods: rules["periods"].to_i, period_duration_secs: rules["period_duration_secs"].to_i, overtime_duration_secs: rules["overtime_duration_secs"].to_i ) else new( sets_to_win: rules["sets_to_win"].to_i.positive? ? rules["sets_to_win"].to_i : 3, points_per_set: rules["points_per_set"].to_i.positive? ? rules["points_per_set"].to_i : 25, points_deciding_set: rules["points_deciding_set"].to_i.positive? ? rules["points_deciding_set"].to_i : 15, min_point_lead: rules["min_point_lead"].to_i.positive? ? rules["min_point_lead"].to_i : 2 ) end end def initialize(sets_to_win:, points_per_set: 25, points_deciding_set: 15, min_point_lead: 2) @sets_to_win = sets_to_win @points_per_set = points_per_set @points_deciding_set = points_deciding_set @min_point_lead = min_point_lead end def max_sets (@sets_to_win * 2) - 1 end def points_target(current_set) current_set >= max_sets ? @points_deciding_set : @points_per_set end def self.points_target_for_match(match, current_set: 1) rules = from_match(match) rules.is_a?(Rules) ? rules.points_target(current_set) : 0 end def set_winner_from_points(home_points:, away_points:, current_set:) target = points_target(current_set) if home_points >= target && (home_points - away_points) >= @min_point_lead :home elsif away_points >= target && (away_points - home_points) >= @min_point_lead :away end end def match_winner(home_sets:, away_sets:) return :home if home_sets >= @sets_to_win return :away if away_sets >= @sets_to_win nil end class PeriodRules attr_reader :periods, :period_duration_secs, :overtime_duration_secs def initialize(periods:, period_duration_secs:, overtime_duration_secs: 300) @periods = periods @period_duration_secs = period_duration_secs @overtime_duration_secs = overtime_duration_secs end end end end