icu_ratings 1.4.0 → 1.5.0

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/README.rdoc CHANGED
@@ -4,11 +4,11 @@ For calculating the Elo ratings of players in a chess tournament. The software i
4
4
  the Irish Chess Union's existing rating software written in Microsoft Visual Basic and
5
5
  intended to replace it in the near future.
6
6
 
7
- The rating calculations are identical to FIDE's for tournaments that consist entirely
8
- of established players (with the exception of player bonuses, which can be turned off).
7
+ The rating calculations are the same as FIDE's for tournaments that consist entirely
8
+ of established players with the exception of player bonuses (which can be turned off)
9
+ and different rules for assigning K-factors.
9
10
  However, the ICU has it's own peculiar way of dealing with unrated players (players
10
- with only a provisional rating or without any prior rating) which is not the same as
11
- FIDE's.
11
+ with only a provisional rating or without any prior rating) which is different to FIDE's.
12
12
 
13
13
  == Install
14
14
 
@@ -35,9 +35,9 @@ Then add results (see ICU::RatedResult for details):
35
35
  t.add_result(4, 2, 1, 'D') # players 1 and 2 drew in round 4
36
36
  # ...
37
37
 
38
- Then call the <em>rate!</em> method.
38
+ Then call the <em>rate!</em> method using the recommended version of the algorithm (see ICU::RatedTournament).
39
39
 
40
- t.rate!
40
+ t.rate!(version: 2)
41
41
 
42
42
  If no exceptions have been raised yet, the tournament is now rated and the
43
43
  main results of the rating calculations can be extracted by querying the
@@ -241,8 +241,9 @@ module ICU
241
241
  @bonus = 0
242
242
  end
243
243
 
244
- def rate! # :nodoc:
244
+ def rate!(update_bonus=false) # :nodoc:
245
245
  @results.each { |r| r.rate!(self) }
246
+ @bonus_rating = @rating + @bonus + rating_change if update_bonus && @bonus_rating
246
247
  end
247
248
 
248
249
  def estimate_performance # :nodoc:
@@ -273,9 +274,7 @@ module ICU
273
274
  stable
274
275
  end
275
276
 
276
- def calculate_bonus(allow_new_bonus) # :nodoc:
277
- # New in December 2012 - see http://ratings.icu.ie/articles/18 (Part 2).
278
- return if !allow_new_bonus && @bonus == 0
277
+ def calculate_bonus # :nodoc:
279
278
  # Rounding is performed in places to emulate the older MSAccess implementation.
280
279
  return if @type != :rated || @kfactor <= 24 || @results.size <= 4 || @rating >= 2100
281
280
  change = rating_change
@@ -85,25 +85,12 @@ module ICU
85
85
  #
86
86
  # == After the Tournament is Rated
87
87
  #
88
- # The main rating calculations are avaiable from player methods (see ICU::RatedPlayer)
88
+ # The main rating calculations are available from player methods (see ICU::RatedPlayer)
89
89
  # but additional details are available via methods of each player's individual results:
90
90
  # _expected_score_, _rating_change_.
91
91
  #
92
92
  class RatedResult
93
- # The round number.
94
- def round
95
- @round
96
- end
97
-
98
- # The player's opponent (an instance of ICU::RatedPlayer).
99
- def opponent
100
- @opponent
101
- end
102
-
103
- # The player's score in this game (1.0, 0.5 or 0.0).
104
- def score
105
- @score
106
- end
93
+ attr_reader :round, :opponent, :score
107
94
 
108
95
  # After the tournament has been rated, this returns the expected score (between 0 and 1)
109
96
  # for the player based on the rating difference with the opponent scaled by 400.
@@ -57,27 +57,20 @@ module ICU
57
57
  #
58
58
  # See ICU::RatedPlayer and ICU::RatedResult for more details.
59
59
  #
60
- # The <em>rate!</em> method takes some optional arguments to control the algorithm, for example:
60
+ # The <em>rate!</em> method takes an optional <em>version</em> argument to control the precise algorithm, for example:
61
61
  #
62
- # t.rate!(max_iterations2: 30, phase_2_bonuses: false) # these are the recommended options
62
+ # t.rate!(version: 2)
63
63
  #
