I wanted to see how simply I could do it from a code perspective, so I
just used nested arrays to represent the tree structure. I think it
actually turned out pretty well. Turning it into an actual tree
results in pretty similar code, removing the niceness of zip, but
making the recursive functions a little OOPier.
-Fred
# Generate a single elimination tournament for N teams, numbered 1..N
def generate_tournament_bracket(num_teams)
# Number of byes = 2**n - num_teams where n is the smallest value
such the number is positive
num_byes = 2**((Math.log(num_teams)/Math.log(2)).ceil) - num_teams
# Generate bye first round "matching"s
byes = (1..num_byes).map{|i| [i]}
# Generate all the other matchings
current_round = ((num_byes + 1)..num_teams).to_a
# Keep going until we have a winner
while current_round.size > 1
# Generate the next round matchings by taking all byes, if any,
from the byes array.
# Then we exploit the fact that our array is always sorted by seed
of winner to find the next
# pairings
current_round = byes.slice!(0..-1) +
current_round[0...current_round.size/2].zip(current_round[current_round.size/2..-1].reverse)
end
return current_round[0]
end
# Outputs any matches in the subtree of current_matching using
match_num as the first
# available match_number
# Returns the match number of current_matching
def output_bracket(current_matching, match_num = 1)
# Since we never go until we get current_matching.kind_of?(Fixnum),
we must have a bye
# which means we're first round
if current_matching.size == 1
puts "Match #{match_num}: #{current_matching[0]} vs Bye"
return match_num
# First round detection
elsif current_matching[0].kind_of?(Fixnum)
puts "Match #{match_num}: #{current_matching[0]} vs #{current_matching[1]}"
return match_num
# Some other round, so we need to recurse down
else
left_match = output_bracket(current_matching[0], match_num)
right_match = output_bracket(current_matching[1], left_match + 1)
match_num = right_match + 1
puts "Match #{match_num}: Winner of Match #{left_match} vs Winner
of Match #{right_match}"
return match_num
end
end
output_bracket(generate_tournament_bracket(5))