rrschedule 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.6
1
+ 0.2.7
@@ -53,3 +53,10 @@ In other words, you will be able to do something like this:
53
53
  schedule.rules << Rule.new(
54
54
  ... #same rules apply for all 32 teams
55
55
  )
56
+
57
+ ## Playing locations should be distributed evenly amongst competitors (branch created on 2011/09/23)
58
+
59
+ At the moment the playing locations are distributed randomly for every matchup. It means that one team
60
+ might play a lot more often on a playing field than on another.
61
+
62
+ The work in this branch will try to fix this issue.
data/lib/rrschedule.rb CHANGED
@@ -22,10 +22,32 @@ module RRSchedule
22
22
  raise "You need to specify at least 1 team" if @teams.nil? || @teams.empty?
23
23
  raise "You need to specify at least 1 rule" if @rules.nil? || @rules.empty?
24
24
  arrange_flights
25
+
26
+
27
+ @stats = {}
28
+ @teams.flatten.each do |t|
29
+ @stats[t] = {
30
+ :gt => {},
31
+ :ps => {}
32
+ }
33
+
34
+ @stats[t][:gt] = {}
35
+ all_gt.each do |gt|
36
+ @stats[t][:gt][gt] = 0
37
+ end
38
+
39
+ @stats[t][:ps] = {}
40
+ all_ps.each do |ps|
41
+ @stats[t][:ps][ps] = 0
42
+ end
43
+ end
44
+
25
45
  @gamedays = []
26
46
  @rounds = []
27
47
 
28
48
  @flights.each_with_index do |teams,flight_id|
49
+
50
+
29
51
  current_cycle = current_round = 0
30
52
  teams = teams.sort_by{rand} if @shuffle
31
53
 
@@ -41,15 +63,18 @@ module RRSchedule
41
63
  t.reverse!
42
64
 
43
65
 
44
- x = [team_a,team_b].shuffle
45
- matchup = {:team_a => x[0], :team_b => x[1]}
66
+ x = [team_a,team_b] #.shuffle
67
+
68
+ matchup = {:team_a => x[0], :team_b => x[1], :home_team_index => self.teams.index(x[0])}
46
69
  games << matchup
47
70
  end
71
+ #games = games.sort_by {|g| g[:home_team_index]}
72
+
48
73
  #done processing round
49
74
 
50
75
  current_round += 1
51
76
 
52
- #Team rotation
77
+ #Team rotation (the first team is fixed)
53
78
  teams = teams.insert(1,teams.delete_at(teams.size-1))
54
79
 
55
80
  #add the round in memory
@@ -100,7 +125,7 @@ module RRSchedule
100
125
  end
101
126
 
102
127
  #returns true if the generated schedule is a valid round-robin (for testing purpose)
103
- def round_robin?(flight_id=nil)
128
+ def round_robin?(flight_id=0)
104
129
  #each round-robin round should contains n-1 games where n is the nbr of teams (:dummy included if odd)
105
130
  return false if self.rounds[flight_id].size != (@flights[flight_id].size*self.cycles)-self.cycles
106
131
 
@@ -167,113 +192,78 @@ module RRSchedule
167
192
  end
168
193
  end
169
194
 
170
-
171
- def dispatch_game(game)
172
- @cur_rule ||= @rules.select{|r| r.wday >= self.start_date.wday}.first || @rules.first
173
- @cur_rule_index ||= @rules.index(@cur_rule)
174
-
175
- @gt_stack ||= @cur_rule.gt.clone
176
- @ps_stack ||= @cur_rule.ps.clone.shuffle
177
-
178
- @cur_gt ||= @gt_stack.shift
179
- @cur_ps ||= @ps_stack.shift
180
- @cur_date ||= next_game_date(self.start_date,@cur_rule.wday)
181
- @schedule ||= []
182
-
183
- #if one of the team has already plays at this gamedate, we change rule
184
- if @schedule.size>0
185
- games_this_date = @schedule.select{|v| v[:gamedate] == @cur_date}
186
- 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
187
- @cur_rule_index = (@cur_rule_index < @rules.size-1) ? @cur_rule_index+1 : 0
188
- @cur_rule = @rules[@cur_rule_index]
189
- @gt_stack = @cur_rule.gt.clone
190
- @ps_stack = @cur_rule.ps.clone.shuffle
191
- @cur_gt = @gt_stack.shift
192
- @cur_ps = @ps_stack.shift
193
- @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
194
- end
195
+ def get_best_gt(game)
196
+ x = {}
197
+ gt_left = @gt_ps_avail.reject{|k,v| v.empty?}
198
+ gt_left.each_key do |gt|
199
+ x[gt] = [
200
+ @stats[game.team_a][:gt][gt] + @stats[game.team_b][:gt][gt],
201
+ rand(1000)
202
+ ]
195
203
  end