64
- # The complete set of current options, with their defaults, is:
65
- #
66
- # * <em>max_iterations1</em>: the maximum number of re-estimation iterations before the bonus calculation (default <b>30</b>)
67
- # * <em>max_iterations2</em>: the maximum number of re-estimation iterations after the bonus calculation (default <b>1</b>)
68
- # * <em>threshold</em>: the maximum difference allowed between re-estimated ratings in a stabe solution (default <b>0.5</b>)
69
- # * <em>phase_2_bonuses</em>: allow new bonuses in the second phase of calculation (default <b>true</b>)
70
- #
71
- # The defaults correspond to the original algorithm. However, it is recommended not to use the defaults for
72
- # <em>max_iterations2</em> and <em>phase_2_bonuses</em> but to use <em>30</em> and <em>false</em> instead.
73
- # See <a href="http://ratings.icu.ie/articles/18">this article</a> for more details.
64
+ # Without a version number or with version <em>0</em>, the original pre-2012 algorithm is used. However, some improvements
65
+ # have since been found (see http://ratings.icu.ie/articles/18 for more details) and currently
66
+ # the recommended version to use is <b>2</b>.
74
67
  #
75
68
  # == Error Handling
76
69
  #
77
70
  # Some of the above methods have the potential to raise RuntimeError exceptions.
78
- # In the case of _add_player_ and _add_result_, the use of invalid arguments
79
- # would cause such an error. Theoretically, the <em>rate!</em> method could also throw an
80
- # exception if the iterative algorithm it uses to estimate performance ratings
71
+ # In the case of _add_player_ and _add_result_, the use of invalid arguments would
72
+ # cause such an error. Theoretically, the <em>rate!</em> method could also throw
73
+ # an exception if the iterative algorithm it uses to estimate performance ratings
81
74
  # of unrated players failed to converge. However an instance of non-convergence
82
75
  # has yet to be observed in practice.
83
76
  #
@@ -113,17 +106,35 @@ module ICU
113
106
 
114
107
  # Rate the tournament. Called after all players and results have been added.
115
108
  def rate!(opt={})
116
- max_iterations1 = opt[:max_iterations1] || 30
117
- max_iterations2 = opt[:max_iterations2] || 1 # legacy default - see http://ratings.icu.ie/articles/18 (Part 1)
118
- phase_2_bonuses = opt.has_key?(:phase_2_bonuses) ? opt[:phase_2_bonuses] : true # legacy default - see http://ratings.icu.ie/articles/18 (Part 2)
119
- threshold = opt[:threshold] || 0.5
109
+ # The original algorithm (version 0).
110
+ max_iterations = [30, 1]
111
+ phase_2_bonuses = true
112
+ update_bonuses = false
113
+ threshold = 0.5
114
+
115
+ # New versions of the algorithm.
116
+ version = opt[:version].to_i
117
+ if version >= 1
118
+ # See http://ratings.icu.ie/articles/18 (Part 1)
119
+ max_iterations[1] = 30
120
+ end
121
+ if version >= 2
122
+ # See http://ratings.icu.ie/articles/18 (Part 2)
123
+ phase_2_bonuses = false
124
+ update_bonuses = true
125
+ threshold = 0.1
126
+ end
127
+
128
+ # Phase 1.
120
129
  players.each { |p| p.init }
121
- @iterations1 = performance_ratings(max_iterations1, threshold)
130
+ @iterations1 = performance_ratings(max_iterations[0], threshold)
122
131
  players.each { |p| p.rate! }
132
+
133
+ # Phase 2.
123
134
  if !no_bonuses && calculate_bonuses > 0
124
- players.each { |p| p.rate! }
125
- @iterations2 = performance_ratings(max_iterations2, threshold)
126
- calculate_bonuses(phase_2_bonuses)
135
+ players.each { |p| p.rate!(update_bonuses) }
136
+ @iterations2 = performance_ratings(max_iterations[1], threshold)
137
+ calculate_bonuses if phase_2_bonuses
127
138
  else
128
139
  @iterations2 = 0
129
140
  end
@@ -157,7 +168,7 @@ module ICU
157
168
  @player = Hash.new
158
169
  end
159
170
 
160
- # Calculate performance ratings either iteratively or with just one sweep for bonus calculations.
171
+ # Calculate performance ratings either iteratively up to a maximum number.
161
172
  def performance_ratings(max, thresh)
162
173
  stable, count = false, 0
163
174
  while !stable && count < max
