diff --git a/rails/map-mash/app/models/mash_tournament.rb b/rails/map-mash/app/models/mash_tournament.rb index 6b6763c..03291be 100644 --- a/rails/map-mash/app/models/mash_tournament.rb +++ b/rails/map-mash/app/models/mash_tournament.rb @@ -16,105 +16,4 @@ class MashTournament < ActiveRecord::Base :conditions => {:number => number} ) 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 - - self.total_rounds = round - 1 - end - - def fill_in_next_round - self.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 = MashTournamentRound.new( - :mash_tournament_id => self.id, - :number => round_number, - :mash_count => n_contenders / 2 - ) - round.save! - - n_contenders.times do - Mash.new( - :mash_tournament_id => self.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 = MashTournamentRound.find_by_mash_tournament_id_and_number( - self.id, round.number - 1 - ) - previous_winners = previous.mashes.collect(&:winner_id) - pool = Map.all( - :order => 'RANDOM()', - :conditions => ['id in ?', previous_winners] - ) - - filled_in = [] - - round.mashes.each do |mash| - mash.map_a = pool.pop.id - mash.map_b = pool.pop.id - mash.save! - - filled_in << mash - end - - filled_in - end - - def assign_maps_for_round_one(round) - pool = Map.all( - :order => 'RANDOM()', - :limit => round.mash_count * 2 - ) - - 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 diff --git a/rails/map-mash/lib/mash_tournament_builder.rb b/rails/map-mash/lib/mash_tournament_builder.rb new file mode 100644 index 0000000..7d5aa78 --- /dev/null +++ b/rails/map-mash/lib/mash_tournament_builder.rb @@ -0,0 +1,113 @@ +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 + 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 = @round_model.new( + :mash_tournament_id => @tournament.id, + :number => round_number, + :mash_count => n_contenders / 2 + ) + round.save! + + n_contenders.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 in ?', previous_winners] + ) + + filled_in = [] + + round.mashes.each do |mash| + mash.map_a = pool.pop.id + mash.map_b = pool.pop.id + mash.save! + + filled_in << mash + end + + filled_in + end + + def assign_maps_for_round_one(round) + pool = @map_model.all( + :order => 'RANDOM()', + :limit => round.mash_count * 2 + ) + + 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 diff --git a/rails/map-mash/spec/lib/mash_tournament_builder_spec.rb b/rails/map-mash/spec/lib/mash_tournament_builder_spec.rb new file mode 100644 index 0000000..63d1fa3 --- /dev/null +++ b/rails/map-mash/spec/lib/mash_tournament_builder_spec.rb @@ -0,0 +1,64 @@ +require 'spec_helper' + +describe MashTournamentBuilder do + let(:subject) do + MashTournamentBuilder.new( + MashTournament.make(:requester => Requester.make), + MashTournament, MashTournamentRound, Map, Mash + ) + end + + let(:mock_subject) do + @tournament = mock(Object) + @tournament_model = mock(Object) + @round_model = mock(Object) + @map_model = mock(Object) + @mash_model = mock(Object) + + MashTournamentBuilder.new( + @tournament, @tournament_model, + @round_model, @map_model, @mash_model + ) + end + + context 'creating rounds' do + it 'should reject invalid numbers of contenders' do + [11, 24, 40].each do |n| + expect do + subject.create_rounds_for_contenders(n) + end.to raise_error + end + end + + before(:all) do + subject.map_model.destroy_all + 40.times do + subject.map_model.make.save + end + end + + [[8, 3], [16, 4], [32, 5]].each do |n_contenders,n_rounds| + context "for #{n_contenders} total contenders" do + it "should create #{n_rounds} rounds" do + subject.create_rounds_for_contenders(n_contenders) + subject.tournament.total_rounds.should == n_rounds + end + end + end + end + + context 'filling in rounds' do + before(:each) do + subject.id.should_not be_nil + subject.create_rounds_for_contenders(8) + end + + xit 'should fill in every map for every mash in a given round' do + subject.fill_in_next_round + subject.round(1).mashes.each do |mash| + mash.map_a.should_not be_nil + mash.map_b.should_not be_nil + end + end + end +end diff --git a/rails/map-mash/spec/models/mash_tournament_spec.rb b/rails/map-mash/spec/models/mash_tournament_spec.rb index c28d154..734b760 100644 --- a/rails/map-mash/spec/models/mash_tournament_spec.rb +++ b/rails/map-mash/spec/models/mash_tournament_spec.rb @@ -5,56 +5,7 @@ describe MashTournament do @valid_attributes = {:requester_id => 1} end - before(:each) do - @requester = Requester.make - @requester.save! - subject.requester_id = @requester.id - subject.save! - subject.reload - end - it "should create a new instance given valid attributes" do MashTournament.create!(@valid_attributes) end - - context 'creating rounds' do - it 'should reject invalid numbers of contenders' do - [11, 24, 40].each do |n| - expect do - subject.create_rounds_for_contenders(n) - end.to raise_error - end - end - - before(:all) do - Map.destroy_all - 40.times do - Map.make.save - end - end - - [[8, 3], [16, 4], [32, 5]].each do |n_contenders,n_rounds| - context "for #{n_contenders} total contenders" do - it "should create #{n_rounds} rounds" do - subject.create_rounds_for_contenders(n_contenders) - subject.total_rounds.should == n_rounds - end - end - end - end - - context 'filling in rounds' do - before(:each) do - subject.id.should_not be_nil - subject.create_rounds_for_contenders(8) - end - - xit 'should fill in every map for every mash in a given round' do - subject.fill_in_next_round - subject.round(1).mashes.each do |mash| - mash.map_a.should_not be_nil - mash.map_b.should_not be_nil - end - end - end end