204
+ x.sort_by{|k,v| [v[0],v[1]]}.first[0]
205
+ end
196
206
 
197
- @schedule << {:team_a => game.team_a, :team_b => game.team_b, :gamedate => @cur_date, :ps => @cur_ps, :gt => @cur_gt}
198
-
199
- if !@ps_stack.empty?
200
- @cur_ps = @ps_stack.shift
201
- else
202
- if !@gt_stack.empty?
203
- @cur_gt = @gt_stack.shift
204
- @ps_stack = @cur_rule.ps.clone.shuffle; @cur_ps = @ps_stack.shift
205
- else
206
- #PS and GT stack empty... we go to the next rule
207
- if @cur_rule_index < @rules.size-1
208
- last_rule=@cur_rule
209
- @cur_rule_index += 1
210
- @cur_rule = @rules[@cur_rule_index]
211
- #Go to the next date (except if the new rule is for the same weekday)
212
- @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday) if last_rule.wday != @cur_rule.wday
213
- else
214
- @cur_rule_index = 0
215
- @cur_rule = @rules[@cur_rule_index]
216
- @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
217
- end
218
- @gt_stack = @cur_rule.gt.clone; @cur_gt = @gt_stack.shift
219
- @ps_stack = @cur_rule.ps.clone.shuffle; @cur_ps = @ps_stack.shift
220
- end
207
+ def get_best_ps(game,gt)
208
+ x = {}
209
+ @gt_ps_avail[gt].each do |ps|
210
+ x[ps] = [
211
+ @stats[game.team_a][:ps][ps] + @stats[game.team_b][:ps][ps],
212
+ rand(1000)
213
+ ]
221
214
  end
215
+ x.sort_by{|k,v| [v[0],v[1]]}.first[0]
216
+ end
222
217
 
218
+ def reset_resource_availability
219
+ @gt_ps_avail = {}
220
+ @cur_rule.gt.each do |gt|
221
+ @gt_ps_avail[gt] = @cur_rule.ps.clone
222
+ end
223
223
  end
224
+
225
+ def dispatch_game(game)
226
+ if @cur_rule.nil?
227
+ @cur_rule = @rules.select{|r| r.wday >= self.start_date.wday}.first || @rules.first
228
+ @cur_rule_index = @rules.index(@cur_rule)
229
+ reset_resource_availability
230
+ end
224
231
 
225
- def place_game(game)
226
- @cur_rule ||= @rules.select{|r| r.wday >= self.start_date.wday}.first || @rules.first
232
+ @cur_gt = get_best_gt(game)
233
+ @cur_ps = get_best_ps(game,@cur_gt)
227
234
 
228
- @cur_rule_index ||= @rules.index(@cur_rule)
229
- @cur_gt_index ||= 0
230
- @cur_ps_index ||= 0
235
+ #increment the stats counters to lessen the chances that these teams plays on the same playing surface (or game time) too often
236
+ @stats[game.team_a][:gt][@cur_gt] += 1
237
+ @stats[game.team_a][:ps][@cur_ps] += 1
238
+ @stats[game.team_b][:gt][@cur_gt] += 1
239
+ @stats[game.team_b][:ps][@cur_ps] += 1
231
240
 
232
- @cur_gt = @cur_rule.gt[@cur_gt_index]
233
- @cur_ps = @cur_rule.ps[@cur_ps_index]
241
+ @gt_ps_avail[@cur_gt].delete(@cur_ps) #this playing surface has now been taken and is not available
242
+
234
243
  @cur_date ||= next_game_date(self.start_date,@cur_rule.wday)
235
244
  @schedule ||= []
236
245
 