@@ -170,8 +181,8 @@ module ICU
170
181
  end
171
182
 
172
183
  # Calculate bonuses for all players and return the number who got one.
173
- def calculate_bonuses(allow_new_bonus=true)
174
- @player.values.inject(0) { |t,p| t + (p.calculate_bonus(allow_new_bonus) ? 1 : 0) }
184
+ def calculate_bonuses
185
+ @player.values.inject(0) { |t,p| t + (p.calculate_bonus ? 1 : 0) }
175
186
  end
176
187
  end
177
188
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ICU
4
4
  class Ratings
5
- VERSION = "1.4.0"
5
+ VERSION = "1.5.0"
6
6
  end
7
7
  end
@@ -1218,7 +1218,7 @@ module ICU
1218
1218
  @t.iterations2.should be_nil
1219
1219
  end
1220
1220
 
1221
- it "should produce inconsistent results with default settings" do
1221
+ it "should produce inconsistent results with original algorithm" do
1222
1222
  @t.rate!
1223
1223
 
1224
1224
  @p.new_rating.should be_within(0.5).of(763) # the original calculation
@@ -1239,8 +1239,8 @@ module ICU
1239
1239
  @t.iterations2.should == 1
1240
1240
  end
1241
1241
 
1242
- it "should produce consistent results with more iterations after the bonus stage" do
1243
- @t.rate!(max_iterations2: 30)
1242
+ it "should produce consistent results with version 1 algorithm" do
1243
+ @t.rate!(version: 1)
1244
1244
 
1245
1245
  @p.new_rating.should_not be_within(0.5).of(763) # the new calculation is different
1246
1246
 
@@ -1265,7 +1265,7 @@ module ICU
1265
1265
  before(:each) do
1266
1266
  @t = ICU::RatedTournament.new(desc: "Bunratty Minor 2012")
1267
1267
 
1268
- # Add the player's of most interest (Sasha-Ettore Faleschini and his opponents).
1268
+ # Add the players of most interest (Sasha-Ettore Faleschini and his opponents).
1269
1269
  @p = @t.add_player(1752, desc: "Sasha-Ettore Faleschini")
1270
1270
  @o1 = @t.add_player(1748, desc: "John P. Dunne", rating: 946, kfactor: 40)
1271
1271
  @o2 = @t.add_player(1755, desc: "Jack Fitzgerald", rating: 913, kfactor: 40)
@@ -1276,57 +1276,57 @@ module ICU
1276
1276
 
1277
1277
  # Add all the other players.
1278
1278
  @t.add_player(1730, desc: "Jeffrey Alfred", rating: 1058, kfactor: 40)
1279
- @t.add_player(1731, desc: "Suliman Ali", rating: 1166, rating: 17)
1279
+ @t.add_player(1731, desc: "Suliman Ali", rating: 1166, games: 17)
1280
1280
  @t.add_player(1733, desc: "Dylan Boland")
1281
1281
  @t.add_player(1734, desc: "Shane Briggs", rating: 1079, kfactor: 24)
1282
1282
  @t.add_player(1735, desc: "Joe Browne", rating: 919, kfactor: 24)
1283
- @t.add_player(1736, desc: "Kieran Burke", rating: 765, rating: 10)
1283
+ @t.add_player(1736, desc: "Kieran Burke", rating: 765, games: 10)
1284
1284
  @t.add_player(1737, desc: "Liam Cadogan", rating: 1002, kfactor: 24)
1285
- @t.add_player(1738, desc: "Evan Cahill", rating: 494, rating: 4)
1285
+ @t.add_player(1738, desc: "Evan Cahill", rating: 494, games: 4)
1286
1286
  @t.add_player(1739, desc: "Joseph Cesar", rating: 751, kfactor: 40)
1287
- @t.add_player(1740, desc: "Joshua Cesar", rating: 403, rating: 10)
1287
+ @t.add_player(1740, desc: "Joshua Cesar", rating: 403, games: 10)
1288
1288
  @t.add_player(1741, desc: "John G. Connolly", rating: 952, kfactor: 32)
1289
1289
  @t.add_player(1742, desc: "Fiona Cormican", rating: 483, kfactor: 32)
