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]