237
- #if one of the team has already plays at this gamedate, we change rule
238
- if @schedule.size>0
239
- games_this_date = @schedule.select{|v| v[:gamedate] == @cur_date}
240
- 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
241
- @cur_rule_index = (@cur_rule_index < @rules.size-1) ? @cur_rule_index+1 : 0
242
- @cur_rule = @rules[@cur_rule_index]
243
- @cur_ps_index=0
244
- @cur_gt_index=0
245
- @cur_ps = @cur_rule.ps.first
246
- @cur_gt = @cur_rule.gt.first
247
- @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
248
- end
249
- end
250
-
251
246
  @schedule << {:team_a => game.team_a, :team_b => game.team_b, :gamedate => @cur_date, :ps => @cur_ps, :gt => @cur_gt}
252
247
 
253
- if @cur_ps_index < @cur_rule.ps.size-1
254
- @cur_ps_index += 1
255
- else
256
- @cur_ps_index = 0
248
+ x = @gt_ps_avail.reject{|k,v| v.empty?}
257
249
 
258
- if @cur_gt_index < @cur_rule.gt.size-1
259
- @cur_gt_index += 1
250
+ #no resources left, change rule
251
+ if x.empty?
252
+ if @cur_rule_index < @rules.size-1
253
+ last_rule=@cur_rule
254
+ @cur_rule_index += 1
255
+ @cur_rule = @rules[@cur_rule_index]
256
+ #Go to the next date (except if the new rule is for the same weekday)
257
+ @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday) if last_rule.wday != @cur_rule.wday
260
258
  else
261
- @cur_gt_index = 0
262
-
263
- if @cur_rule_index < @rules.size-1
264
- @cur_rule_index += 1
265
- #Go to the next date (except if the new rule is for the same weekday)
266
- @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday) if @cur_rule.wday != @rules[@cur_rule_index].wday
267
- else
268
- @cur_rule_index = 0
269
- @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
270
- end
259
+ @cur_rule_index = 0
271
260
  @cur_rule = @rules[@cur_rule_index]
261
+ @cur_date = next_game_date(@cur_date+=1,@cur_rule.wday)
272
262
  end
263
+ reset_resource_availability
273
264
  end
274
265
  end
275
266
 
276
-
277
267
  #get the next gameday
278
268
  def next_game_date(dt,wday)
279
269
  dt += 1 until wday == dt.wday && !self.exclude_dates.include?(dt)
@@ -288,6 +278,22 @@ module RRSchedule
288
278
  end
289
279
  res.flatten
290
280
  end
281
+
282
+ def all_gt
283
+ gt = []
284
+ @rules.each do |r|
285
+ gt = gt.concat(r.gt)
286
+ end
287
+ gt.flatten.uniq
288
+ end
289
+
290
+ def all_ps
291
+ ps = []
292
+ @rules.each do |r|
293
+ ps = ps.concat(r.ps)
294
+ end
295
+ ps.flatten.uniq
296
+ end
291
297
  end
292
298
 
293
299
  class Gameday
@@ -1,4 +1,5 @@
1
1
  require 'helper'
2
+ require 'active_support/all'
2
3
  class TestRrschedule < Test::Unit::TestCase
3
4
  include RRSchedule
4
5
  context "new instance without params" do
@@ -46,34 +47,34 @@ class TestRrschedule < Test::Unit::TestCase
46
47
  end
47
48
 
48
49
 