1290
- @t.add_player(1743, desc: "Joe Cronin", rating: 601, rating: 6)
1291
- @t.add_player(1744, desc: "Aaron Daly", rating: 699, rating: 12)
1290
+ @t.add_player(1743, desc: "Joe Cronin", rating: 601, games: 6)
1291
+ @t.add_player(1744, desc: "Aaron Daly", rating: 699, games: 12)
1292
1292
  @t.add_player(1745, desc: "Conor Devilly", rating: 676, kfactor: 40)
1293
1293
  @t.add_player(1746, desc: "Charles Dillon")
1294
1294
  @t.add_player(1747, desc: "Jack Donovan")
1295
1295
  @t.add_player(1749, desc: "Thomas Dunne", rating: 887, kfactor: 32)
1296
1296
  @t.add_player(1750, desc: "Michael Eyers", rating: 857, kfactor: 32)
1297
- @t.add_player(1751, desc: "Sean Fagan", rating: 243, rating: 10)
1298
- @t.add_player(1753, desc: "Victoria Fennell", rating: 166, rating: 11)
1297
+ @t.add_player(1751, desc: "Sean Fagan", rating: 243, games: 10)
1298
+ @t.add_player(1753, desc: "Victoria Fennell", rating: 166, games: 11)
1299
1299
  @t.add_player(1754, desc: "Mark Finn-Lynch")
1300
- @t.add_player(1756, desc: "Peter Fletcher", rating: 680, rating: 18)
1300
+ @t.add_player(1756, desc: "Peter Fletcher", rating: 680, games: 18)
1301
1301
  @t.add_player(1757, desc: "Darragh Flynn", rating: 296, kfactor: 40)
1302
- @t.add_player(1758, desc: "Geordan Freeman", rating: 413, rating: 4)
1302
+ @t.add_player(1758, desc: "Geordan Freeman", rating: 413, games: 4)
1303
1303
  @t.add_player(1759, desc: "Ruairi Freeman", rating: 582, kfactor: 40)
1304
1304
  @t.add_player(1760, desc: "Aoife Gallagher")
1305
1305
  @t.add_player(1761, desc: "Hannah Gallagher")
1306
1306
  @t.add_player(1762, desc: "Tommy Gallagher")
1307
1307
  @t.add_player(1763, desc: "Leslie Garabedian")
1308
- @t.add_player(1764, desc: "Alexander Gillett", rating: 850, rating: 19)
1309
- @t.add_player(1765, desc: "Jan Glegolski", rating: 525, rating: 16)
1308
+ @t.add_player(1764, desc: "Alexander Gillett", rating: 850, games: 19)
1309
+ @t.add_player(1765, desc: "Jan Glegolski", rating: 525, games: 16)
1310
1310
  @t.add_player(1767, desc: "Mark Halley", rating: 1280, kfactor: 40)
1311
- @t.add_player(1768, desc: "Siobhan Halley", rating: 434, rating: 18)
1312
- @t.add_player(1769, desc: "Luke Hayden", rating: 781, rating: 6)
1313
- @t.add_player(1770, desc: "Colm Hehir", rating: 564, rating: 16)
1314
- @t.add_player(1771, desc: "Donal Hehir", rating: 424, rating: 6)
1311
+ @t.add_player(1768, desc: "Siobhan Halley", rating: 434, games: 18)
1312
+ @t.add_player(1769, desc: "Luke Hayden", rating: 781, games: 6)
1313
+ @t.add_player(1770, desc: "Colm Hehir", rating: 564, games: 16)
1314
+ @t.add_player(1771, desc: "Donal Hehir", rating: 424, games: 6)
1315
1315
  @t.add_player(1772, desc: "Andrew Ingram", rating: 859, kfactor: 32)
1316
1316
  @t.add_player(1773, desc: "Rory Jackson")
1317
1317
  @t.add_player(1774, desc: "Tom Kearney", rating: 924, kfactor: 40)
1318
- @t.add_player(1775, desc: "Jamie Kearns", rating: 753, rating: 11)
1318
+ @t.add_player(1775, desc: "Jamie Kearns", rating: 753, games: 11)
1319
1319
  @t.add_player(1777, desc: "Thomas Keating", rating: 864, kfactor: 40)
1320
1320
  @t.add_player(1778, desc: "Darragh Kennedy", rating: 1052, kfactor: 40)
1321
1321
  @t.add_player(1779, desc: "Stephen Kennedy", rating: 490, kfactor: 40)
1322
1322
  @t.add_player(1780, desc: "Jonathan Kiely", rating: 1117, kfactor: 24)
