1
0
mirror of https://github.com/jcwimer/wrestlingApp synced 2026-03-25 01:14:43 +00:00

Fixed random double elimination seeding to avoid double byes in round 1 and evenly distribute the number of round 1 matches from the top and bottom half of the bracket

This commit is contained in:
2026-01-14 19:00:35 -05:00
parent 8b03a74b1e
commit 52df73d14f
2 changed files with 76 additions and 9 deletions

View File

@@ -19,14 +19,19 @@ class TournamentSeeding
half_of_bracket = bracket_size / 2 half_of_bracket = bracket_size / 2
available_bracket_lines = (1..bracket_size).to_a available_bracket_lines = (1..bracket_size).to_a
first_half_available_bracket_lines = (1..half_of_bracket).to_a first_half_available_bracket_lines = (1..half_of_bracket).to_a
first_line_of_second_half_of_bracket = half_of_bracket + 1
second_half_available_bracket_lines = (first_line_of_second_half_of_bracket..bracket_size).to_a
# remove bracket lines that are taken from available_bracket_lines # remove bracket lines that are taken from available_bracket_lines
wrestlers_with_bracket_lines = wrestlers.select{|w| w.bracket_line != nil } wrestlers_with_bracket_lines = wrestlers.select{|w| w.bracket_line != nil }
wrestlers_with_bracket_lines.each do |wrestler| wrestlers_with_bracket_lines.each do |wrestler|
available_bracket_lines.delete(wrestler.bracket_line) available_bracket_lines.delete(wrestler.bracket_line)
first_half_available_bracket_lines.delete(wrestler.bracket_line) first_half_available_bracket_lines.delete(wrestler.bracket_line)
second_half_available_bracket_lines.delete(wrestler.bracket_line)
end end
available_bracket_lines_to_use = set_random_seeding_bracket_line_order(first_half_available_bracket_lines, second_half_available_bracket_lines)
wrestlers_without_bracket_lines = wrestlers.select{|w| w.bracket_line == nil } wrestlers_without_bracket_lines = wrestlers.select{|w| w.bracket_line == nil }
if @tournament.tournament_type == "Pool to bracket" if @tournament.tournament_type == "Pool to bracket"
wrestlers_without_bracket_lines.shuffle.each do |wrestler| wrestlers_without_bracket_lines.shuffle.each do |wrestler|
@@ -38,15 +43,10 @@ class TournamentSeeding
else else
# Iterrate over the list randomly # Iterrate over the list randomly
wrestlers_without_bracket_lines.shuffle.each do |wrestler| wrestlers_without_bracket_lines.shuffle.each do |wrestler|
if first_half_available_bracket_lines.size > 0 if available_bracket_lines_to_use.size > 0
random_available_bracket_line = first_half_available_bracket_lines.sample bracket_line_to_use = available_bracket_lines_to_use.first
wrestler.bracket_line = random_available_bracket_line wrestler.bracket_line = bracket_line_to_use
available_bracket_lines.delete(random_available_bracket_line) available_bracket_lines_to_use.delete(bracket_line_to_use)
first_half_available_bracket_lines.delete(random_available_bracket_line)
else
random_available_bracket_line = available_bracket_lines.sample
wrestler.bracket_line = random_available_bracket_line
available_bracket_lines.delete(random_available_bracket_line)
end end
end end
end end
@@ -81,4 +81,35 @@ class TournamentSeeding
end end
return wrestlers return wrestlers
end end
private
def set_random_seeding_bracket_line_order(first_half_lines, second_half_lines)
# This method prevents double BYEs in round 1
# It also evenly distributes matches from the top half of the bracket to the bottom half
# It does both of these while keeping the randomness of the line assignment
odd_or_even = [0, 1]
odd_or_even_sample = odd_or_even.sample
# sort by odd or even based on the sample above
if odd_or_even_sample == 1
# odd numbers first
sorted_first_half_lines = first_half_lines.sort_by { |n| n.even? ? 1 : 0 }
sorted_second_half_lines = second_half_lines.sort_by { |n| n.even? ? 1 : 0 }
else
# even numbers first
sorted_first_half_lines = first_half_lines.sort_by { |n| n.odd? ? 1 : 0 }
sorted_second_half_lines = second_half_lines.sort_by { |n| n.odd? ? 1 : 0 }
end
# zip requires either even arrays or the receiver to be the bigger list
if first_half_lines.size >= second_half_lines.size
result = sorted_first_half_lines.zip(sorted_second_half_lines).flatten
else
result = sorted_second_half_lines.zip(sorted_first_half_lines).flatten
end
result.compact
result.delete(nil)
result
end
end end

View File

@@ -0,0 +1,36 @@
require 'test_helper'
class RandomSeedingTest < ActionDispatch::IntegrationTest
def setup
end
def clean_up_original_seeds(tournament)
tournament.wrestlers.select{|w| w.original_seed > 12}.each do |wrestler|
wrestler.original_seed = nil
wrestler.save
end
tournament.wrestlers.reload.each do |wrestler|
wrestler.bracket_line = nil
wrestler.save
end
GenerateTournamentMatches.new(tournament).generate
end
test "There are no double byes in a double elimination tournament round 1" do
create_double_elim_tournament_single_weight(18, "Regular Double Elimination 1-8")
clean_up_original_seeds(@tournament)
round_one_matches = @tournament.matches.reload.select{|m| m.round == 1}
assert round_one_matches.select{|m| m.w1.nil? and m.w2.nil? }.size == 0
end
test "There are the same number of matches in the top half and bottom half of a double elimination tournament in round 1" do
create_double_elim_tournament_single_weight(18, "Regular Double Elimination 1-8")
clean_up_original_seeds(@tournament)
round_one_matches = @tournament.matches.reload.select{|m| m.round == 1}
# 32 man bracket there are 16 matches so top half is bracket_position_number 1-8 and bottom is 9-16
round_one_top_half = round_one_matches.select{|m| !m.w1.nil? and !m.w2.nil? and m.bracket_position_number < 9}
round_one_bottom_half = round_one_matches.select{|m| !m.w1.nil? and !m.w2.nil? and m.bracket_position_number > 8}
assert round_one_top_half.size == round_one_bottom_half.size
end
end