diff --git a/app/services/match_service.rb b/app/services/match_service.rb index 0eb9fa8..adf2995 100644 --- a/app/services/match_service.rb +++ b/app/services/match_service.rb @@ -6,9 +6,16 @@ class MatchService # @param teams [Array] the teams to generate matches with # @return [Array] the generated matches def self.generate_matches(teams) - if teams.size < 2 + if teams.empty? # should be prevented by controller - return + 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 @@ -37,9 +44,11 @@ class MatchService matches << match end + # the start point is to compensate for all the teams that are already within a "normal" match + startpoint = 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 - i = matches.size + i = matches.size + startpoint match = Match.new state: :single_team, position: i, match_scores: [MatchScore.create(team: teams[i])] matches << match end diff --git a/app/services/playoff_stage_service.rb b/app/services/playoff_stage_service.rb index 1168ff4..340a9a2 100644 --- a/app/services/playoff_stage_service.rb +++ b/app/services/playoff_stage_service.rb @@ -61,11 +61,12 @@ class PlayoffStageService # @param number_of_teams [Integer] the teams number of teams to calculate amount of stages # @return [Integer] amount of required stages def self.calculate_required_stage_count(number_of_teams) - if number_of_teams.zero? || number_of_teams == 1 - 0 + if number_of_teams == 1 + 1 else # black voodoo magic - stage_count = Math.log(Utils.previous_power_of_two(number_of_teams)) / Math.log(2) + stage_count = Math.log(Utils.next_power_of_two(number_of_teams)) / Math.log(2) + stage_count -= 1 if Utils.po2?(number_of_teams) stage_count.to_int end end diff --git a/spec/services/match_service_spec.rb b/spec/services/match_service_spec.rb index 09fc450..21ada52 100644 --- a/spec/services/match_service_spec.rb +++ b/spec/services/match_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe MatchService do - describe '#generate_matches' do + describe 'generates' do [ { team_size: 2 }, { team_size: 4 }, @@ -11,7 +11,7 @@ RSpec.describe MatchService do { team_size: 64 } ].each do |parameters| result = parameters[:team_size] / 2 - it "generates #{result} matches from #{parameters[:team_size]} teams" do + it "#{result} matches from #{parameters[:team_size]} teams" do teams = build_list(:team, parameters[:team_size], tournament: create(:tournament)) generated_matches = MatchService.generate_matches teams expect(generated_matches.size).to eq(result) @@ -54,7 +54,7 @@ RSpec.describe MatchService do { team_size: 256 } ].each do |parameters| - it "matches the right teams for powers of 2 (#{parameters[:team_size]})" do + it "the right matchups for powers of 2 (#{parameters[:team_size]})" do teams = build_list(:team, parameters[:team_size], tournament: create(:tournament)) generated_matches = MatchService.generate_matches teams generated_matches.each_index do |index| @@ -67,7 +67,30 @@ RSpec.describe MatchService do end end - # TODO: matches right teams for !powers of 2 + [ + { team_size: 3 }, + { team_size: 5 }, + { team_size: 7 }, + { team_size: 9 }, + { team_size: 19 }, + { team_size: 41 }, + { team_size: 52 }, + { team_size: 111 } + + ].each do |parameters| + it "the right matchups for team numbers that are not powers of 2 (#{parameters[:team_size]})" do + team_size = parameters[:team_size] + teams = build_list(:team, team_size, tournament: create(:tournament)) + generated_matches = MatchService.generate_matches teams + team_order = [] + generated_matches.each do |match| + match.match_scores.each do |score| + team_order << score.team + end + end + expect(team_order).to match_array(teams) + end + end [ { team_size: 3, single_team_matches: 1 }, @@ -91,12 +114,8 @@ RSpec.describe MatchService do end end - it 'generates no matches for 0 teams' do - expect(MatchService.generate_matches([])). to eq(nil) - end - - it 'generates no matches for 1 team' do - expect(MatchService.generate_matches(build_list(:team, 1))). to eq(nil) + it 'raises an exception for for 0 teams' do + expect { MatchService.generate_matches([]) }. to raise_error 'Cannot generate Matches without teams' end end end diff --git a/spec/services/playoff_stage_service_spec.rb b/spec/services/playoff_stage_service_spec.rb index 1fb8eb7..46dfe55 100644 --- a/spec/services/playoff_stage_service_spec.rb +++ b/spec/services/playoff_stage_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe PlayoffStageService do - describe '#generate_empty_matches' do + describe 'generates' do [ { amount: 1 }, { amount: 3 }, @@ -12,7 +12,7 @@ RSpec.describe PlayoffStageService do { amount: 82 }, { amount: 359 } ].each do |parameters| - it "generates #{parameters[:amount]} empty matches" do + it "#{parameters[:amount]} empty matches" do amount = parameters[:amount] generated_matches = PlayoffStageService.generate_empty_matches amount generated_matches.each_index do |i| @@ -24,7 +24,7 @@ RSpec.describe PlayoffStageService do end end - describe '#generate_stages_with_empty_matches' do + describe 'generates' do [ { stages: 1 }, { stages: 2 }, @@ -37,7 +37,7 @@ RSpec.describe PlayoffStageService do { stages: 9 }, { stages: 10 } ].each do |parameters| - it "generates #{parameters[:stages]} stages with matches provided by #generate_empty_matches" do + it "#{parameters[:stages]} stages with matches provided by #generate_empty_matches" do amount_of_empty_stages = parameters[:stages] empty_stages = PlayoffStageService.generate_stages_with_empty_matches(amount_of_empty_stages) expect(empty_stages.size).to eq(amount_of_empty_stages) @@ -51,17 +51,22 @@ RSpec.describe PlayoffStageService do end end - describe '#generate_playoffs' do + describe 'generates playoff stages for' do [ + { team_size: 1, expected_amount_of_playoff_stages: 1 }, + { team_size: 2, expected_amount_of_playoff_stages: 1 }, + { team_size: 3, expected_amount_of_playoff_stages: 2 }, { team_size: 4, expected_amount_of_playoff_stages: 2 }, { team_size: 8, expected_amount_of_playoff_stages: 3 }, + { team_size: 9, expected_amount_of_playoff_stages: 4 }, + { team_size: 10, expected_amount_of_playoff_stages: 4 }, { team_size: 16, expected_amount_of_playoff_stages: 4 }, - { team_size: 24, expected_amount_of_playoff_stages: 4 }, + { team_size: 24, expected_amount_of_playoff_stages: 5 }, { team_size: 32, expected_amount_of_playoff_stages: 5 }, { team_size: 64, expected_amount_of_playoff_stages: 6 }, - { team_size: 111, expected_amount_of_playoff_stages: 6 } + { team_size: 111, expected_amount_of_playoff_stages: 7 } ].each do |parameters| - it "generates playoff stages for #{parameters[:team_size]} teams" do + it "#{parameters[:team_size]} teams" do amount_of_teams = parameters[:team_size] expected_amount_of_playoff_stages = parameters[:expected_amount_of_playoff_stages] teams = build_list(:team, amount_of_teams)