1323
1323
  @t.add_player(1781, desc: "Kevin Kilduff", rating: 1116, kfactor: 40)
1324
- @t.add_player(1782, desc: "Conor Kirby MacGuill", rating: 410, rating: 9)
1324
+ @t.add_player(1782, desc: "Conor Kirby MacGuill", rating: 410, games: 9)
1325
1325
  @t.add_player(1783, desc: "Wiktor Kwapinski")
1326
1326
  @t.add_player(1784, desc: "Andrew Kyne-Delaney", rating: 869, kfactor: 40)
1327
1327
  @t.add_player(1785, desc: "Samuel Lenihan", rating: 683, kfactor: 40)
1328
1328
  @t.add_player(1786, desc: "Haoang Li", rating: 667, kfactor: 40)
1329
- @t.add_player(1787, desc: "Stephen Li", rating: 880, rating: 17)
1329
+ @t.add_player(1787, desc: "Stephen Li", rating: 880, games: 17)
1330
1330
  @t.add_player(1788, desc: "Desmond Martin", rating: 1018, kfactor: 24)
1331
1331
  @t.add_player(1789, desc: "Clare McCarrick", rating: 805, kfactor: 40)
1332
1332
  @t.add_player(1790, desc: "Padraig McCullough", rating: 676, kfactor: 24)
@@ -1339,7 +1339,7 @@ module ICU
1339
1339
  @t.add_player(1797, desc: "Jacob Miller")
1340
1340
  @t.add_player(1799, desc: "Diarmuid Minnock", rating: 760, kfactor: 40)
1341
1341
  @t.add_player(1800, desc: "Michael Morgan", rating: 889, kfactor: 32)
1342
- @t.add_player(1801, desc: "Alex Mulligan", rating: 603, rating: 17)
1342
+ @t.add_player(1801, desc: "Alex Mulligan", rating: 603, games: 17)
1343
1343
  @t.add_player(1802, desc: "Scott Mulligan", rating: 1100, kfactor: 40)
1344
1344
  @t.add_player(1803, desc: "Jessica Mulqueen-Danaher", rating: 286, kfactor: 40)
1345
1345
  @t.add_player(1804, desc: "Christopher Murphy", rating: 990, kfactor: 40)
@@ -1348,10 +1348,10 @@ module ICU
1348
1348
  @t.add_player(1807, desc: "Dan O'Brien", rating: 789, kfactor: 40)
1349
1349
  @t.add_player(1808, desc: "Pat O'Brien", rating: 970, kfactor: 24)
1350
1350
  @t.add_player(1809, desc: "Michael Joseph O'Connell", rating: 1010, kfactor: 32)
1351
- @t.add_player(1810, desc: "John P. O'Connor", rating: 242, rating: 6)
1351
+ @t.add_player(1810, desc: "John P. O'Connor", rating: 242, games: 6)
1352
1352
  @t.add_player(1811, desc: "Ross O'Connor", rating: 812, kfactor: 40)
1353
1353
  @t.add_player(1812, desc: "Colm O'Muireagain", rating: 950, kfactor: 32)
1354
- @t.add_player(1813, desc: "Barry O'Reilly", rating: 736, rating: 6)
1354
+ @t.add_player(1813, desc: "Barry O'Reilly", rating: 736, games: 6)
1355
1355
  @t.add_player(1814, desc: "Jim O'Reilly", rating: 784, kfactor: 40)
1356
1356
  @t.add_player(1815, desc: "David Piercy", rating: 970, kfactor: 32)
1357
1357
  @t.add_player(1816, desc: "Agnieszka Pozniak", rating: 906, kfactor: 40)
@@ -1362,8 +1362,8 @@ module ICU
1362
1362
  @t.add_player(1821, desc: "Stephen Sheehan")
1363
1363
  @t.add_player(1822, desc: "Kevin Singpurwala", rating: 790, kfactor: 40)
1364
1364
  @t.add_player(1823, desc: "Kaj Skubiszak")
1365
- @t.add_player(1824, desc: "Jack Staed", rating: 133, rating: 10)
1366
- @t.add_player(1825, desc: "Devin Tarleton", rating: 852, rating: 11)
1365
+ @t.add_player(1824, desc: "Jack Staed", rating: 133, games: 10)
1366
+ @t.add_player(1825, desc: "Devin Tarleton", rating: 852, games: 11)
1367
1367
  @t.add_player(1826, desc: "M. Thangaramanujam", rating: 813, kfactor: 24)