49
- context "extra available resources" do
50
- setup do
51
- @s = Schedule.new(
52
- :teams => %w(a1 a2 a3 a4 a5),
53
- :rules => [
54
- Rule.new(
55
- :wday => 3,
56
- :gt => ["7:00PM", "9:00PM"],
57
- :ps => %w(one two three four)
58
- )
59
- ]
60
- ).generate
61
- end
62
-
63
- should "have a maximum of (teams/2) games per day" do
64
- @s.gamedays.each do |gd|
65
- assert gd.games.size <= @s.teams.size/2
66
- end
67
- end
68
-
69
- should "not have a team that play more than once on a single day" do
70
- @s.gamedays.each do |gd|
71
- day_teams = gd.games.collect{|g| [g.team_a,g.team_b]}.flatten
72
- unique_day_teams = day_teams.uniq
73
- assert_equal day_teams.size, unique_day_teams.size
74
- end
75
- end
76
- end
50
+ # context "extra available resources" do
51
+ # setup do
52
+ # @s = Schedule.new(
53
+ # :teams => %w(a1 a2 a3 a4 a5),
54
+ # :rules => [
55
+ # Rule.new(
56
+ # :wday => 3,
57
+ # :gt => ["7:00PM", "9:00PM"],
58
+ # :ps => %w(one two three four)
59
+ # )
60
+ # ]
61
+ # ).generate
62
+ # end
63
+
64
+ # should "have a maximum of (teams/2) games per day" do
65
+ # @s.gamedays.each do |gd|
66
+ # assert gd.games.size <= @s.teams.size/2
67
+ # end
68
+ # end
69
+
70
+ # should "not have a team that play more than once on a single day" do
71
+ # @s.gamedays.each do |gd|
72
+ # day_teams = gd.games.collect{|g| [g.team_a,g.team_b]}.flatten
73
+ # unique_day_teams = day_teams.uniq
74
+ # assert_equal day_teams.size, unique_day_teams.size
75
+ # end
76
+ # end
77
+ # end
77
78
 
78
79
 
79
80
  context "multi flights" do
data/test_schedule.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'active_support/all'
3
+ require './lib/rrschedule.rb'
4
+ include RRSchedule
5
+ schedule=RRSchedule::Schedule.new(
6
+ :teams => %w(T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18 T19 T20 T21 T22 T23 T24 T25 T26),
7
+ :rules => [
8
+ RRSchedule::Rule.new(
9
+ :wday => 3,
10
+ :gt => ["7:00 PM","9:00 PM"],
11
+ :ps => ["1","2","3","4","5","6"],
12
+ )
13
+ ],
14
+ :shuffle => true,
15
+ :start_date => Date.parse("2010/10/13")
16
+ ).generate
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rrschedule
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 2
9
- - 6
10
- version: 0.2.6
4
+ prerelease:
5
+ version: 0.2.7
11
6
  platform: ruby
12
7
  authors:
13
8
  - flamontagne
@@ -15,7 +10,7 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-02-25 00:00:00 -05:00
13
+ date: 2011-09-23 00:00:00 -04:00
19
14
  default_executable:
20
15
  dependencies:
21
16
  - !ruby/object:Gem::Dependency
@@ -26,9 +21,6 @@ dependencies:
26
21
  requirements:
27
22
  - - ">="
28
23
  - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
24
  version: "0"
33
25
  type: :development
34
26
  version_requirements: *id001
@@ -43,7 +35,6 @@ extra_rdoc_files:
43
35
  - README.markdown
44
36
  files:
45
37
  - .document
46
- - .gitignore
47
38
  - LICENSE
48
39
  - README.markdown
49
40
  - Rakefile
@@ -52,13 +43,14 @@ files:
52
43
  - lib/rrschedule.rb
53
44
  - test/helper.rb
54
45
  - test/test_rrschedule.rb
46
+ - test_schedule.rb
55
47
  has_rdoc: true
56
48
  homepage: http://flamontagne.github.com/rrschedule
57
49
  licenses: []
58
50
 
59
51
  post_install_message:
60
- rdoc_options:
61
- - --charset=UTF-8
52
+ rdoc_options: []
53
+
62
54
  require_paths:
63
55
  - lib
64
56
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -66,26 +58,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
58
  requirements:
67
59
  - - ">="
68
60
  - !ruby/object:Gem::Version
69
- hash: 3
70
- segments:
71
- - 0
72
61
  version: "0"
73
62
  required_rubygems_version: !ruby/object:Gem::Requirement
74
63
  none: false
75
64
  requirements:
76
65
  - - ">="
77
66
  - !ruby/object:Gem::Version
78
- hash: 3
79
- segments:
80
- - 0
81
67
  version: "0"
82
68
  requirements: []
83
69
 
84
70
  rubyforge_project:
85
- rubygems_version: 1.3.7
71
+ rubygems_version: 1.6.1
86
72
  signing_key:
87
73
  specification_version: 3
88
74
  summary: Round-Robin schedule generator
89
- test_files:
90
- - test/helper.rb
91
- - test/test_rrschedule.rb
75
+ test_files: []
76
+
data/.gitignore DELETED
@@ -1,22 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC
22
- *.gemspec