lib/rrschedule.rb in rrschedule-0.2.9 vs lib/rrschedule.rb in rrschedule-0.2.10

- old
+ new

@@ -6,11 +6,11 @@ attr_reader :flights, :rounds, :gamedays attr_accessor :teams, :rules, :cycles, :start_date, :exclude_dates,:shuffle def initialize(params={}) @gamedays = [] - self.teams = params[:teams] if params[:teams] + self.teams = params[:teams] || [] self.cycles = params[:cycles] || 1 self.shuffle = params[:shuffle].nil? ? true : params[:shuffle] self.exclude_dates = params[:exclude_dates] || [] self.start_date = params[:start_date] || Date.today self.rules = params[:rules] || [] @@ -19,37 +19,18 @@ #This will generate the schedule based on the various parameters def generate(params={}) raise "You need to specify at least 1 team" if @teams.nil? || @teams.empty? raise "You need to specify at least 1 rule" if @rules.nil? || @rules.empty? + arrange_flights + init_stats + @gamedays = []; @rounds = [] - @stats = {} - @teams.flatten.each do |t| - @stats[t] = { - :gt => {}, - :ps => {} - } - @stats[t][:gt] = {} - all_gt.each do |gt| - @stats[t][:gt][gt] = 0 - end - - @stats[t][:ps] = {} - all_ps.each do |ps| - @stats[t][:ps][ps] = 0 - end - end - - @gamedays = [] - @rounds = [] - @flights.each_with_index do |teams,flight_id| - - current_cycle = current_round = 0 teams = teams.sort_by{rand} if @shuffle #loop to generate the whole round-robin(s) for the current flight begin @@ -60,18 +41,15 @@ while !t.empty? do team_a = t.shift team_b = t.reverse!.shift t.reverse! + x = [team_a,team_b].shuffle - x = [team_a,team_b] #.shuffle - - matchup = {:team_a => x[0], :team_b => x[1], :home_team_index => self.teams.index(x[0])} + matchup = {:team_a => x[0], :team_b => x[1]} games << matchup end - #games = games.sort_by {|g| g[:home_team_index]} - #done processing round current_round += 1 #Team rotation (the first team is fixed) @@ -93,15 +71,11 @@ #done adding round #have we completed a full round-robin for the current flight? if current_round == teams.size-1 current_cycle += 1 - - if current_cycle < self.cycles - current_round = 0 - teams = teams.sort_by{rand} if @shuffle - end + current_round = 0 if current_cycle < self.cycles end end until current_round == teams.size-1 && current_cycle==self.cycles end @@ -190,56 +164,20 @@ end self.gamedays << Gameday.new(:date => gamedate, :games => games) end end - def get_best_gt(game) - x = {} - gt_left = @gt_ps_avail.reject{|k,v| v.empty?} - gt_left.each_key do |gt| - x[gt] = [ - @stats[game.team_a][:gt][gt] + @stats[game.team_b][:gt][gt], - rand(1000) - ] - end - x.sort_by{|k,v| [v[0],v[1]]}.first[0] - end - - def get_best_ps(game,gt) - x = {} - @gt_ps_avail[gt].each do |ps| - x[ps] = [ - @stats[game.team_a][:ps][ps] + @stats[game.team_b][:ps][ps], - rand(1000) - ] - end - x.sort_by{|k,v| [v[0],v[1]]}.first[0] - end - - def reset_resource_availability - @gt_ps_avail = {} - @cur_rule.gt.each do |gt| - @gt_ps_avail[gt] = @cur_rule.ps.clone - end - end - def dispatch_game(game) if @cur_rule.nil? @cur_rule = @rules.select{|r| r.wday >= self.start_date.wday}.first || @rules.first @cur_rule_index = @rules.index(@cur_rule) reset_resource_availability end @cur_gt = get_best_gt(game) @cur_ps = get_best_ps(game,@cur_gt) - #increment the stats counters to lessen the chances that these teams plays on the same playing surface (or game time) too often - @stats[game.team_a][:gt][@cur_gt] += 1 - @stats[game.team_a][:ps][@cur_ps] += 1 - @stats[game.team_b][:gt][@cur_gt] += 1 - @stats[game.team_b][:ps][@cur_ps] += 1 - @cur_date ||= next_game_date(self.start_date,@cur_rule.wday) @schedule ||= [] #if one of the team has already plays at this gamedate, we change rule if @schedule.size>0 @@ -252,16 +190,18 @@ @cur_ps = get_best_ps(game,@cur_gt) @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday) end end + #We found our playing surface and game time, add the game in the schedule. @schedule << {:team_a => game.team_a, :team_b => game.team_b, :gamedate => @cur_date, :ps => @cur_ps, :gt => @cur_gt} - @gt_ps_avail[@cur_gt].delete(@cur_ps) #this playing surface has now been taken and is not available + update_team_stats(game,@cur_gt,@cur_ps) + update_resource_availability(@cur_gt,@cur_ps) - x = @gt_ps_avail.reject{|k,v| v.empty?} - #no resources left, change rule + #If no resources left, change rule + x = @gt_ps_avail.reject{|k,v| v.empty?} if x.empty? if @cur_rule_index < @rules.size-1 last_rule=@cur_rule @cur_rule_index += 1 @cur_rule = @rules[@cur_rule_index] @@ -280,48 +220,87 @@ def next_game_date(dt,wday) dt += 1 until wday == dt.wday && !self.exclude_dates.include?(dt) dt end + def update_team_stats(game,cur_gt,cur_ps) + @stats[game.team_a][:gt][cur_gt] += 1 + @stats[game.team_a][:ps][cur_ps] += 1 + @stats[game.team_b][:gt][cur_gt] += 1 + @stats[game.team_b][:ps][cur_ps] += 1 + end + + def get_best_gt(game) + x = {} + gt_left = @gt_ps_avail.reject{|k,v| v.empty?} + gt_left.each_key do |gt| + x[gt] = [ + @stats[game.team_a][:gt][gt] + @stats[game.team_b][:gt][gt], + rand(1000) + ] + end + x.sort_by{|k,v| [v[0],v[1]]}.first[0] + end + + def get_best_ps(game,gt) + x = {} + @gt_ps_avail[gt].each do |ps| + x[ps] = [ + @stats[game.team_a][:ps][ps] + @stats[game.team_b][:ps][ps], + rand(1000) + ] + end + x.sort_by{|k,v| [v[0],v[1]]}.first[0] + end + + def reset_resource_availability + @gt_ps_avail = {} + @cur_rule.gt.each do |gt| + @gt_ps_avail[gt] = @cur_rule.ps.clone + end + end + + def update_resource_availability(cur_gt,cur_ps) + @gt_ps_avail[cur_gt].delete(cur_ps) + end + + #return matchups between two teams def face_to_face(team_a,team_b) res=[] self.gamedays.each do |gd| res << gd.games.select {|g| (g.team_a == team_a && g.team_b == team_b) || (g.team_a == team_b && g.team_b == team_a)} end res.flatten end - def all_gt - gt = [] - @rules.each do |r| - gt = gt.concat(r.gt) + #Count the number of times each team plays on a given playing surface and at what time. That way + #we can balance the available playing surfaces/game times among competitors. + def init_stats + @stats = {} + @teams.flatten.each do |t| + @stats[t] = {:gt => {}, :ps => {}} + all_gt.each { |gt| @stats[t][:gt][gt] = 0 } + all_ps.each { |ps| @stats[t][:ps][ps] = 0 } end - gt.flatten.uniq end - def all_ps - ps = [] - @rules.each do |r| - ps = ps.concat(r.ps) - end - ps.flatten.uniq - end + #returns an array of all available game times / playing surfaces, all rules included. + def all_gt; @rules.collect{|r| r.gt}.flatten.uniq; end + def all_ps; @rules.collect{|r| r.ps}.flatten.uniq; end end class Gameday attr_accessor :date, :games def initialize(params) self.date = params[:date] self.games = params[:games] || [] end - end class Rule attr_accessor :wday, :gt, :ps - def initialize(params) self.wday = params[:wday] self.gt = params[:gt] self.ps = params[:ps]