turniere-backend/app/services/match_service.rb

60 lines
2.1 KiB
Ruby

# frozen_string_literal: true
class MatchService
# Generates all necessary matches from a list of teams
#
# @param teams [Array] the teams to generate matches with
# @return [Array] the generated matches
def self.generate_matches(teams)
if teams.empty?
# should be prevented by controller
raise 'Cannot generate Matches without teams'
end
if teams.size == 1
matches = []
match = Match.new state: :single_team, position: 1, match_scores: [MatchScore.create(team: teams.first)]
matches << match
return matches
end
# normal_games = number of matches with two teams attending
# needed_games = number of matches to generate in total for the given number of teams
if Utils.po2?(teams.size)
# if amount of teams is power of two, all matches are with two teams
normal_games = teams.size / 2
needed_games = normal_games
else
# if amount of teams isn't a power of two we need to "kick out"
# enough teams to get to a power of two in the next round
normal_games = teams.size - Utils.previous_power_of_two(teams.size)
needed_games = Utils.previous_power_of_two(teams.size)
end
matches = []
while matches.size < normal_games
# while we do not have as many matches with two teams as we need, create another one
i = matches.size
match = Match.new state: :not_started,
position: i,
match_scores: [
MatchScore.create(team: teams[2 * i]),
MatchScore.create(team: teams[(2 * i) + 1])
]
matches << match
end
# the start point is to compensate for all the teams that are already within a "normal" match
i = team_offset = matches.size
until matches.size >= needed_games
# while we do not have enough matches in general we need to fill the array with "single team" matches
match = Match.new state: :single_team,
position: i,
match_scores: [MatchScore.create(team: teams[i + team_offset])]
matches << match
i += 1
end
matches
end
end