lib/rrschedule.rb in rrschedule-0.2.2 vs lib/rrschedule.rb in rrschedule-0.2.3
- old
+ new
@@ -87,11 +87,11 @@
res = ""
res << "#{self.gamedays.size.to_s} gamedays\n"
self.gamedays.each do |gd|
res << gd.date.strftime("%Y-%m-%d") + "\n"
res << "==========\n"
- gd.games.each do |g|
+ gd.games.sort{|g1,g2| g1.gt == g2.gt ? g1.ps <=> g2.ps : g1.gt <=> g2.gt}.each do |g|
res << "#{g.ta.to_s} VS #{g.tb.to_s} on playing surface #{g.ps} at #{g.gt.strftime("%I:%M %p")}\n"
end
res << "\n"
end
res
@@ -127,55 +127,32 @@
@flights[i] << :dummy if flight.size.odd?
end
end
#Dispatch games according to available playing surfaces and game times
- #The flat schedule contains "place holders" for the actual games. Each row contains
- #a game date, a game time and a playing surface. We then process our rounds one by one
- #and we put each matchup in the next available slot of the flat schedule
def dispatch_games(rounds)
- teams_day = {}
- flat_schedule = generate_flat_schedule
-
rounds_copy = Marshal.load(Marshal.dump(rounds)) #deep clone
- cur_flight_index = i = 0
+ cur_flight_index = 0
while !rounds_copy.flatten.empty? do
cur_round = rounds_copy[cur_flight_index].shift
-
#process the next round in the current flight
if cur_round
- cur_round.games.shuffle.each do |game|
- unless [game.team_a,game.team_b].include?(:dummy)
- if teams_day[flat_schedule[i][:gamedate]] && (teams_day[flat_schedule[i][:gamedate]].include?(game.team_a) || teams_day[flat_schedule[i][:gamedate]].include?(game.team_b))
- #team is already playing this day. This can happen if we have flights with different number of teams in it.
- gamedate = flat_schedule[i][:gamedate]
- while flat_schedule[i] && flat_schedule[i][:gamedate] == gamedate do
- i += 1
- end
- end
-
- flat_schedule[i][:team_a] = game.team_a
- flat_schedule[i][:team_b] = game.team_b
- teams_day[flat_schedule[i][:gamedate]] ||= []
- teams_day[flat_schedule[i][:gamedate]] << game.team_a
- teams_day[flat_schedule[i][:gamedate]] << game.team_b
- i += 1
- end
+ cur_round.games.each do |game|
+ dispatch_game(game) unless [game.team_a,game.team_b].include?(:dummy)
end
end
-
if cur_flight_index == @flights.size-1
cur_flight_index = 0
else
cur_flight_index += 1
end
end
- #We group our flat schedule by gameday
- s=flat_schedule.group_by{|fs| fs[:gamedate]}.sort
+ #We group our schedule by gameday
+ s=@schedule.group_by{|fs| fs[:gamedate]}.sort
s.each do |gamedate,gms|
games = []
gms.each do |gm|
games << Game.new(
:team_a => gm[:team_a],
@@ -184,59 +161,115 @@
:game_time => gm [:gt]
)
end
self.gamedays << Gameday.new(:date => gamedate, :games => games)
end
- self.gamedays.each { |gd| gd.games.reject! {|g| g.team_a.nil?}}
end
- def generate_flat_schedule
- flat_schedule = []
- games_left = max_games_per_day = day_game_ctr = rule_ctr = 0
+ def dispatch_game(game)
+ @cur_rule ||= @rules.select{|r| r.wday >= self.start_date.wday}.first || @rules.first
+ @cur_rule_index ||= @rules.index(@cur_rule)
- #determine first rule based on the nearest gameday
- cur_rule = @rules.select{|r| r.wday >= self.start_date.wday}.first || @rules.first
- cur_rule_index = @rules.index(cur_rule)
- cur_date = next_game_date(self.start_date,cur_rule.wday)
+ @gt_stack ||= @cur_rule.gt.clone
+ @ps_stack ||= @cur_rule.ps.clone.shuffle
- @flights.each do |flight|
- games_left += @cycles * (flight.include?(:dummy) ? ((flight.size-1)/2.0)*(flight.size-2) : (flight.size/2)*(flight.size-1))
- max_games_per_day += (flight.include?(:dummy) ? ((flight.size-2)/2.0) : (flight.size-1)/2.0).ceil
+ @cur_gt ||= @gt_stack.shift
+ @cur_ps ||= @ps_stack.shift
+ @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
+ games_this_date = @schedule.select{|v| v[:gamedate] == @cur_date}
+ if games_this_date.select{|g| [game.team_a,game.team_b].include?(g[:team_a]) || [game.team_a,game.team_b].include?(g[:team_b])}.size >0
+ @cur_rule_index = (@cur_rule_index < @rules.size-1) ? @cur_rule_index+1 : 0
+ @cur_rule = @rules[@cur_rule_index]
+ @gt_stack = @cur_rule.gt.clone
+ @ps_stack = @cur_rule.ps.clone.shuffle
+ @cur_gt = @gt_stack.shift
+ @cur_ps = @ps_stack.shift
+ @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
+ end
end
+ @schedule << {:team_a => game.team_a, :team_b => game.team_b, :gamedate => @cur_date, :ps => @cur_ps, :gt => @cur_gt}
- #while there are games to process...
- while games_left > 0 do
+ if !@ps_stack.empty?
+ @cur_ps = @ps_stack.shift
+ else
+ if !@gt_stack.empty?
+ @cur_gt = @gt_stack.shift
+ @ps_stack = @cur_rule.ps.clone.shuffle; @cur_ps = @ps_stack.shift
+ else
+ #PS and GT stack empty... we go to the next rule
+ if @cur_rule_index < @rules.size-1
+ @cur_rule_index += 1
+ #Go to the next date (except if the new rule is for the same weekday)
+ @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday) if @cur_rule.wday != @rules[@cur_rule_index].wday
+ else
+ @cur_rule_index = 0
+ @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
+ end
+ @cur_rule = @rules[@cur_rule_index]
+ @gt_stack = @cur_rule.gt.clone; @cur_gt = @gt_stack.shift
+ @ps_stack = @cur_rule.ps.clone.shuffle; @cur_ps = @ps_stack.shift
+ end
+ end
- #add all possible games based on the current rule
- cur_rule.gt.each do |gt|
- cur_rule.ps.each do |ps|
+ end
- #if there are more physical resources (playing surfaces and game times) for a given day than
- #we need, we don't use them all (or else some teams would play twice on a single day)
- if day_game_ctr <= max_games_per_day-1
- flat_schedule << {:gamedate => cur_date, :gt => gt, :ps => ps}
- games_left -= 1; day_game_ctr += 1
- end
- end
+ def place_game(game)
+ @cur_rule ||= @rules.select{|r| r.wday >= self.start_date.wday}.first || @rules.first
+
+ @cur_rule_index ||= @rules.index(@cur_rule)
+ @cur_gt_index ||= 0
+ @cur_ps_index ||= 0
+
+ @cur_gt = @cur_rule.gt[@cur_gt_index]
+ @cur_ps = @cur_rule.ps[@cur_ps_index]
+ @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
+ games_this_date = @schedule.select{|v| v[:gamedate] == @cur_date}
+ if games_this_date.select{|g| [game.team_a,game.team_b].include?(g[:team_a]) || [game.team_a,game.team_b].include?(g[:team_b])}.size >0
+ @cur_rule_index = (@cur_rule_index < @rules.size-1) ? @cur_rule_index+1 : 0
+ @cur_rule = @rules[@cur_rule_index]
+ @cur_ps_index=0
+ @cur_gt_index=0
+ @cur_ps = @cur_rule.ps.first
+ @cur_gt = @cur_rule.gt.first
+ @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
end
+ end
- last_rule = cur_rule
- last_date = cur_date
+ @schedule << {:team_a => game.team_a, :team_b => game.team_b, :gamedate => @cur_date, :ps => @cur_ps, :gt => @cur_gt}
- #Advance to the next rule (if we're at the last one, we go back to the first)
- cur_rule_index = (cur_rule_index == @rules.size-1) ? 0 : cur_rule_index + 1
- cur_rule = @rules[cur_rule_index]
+ if @cur_ps_index < @cur_rule.ps.size-1
+ @cur_ps_index += 1
+ else
+ @cur_ps_index = 0
- #Go to the next date (except if the new rule is for the same weekday)
- if cur_rule.wday != last_rule.wday || cur_rule_index == 0
- cur_date = next_game_date(cur_date+=1,cur_rule.wday)
- day_game_ctr = 0
+ if @cur_gt_index < @cur_rule.gt.size-1
+ @cur_gt_index += 1
+ else
+ @cur_gt_index = 0
+
+ if @cur_rule_index < @rules.size-1
+ @cur_rule_index += 1
+ #Go to the next date (except if the new rule is for the same weekday)
+ @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday) if @cur_rule.wday != @rules[@cur_rule_index].wday
+ else
+ @cur_rule_index = 0
+ @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
+ end
+ @cur_rule = @rules[@cur_rule_index]
end
end
- flat_schedule
end
+
#get the next gameday
def next_game_date(dt,wday)
dt += 1 until wday == dt.wday && !self.exclude_dates.include?(dt)
dt