116 lines
2.9 KiB
Ruby
116 lines
2.9 KiB
Ruby
module Tournaments
|
|
class Standings
|
|
Row = Struct.new(
|
|
:participant, :played, :won, :lost, :drawn, :points,
|
|
:sets_for, :sets_against, :score_for, :score_against,
|
|
keyword_init: true
|
|
)
|
|
|
|
def self.call(group)
|
|
new(group).call
|
|
end
|
|
|
|
def initialize(group)
|
|
@group = group
|
|
@tournament = group.tournament
|
|
end
|
|
|
|
def call
|
|
rows = @group.participants.with_attached_logo_file.map { |p| blank_row(p) }.index_by { |r| r.participant.id }
|
|
matches = @group.matches.where(result_status: %w[played walkover_home walkover_away])
|
|
matches.find_each do |match|
|
|
apply_match!(rows, match)
|
|
end
|
|
rows.values.sort_by { |row| [-row.points, -set_diff(row), -score_diff(row), row.participant.name] }
|
|
end
|
|
|
|
private
|
|
|
|
def blank_row(participant)
|
|
Row.new(
|
|
participant: participant, played: 0, won: 0, lost: 0, drawn: 0, points: 0,
|
|
sets_for: 0, sets_against: 0, score_for: 0, score_against: 0
|
|
)
|
|
end
|
|
|
|
def apply_match!(rows, match)
|
|
home = rows[match.home_participant_id]
|
|
away = rows[match.away_participant_id]
|
|
return unless home && away
|
|
|
|
hs = match.home_score.to_i
|
|
as = match.away_score.to_i
|
|
home.played += 1
|
|
away.played += 1
|
|
home.sets_for += hs
|
|
home.sets_against += as
|
|
away.sets_for += as
|
|
away.sets_against += hs
|
|
home.score_for += hs
|
|
home.score_against += as
|
|
away.score_for += as
|
|
away.score_against += hs
|
|
|
|
if hs == as
|
|
home.drawn += 1
|
|
away.drawn += 1
|
|
home.points += split_draw_points
|
|
away.points += split_draw_points
|
|
return
|
|
end
|
|
|
|
if hs > as
|
|
home.won += 1
|
|
away.lost += 1
|
|
home.points += win_points(hs, as)
|
|
away.points += loss_points(hs, as)
|
|
else
|
|
away.won += 1
|
|
home.lost += 1
|
|
away.points += win_points(as, hs)
|
|
home.points += loss_points(as, hs)
|
|
end
|
|
end
|
|
|
|
def settings
|
|
@settings ||= (@tournament.scoring_settings || {}).stringify_keys
|
|
end
|
|
|
|
def split_sets?
|
|
ActiveModel::Type::Boolean.new.cast(settings["split_sets"])
|
|
end
|
|
|
|
def win_points(winner_sets, loser_sets)
|
|
return settings.fetch("win_points", 3).to_i unless split_sets?
|
|
|
|
if winner_sets - loser_sets >= 2
|
|
settings.fetch("win_3_0_or_3_1", 3).to_i
|
|
else
|
|
settings.fetch("win_3_2", 2).to_i
|
|
end
|
|
end
|
|
|
|
def loss_points(winner_sets, loser_sets)
|
|
return settings.fetch("loss_points", 0).to_i unless split_sets?
|
|
|
|
if winner_sets - loser_sets >= 2
|
|
settings.fetch("loss_0_3_or_1_3", 0).to_i
|
|
else
|
|
settings.fetch("loss_2_3", 1).to_i
|
|
end
|
|
end
|
|
|
|
def split_draw_points
|
|
settings.fetch("draw_points", 1).to_i
|
|
end
|
|
|
|
def set_diff(row)
|
|
row.sets_for - row.sets_against
|
|
end
|
|
|
|
def score_diff(row)
|
|
row.score_for - row.score_against
|
|
end
|
|
end
|
|
end
|