1368
1368
  @t.add_player(1827, desc: "Haley Tomlinson")
1369
1369
  @t.add_player(1828, desc: "Peter Urwin", rating: 848, kfactor: 40)
@@ -1998,7 +1998,7 @@ module ICU
1998
1998
  @t.iterations2.should be_nil
1999
1999
  end
2000
2000
 
2001
- it "should produce inconsistent results with default settings" do
2001
+ it "should produce inconsistent results with original algorithm" do
2002
2002
  @t.rate!
2003
2003
 
2004
2004
  @p.new_rating.should == @p.performance
@@ -2019,8 +2019,8 @@ module ICU
2019
2019
  @t.iterations2.should == 1
2020
2020
  end
2021
2021
 
2022
- it "should produce inconsistent results even with more 2nd phase iterations" do
2023
- @t.rate!(max_iterations2: 30)
2022
+ it "should produce inconsistent results with version 1 algorithm" do
2023
+ @t.rate!(version: 1)
2024
2024
 
2025
2025
  @p.new_rating.should == @p.performance
2026
2026
 
@@ -2040,8 +2040,8 @@ module ICU
2040
2040
  @t.iterations2.should be > 1
2041
2041
  end
2042
2042
 
2043
- it "should produce consistent results only when new bonuses in phase 2 are disallowed" do
2044
- @t.rate!(max_iterations2: 30, phase_2_bonuses: false)
2043
+ it "should produce consistent results with version 2 algorithm" do
2044
+ @t.rate!(version: 2)
2045
2045
 
2046
2046
  @o1.bonus.should == 0 # no bonus this time because it comes from 2nd phase
2047
2047
  @o2.bonus.should == 0
@@ -2058,6 +2058,178 @@ module ICU
2058
2058
  @t.iterations1.should be > 1
2059
2059
  @t.iterations2.should be > 1
2060
2060
  end
