rrschedule 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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