lib/rrschedule.rb in rrschedule-0.1.3 vs lib/rrschedule.rb in rrschedule-0.1.4
- old
+ new
@@ -6,18 +6,30 @@
class Schedule
attr_accessor :playing_surfaces, :game_times, :cycles, :wdays, :start_date, :exclude_dates, :shuffle_initial_order
attr_reader :teams, :rounds
def initialize(params={})
- self.teams = params[:teams] || [1,2,3,4,5]
- self.playing_surfaces = params[:playing_surfaces] || ["--"]
+ self.teams = params[:teams] || [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
+ self.playing_surfaces = Array(params[:playing_surfaces]).empty? ? ["Surface A", "Surface B"] : Array(params[:playing_surfaces])
self.cycles = params[:cycles] || 1
- self.game_times = params[:game_times] || ["Game time not specified"]
+
+ self.game_times = Array(params[:game_times]).empty? ? ["7:00 PM", "9:00 PM"] : Array(params[:game_times])
+ self.game_times.collect! do |gt|
+ begin
+ DateTime.parse(gt)
+ rescue
+ raise "game times must be valid time representations in the string form (e.g. 3:00 PM, 11:00 AM, 18:20, etc)"
+ end
+ end
+
self.shuffle_initial_order = params[:shuffle_initial_order] || true
self.exclude_dates = params[:exclude_dates] || []
self.start_date = params[:start_date] || Time.now.beginning_of_day
self.wdays = Array(params[:wdays]).empty? ? [1] : Array(params[:wdays])
+
+ raise "each value in wdays must be between 0 and 6" if self.wdays.reject{|w| (0..6).member?(w)}.size > 0
+ self
end
def generate(params={})
@teams = @teams.sort_by{rand} if self.shuffle_initial_order
@@ -61,12 +73,13 @@
@teams = @teams.sort_by{rand}
initial_order = @teams.clone
end
end
end until @teams == initial_order && current_cycle==self.cycles
- @teams.delete(:dummy)
- slice(all_games)
+ #@teams.delete(:dummy)
+ slice(all_games)
+ self
end
def face_to_face(team_a,team_b)
res=[]
@@ -81,11 +94,11 @@
res << "#{@schedule.keys.size.to_s} gamedays\n"
@schedule.sort.each do |gd,games|
res << gd.strftime("%Y-%m-%d") + "\n"
res << "==========\n"
games.each do |g|
- res << "#{g.team_a.to_s} VS #{g.team_b.to_s} on playing surface #{g.playing_surface} at #{g.game_time}\n"
+ res << "#{g.team_a.to_s} VS #{g.team_b.to_s} on playing surface #{g.playing_surface} at #{g.game_time.strftime("%I:%M %p")}\n"
end
res << "\n"
end
res
end
@@ -100,28 +113,44 @@
gms << games.select{|g| g.team_a == team || g.team_b == team}
end
gms.flatten
end
+ #TODO: returns true if the generated schedule is a valid round-robin (for testing purpose)
+ def round_robin?
+
+ #each round-robin round should contains n-1 games where n is the nbr of teams (:dummy included if odd)
+ return false if self.rounds.size != (@teams.size*self.cycles)-self.cycles
+
+ #check if each team plays the same number of games against each other
+ self.teams.each do |t1|
+ self.teams.reject{|t| t == t1}.each do |t2|
+ return false unless self.face_to_face(t1,t2).size == self.cycles || [t1,t2].include?(:dummy)
+ end
+ end
+ return true
+ end
+
private
def teams=(arr)
@teams = arr.clone
- @teams << :dummy if arr.size.odd?
+ raise ":dummy is a reserved team name. Please use something else" if @teams.member?(:dummy)
+ raise "at least 2 teams are required" if @teams.size == 1
+ @teams << :dummy if @teams.size.odd?
end
#Let's slice our games according to our physical constraints
def slice(games)
res={}
slices = games.each_slice(games_per_day)
- wdays_stack = self.wdays.clone
-
+ wdays_stack = self.wdays.clone
cur_date = self.start_date
slices.each_with_index do |slice,i|
gt_stack = self.game_times.clone
ps_stack = self.playing_surfaces.clone
- wdays_stack=self.wdays.clone if wdays_stack.empty?
+ wdays_stack = self.wdays.clone if wdays_stack.empty?
cur_wday = wdays_stack.shift
cur_date = next_game_date(cur_date,cur_wday)
cur_gt = gt_stack.shift
@@ -136,9 +165,11 @@
:game_date => cur_date)
cur_gt = gt_stack.shift if ps_stack.empty?
gt_stack = self.game_times.clone if gt_stack.empty?
ps_stack = self.playing_surfaces.clone if ps_stack.empty?
end
+
+ res[cur_date] = res[cur_date].sort_by {|g| [g.game_time,g.playing_surface]}
cur_date += 1.day
end
@schedule = res
end