require 'logger' class MashTournamentBuilder attr_accessor :tournament, :tournament_model, :round_model attr_accessor :map_model, :mash_model def initialize(tournament, tournament_model, round_model, map_model, mash_model) @tournament = tournament @tournament_model = tournament_model @round_model = round_model @map_model = map_model @mash_model = mash_model @logger = Logger.new( File.expand_path( '../log/mash-tournament-builder.log', File.dirname(__FILE__) ) ) end def valid_number_of_contenders?(n_contenders) [8, 16, 32, 64, 128].include?(n_contenders) end def create_rounds_for_contenders(n_contenders) if not valid_number_of_contenders?(n_contenders) raise StandardError.new( "The number of contenders must be 8, 16, 32, 64, or 128! " + "Got '#{n_contenders}'" ) end round = 1 while n_contenders > 1 create_round(round, n_contenders) n_contenders = n_contenders / 2 round += 1 end @tournament.total_rounds = round - 1 end def fill_in_next_round @tournament.rounds.sort{ |a,b| a.number <=> b.number}.each do |round| if not round.done? return assign_maps_for_round(round) end end end private def create_round(round_number, n_contenders) round_options = { :mash_tournament_id => @tournament.id, :number => round_number, :mash_count => n_contenders / 2 } @logger.info("Creating round #{round_number} of #{n_contenders} contenders " + "with options: #{round_options.inspect}") round = @round_model.new(round_options) round.save! round.mash_count.times do @mash_model.new( :mash_tournament_id => @tournament.id, :mash_tournament_round_id => round.id ).save! end end def assign_maps_for_round(round) if round.number == 1 return assign_maps_for_round_one(round) end previous = @round_model.find_by_mash_tournament_id_and_number( @tournament.id, round.number - 1 ) previous_winners = previous.mashes.collect(&:winner_id) pool = @map_model.all( :order => 'RANDOM()', :conditions => {:id => previous_winners} ) filled_in = [] round.mashes.each do |mash| mash.map_a = pool.pop mash.map_b = pool.pop mash.save! filled_in << mash end filled_in end def assign_maps_for_round_one(round) pool_options = { :order => 'RANDOM()', :limit => round.mash_count * 2 } @logger.info("Allocating pool with options: #{pool_options.inspect}") pool = @map_model.all(pool_options) @logger.info("Populating mashes from pool: #{pool.inspect}") filled_in = [] round.mashes.each do |mash| map_a = pool.pop map_b = pool.pop @logger.info("Assigning `map_a` from #{map_a.inspect}, " + "`map_b` from #{map_b.inspect} to mash #{mash.inspect}") mash.map_a = map_a mash.map_b = map_b mash.save! filled_in << mash end filled_in end end