2061
+
2062
+ it "should produce consistent results with version 3 algorithm" do
2063
+ @t.rate!(version: 3)
2064
+
2065
+ @o1.bonus.should == 0 # no bonus this time because it comes from 2nd phase
2066
+ @o2.bonus.should == 0
2067
+ @o3.bonus.should == 0
2068
+ @o4.bonus.should == 0
2069
+ @o5.bonus.should == 0
2070
+ @o6.bonus.should == 0
2071
+
2072
+ ratings = [@o1, @o2, @o3, @o4, @o5, @o6].map { |o| o.bonus == 0 ? o.rating : o.new_rating }
2073
+
2074
+ performance = ratings.inject(0.0){ |m,r| m = m + r } / 6.0 - 400.0 / 3.0
2075
+ performance.should be_within(0.5).of(@p.new_rating)
2076
+
2077
+ @t.iterations1.should be > 1
2078
+ @t.iterations2.should be > 1
2079
+ end
2080
+ end
2081
+
2082
+ context "#rate - Dierdre Turner in the Limerick U1400 2012" do
2083
+ before(:each) do
2084
+ @t = ICU::RatedTournament.new(desc: "Limerick U1400 2012")
2085
+
2086
+ # Add the players of most interest (Dierdre Turner and her opponents).
2087
+ @p = @t.add_player(6697, desc: "Dierdre Turner")
2088
+ @o1 = @t.add_player(6678, desc: "John P. Dunne", rating: 980, kfactor: 40)
2089
+ @o2 = @t.add_player(6694, desc: "Jordan O'Sullivan")
2090
+ @o3 = @t.add_player(6681, desc: "Ruairi Freeman", rating: 537, kfactor: 40)
2091
+ @o4 = @t.add_player(6676, desc: "Joe Cronin", rating: 682, kfactor: 32)
2092
+ @o5 = @t.add_player(6675, desc: "Jeffrey Alfred", rating: 1320, kfactor: 40)
2093
+ @o6 = @t.add_player(6687, desc: "Roisin MacNamee", rating: 460, games: 7)
2094
+
2095
+ # Add all the other players.
2096
+ @t.add_player(6679, desc: "Thomas Senior Dunne", rating: 876, kfactor: 32)
2097
+ @t.add_player(6682, desc: "John Hensey", rating: 1347, kfactor: 24)
2098
+ @t.add_player(6683, desc: "Noel Keating", rating: 622, kfactor: 32)
2099
+ @t.add_player(6684, desc: "Thomas Keating", rating: 886, kfactor: 40)
2100
+ @t.add_player(6686, desc: "Nora MacNamee", rating: 508, kfactor: 40)
2101
+ @t.add_player(6690, desc: "Robbie Meaney", rating: 1020, kfactor: 40)
2102
+ @t.add_player(6691, desc: "Stephen Meaney", rating: 979, kfactor: 40)
2103
+ @t.add_player(6692, desc: "Jessica Mulqueen-Danaher", rating: 435, kfactor: 40)
2104
+ @t.add_player(6693, desc: "Michael Joseph O'Connell", rating: 965, kfactor: 32)
2105
+ @t.add_player(6677, desc: "Adam Dean", rating: 652, games: 6)
2106
+ @t.add_player(6680, desc: "Geordan Freeman", rating: 344, games: 10)
2107
+ @t.add_player(6685, desc: "Eamon MacNamee")
2108
+ @t.add_player(6688, desc: "Pippa Madigan")
2109
+ @t.add_player(6689, desc: "John McNamara")
2110
+ @t.add_player(6695, desc: "Grigory Ramendik")
2111
+ @t.add_player(6696, desc: "Mark David Tonita")
2112
+ @t.add_player(6698, desc: "Eoghan Turner")
2113
+
2114
+ # Dierdre's results.
2115
+ @t.add_result(1, 6697, 6678, "L")
2116
+ @t.add_result(2, 6697, 6694, "W")
2117
+ @t.add_result(3, 6697, 6681, "W")
2118
+ @t.add_result(4, 6697, 6676, "L")
2119
+ @t.add_result(5, 6697, 6675, "L")
2120
+ @t.add_result(6, 6697, 6687, "W")
2121
+
2122
+ # Other results.
2123
+ @t.add_result(1, 6689, 6676, "L")
2124
+ @t.add_result(1, 6693, 6677, "L")
2125
+ @t.add_result(1, 6695, 6679, "L")
2126
+ @t.add_result(1, 6694, 6681, "L")
2127
+ @t.add_result(1, 6692, 6682, "L")
2128
+ @t.add_result(1, 6688, 6683, "L")
2129
+ @t.add_result(1, 6698, 6684, "D")
2130
+ @t.add_result(1, 6691, 6685, "W")
2131
+ @t.add_result(1, 6696, 6686, "L")
2132
+ @t.add_result(1, 6690, 6687, "W")
2133
+ @t.add_result(2, 6684, 6675, "D")
2134
+ @t.add_result(2, 6682, 6676, "W")
2135
+ @t.add_result(2, 6698, 6677, "L")
2136
+ @t.add_result(2, 6683, 6678, "L")
2137
+ @t.add_result(2, 6686, 6679, "L")
2138
+ @t.add_result(2, 6690, 6680, "W")
2139
+ @t.add_result(2, 6691, 6681, "W")
2140
+ @t.add_result(2, 6693, 6685, "W")
2141
+ @t.add_result(2, 6695, 6687, "L")
2142
+ @t.add_result(2, 6692, 6689, "W")
2143
+ @t.add_result(3, 6678, 6675, "W")
2144
+ @t.add_result(3, 6687, 6676, "L")
2145
+ @t.add_result(3, 6682, 6677, "W")
2146
+ @t.add_result(3, 6696, 6680, "D")
2147
+ @t.add_result(3, 6686, 6683, "L")
2148
+ @t.add_result(3, 6693, 6684, "D")
2149
+ @t.add_result(3, 6698, 6685, "W")
2150
+ @t.add_result(3, 6692, 6688, "W")
2151
+ @t.add_result(3, 6695, 6689, "L")
2152
+ @t.add_result(3, 6691, 6690, "W")
2153
+ @t.add_result(4, 6687, 6675, "L")
2154
+ @t.add_result(4, 6683, 6677, "W")
2155
+ @t.add_result(4, 6682, 6678, "D")
2156
+ @t.add_result(4, 6691, 6679, "W")
2157
+ @t.add_result(4, 6684, 6680, "W")
2158
+ @t.add_result(4, 6693, 6681, "L")
2159
+ @t.add_result(4, 6695, 6685, "W")
2160
+ @t.add_result(4, 6694, 6686, "L")
2161
+ @t.add_result(4, 6692, 6690, "L")
2162
+ @t.add_result(4, 6698, 6696, "W")
2163
+ @t.add_result(5, 6683, 6676, "W")
2164
+ @t.add_result(5, 6692, 6677, "L")
2165
+ @t.add_result(5, 6691, 6678, "W")
2166
+ @t.add_result(5, 6698, 6679, "D")
2167
+ @t.add_result(5, 6687, 6680, "W")
2168
+ @t.add_result(5, 6689, 6681, "L")
2169
+ @t.add_result(5, 6690, 6682, "L")
2170
+ @t.add_result(5, 6686, 6684, "L")
2171
+ @t.add_result(5, 6696, 6693, "L")
2172
+ @t.add_result(5, 6695, 6694, "D")
2173
+ @t.add_result(6, 6677, 6675, "D")
2174
+ @t.add_result(6, 6698, 6676, "W")
2175
+ @t.add_result(6, 6679, 6678, "L")
2176
+ @t.add_result(6, 6694, 6680, "L")
2177
+ @t.add_result(6, 6690, 6681, "W")
2178
+ @t.add_result(6, 6691, 6682, "L")
2179
+ @t.add_result(6, 6684, 6683, "L")
2180
+ @t.add_result(6, 6696, 6685, "W")
2181
+ @t.add_result(6, 6689, 6686, "L")
2182
+ @t.add_result(6, 6693, 6692, "W")
2183
+ end
2184
+
2185
+ it "should be setup properly" do
2186
+ @p.desc.should == "Dierdre Turner"
2187
+ @o1.desc.should == "John P. Dunne"
2188
+ @o2.desc.should == "Jordan O'Sullivan"
2189
+ @o3.desc.should == "Ruairi Freeman"
2190
+ @o4.desc.should == "Joe Cronin"
2191
+ @o5.desc.should == "Jeffrey Alfred"
2192
+ @o6.desc.should == "Roisin MacNamee"
2193
+
2194
+ @p.type.should == :unrated
2195
+ @o1.type.should == :rated
2196
+ @o2.type.should == :unrated
2197
+ @o3.type.should == :rated
2198
+ @o4.type.should == :rated
2199
+ @o5.type.should == :rated
2200
+ @o6.type.should == :provisional
2201
+
2202
+ @o1.rating.should == 980
2203
+ @o2.rating.should be_nil
2204
+ @o3.rating.should == 537
2205
+ @o4.rating.should == 682
2206
+ @o5.rating.should == 1320
2207
+ @o6.rating.should == 460
2208
+
2209
+ @t.iterations1.should be_nil
2210
+ @t.iterations2.should be_nil
2211
+ end
2212
+
2213
+ it "should produce consistent results with version 2 algorithm" do
2214
+ @t.rate!(version: 2)
2215
+
2216
+ @p.new_rating.should == @p.performance
2217
+
2218
+ @o1.bonus.should == 23
2219
+ @o2.bonus.should == 0
2220
+ @o3.bonus.should == 0
2221
+ @o4.bonus.should == 0
2222
+ @o5.bonus.should == 0
2223
+ @o6.bonus.should == 0
2224
+
2225
+ ratings = [@o1, @o2, @o3, @o4, @o5, @o6].map { |o| o.bonus > 0 || o.type != :rated ? o.new_rating : o.rating }
2226
+
2227
+ performance = ratings.inject(0.0){ |m,r| m = m + r } / 6.0
2228
+ performance.should be_within(0.5).of(@p.new_rating)
2229
+
2230
+ @t.iterations1.should be > 1
2231
+ @t.iterations2.should be > 1
2232
+ end
2061
2233
  end
2062
2234
  end
2063
2235
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icu_ratings
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-25 00:00:00.000000000 Z
12
+ date: 2012-12-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -111,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
111
  version: '0'
112
112
  segments:
113
113
  - 0
114
- hash: 4520836644444600714
114
+ hash: -4449600080095585228
115
115
  required_rubygems_version: !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
@@ -120,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  version: '0'
121
121
  segments:
122
122
  - 0
123
- hash: 4520836644444600714
123
+ hash: -4449600080095585228
124
124
  requirements: []
125
125
  rubyforge_project: icu_ratings
126
126
  rubygems_version: 1.8.23