icu_ratings 0.2.7 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/lib/icu_ratings/player.rb +37 -0
- data/lib/icu_ratings/tournament.rb +1 -0
- data/lib/icu_ratings/util.rb +18 -2
- data/spec/player_spec.rb +24 -0
- data/spec/tournament_spec.rb +26 -0
- data/spec/util_spec.rb +15 -0
- metadata +1 -1
data/VERSION.yml
CHANGED
data/lib/icu_ratings/player.rb
CHANGED
@@ -91,6 +91,29 @@ all these parameters can be specified using strings, even when padded with white
|
|
91
91
|
p.rating # 2000.5 (Float)
|
92
92
|
p.kfactor # 20.5 (Float)
|
93
93
|
|
94
|
+
== Calculation of K-factors
|
95
|
+
|
96
|
+
Rather than pre-calculating the value to set for a rated player's K-factor, the RatedPlayer class can itself
|
97
|
+
calculate K-factors if the releavant information is supplied. ICU K-factors depend not only on a player's
|
98
|
+
rating, but also on their age and experience. Therefore, supply a hash, instead of a numerical value, for the
|
99
|
+
_kfactor_ attribute with values set for date-of-birth (_dob_) and date joined (_joined_):
|
100
|
+
|
101
|
+
t = Tournament.new(:start => "2010-07-10")
|
102
|
+
p = t.add_player(1, :rating => 2225, :kfactor => { :dob => "1993-12-20", :joined => "2004-11-28" })
|
103
|
+
p.kfactor # 16.0
|
104
|
+
|
105
|
+
For this to work the tournament's optional start date must be set to enable the player's age and
|
106
|
+
experience at the start of the tournament be to calculated. The ICU K-factor rules are:
|
107
|
+
|
108
|
+
* 16 for players rated 2100 and over, otherwise
|
109
|
+
* 40 for players aged under 21, otherwise
|
110
|
+
* 32 for players who have been members for less than 8 years, otherwise
|
111
|
+
* 24
|
112
|
+
|
113
|
+
If you want to calculate K-factors accrding to some other, non-ICU scheme, then override the
|
114
|
+
static method _kfactor_ of the RatedPlayer class and pass in a hash of whatever key-value pairs
|
115
|
+
it requires as the value associated with _kfactor_ key in the _add_player_ method.
|
116
|
+
|
94
117
|
== Description Parameter
|
95
118
|
|
96
119
|
There is one other optional parameter, _desc_ (short for "description"). It has no effect on player
|
@@ -166,6 +189,20 @@ method.
|
|
166
189
|
@type
|
167
190
|
end
|
168
191
|
|
192
|
+
# Calculate a K-factor according to ICU rules.
|
193
|
+
def self.kfactor(args)
|
194
|
+
case
|
195
|
+
when args[:rating] >= 2100 then
|
196
|
+
16
|
197
|
+
when ICU::Util.age(args[:dob], args[:start]) < 21 then
|
198
|
+
40
|
199
|
+
when ICU::Util.age(args[:joined], args[:start]) < 8 then
|
200
|
+
32
|
201
|
+
else
|
202
|
+
24
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
169
206
|
def add_result(result) # :nodoc:
|
170
207
|
raise "invalid result (#{result.class})" unless result.is_a? ICU::RatedResult
|
171
208
|
raise "players cannot score results against themselves" if self == result.opponent
|
@@ -70,6 +70,7 @@ to be caught and handled in some suitable place in your code.
|
|
70
70
|
# See ICU::RatedPlayer for details.
|
71
71
|
def add_player(num, args={})
|
72
72
|
raise "player with number #{num} already exists" if @player[num]
|
73
|
+
args[:kfactor] = ICU::RatedPlayer.kfactor(args[:kfactor].merge({ :start => start, :rating => args[:rating] })) if args[:kfactor].is_a?(Hash)
|
73
74
|
@player[num] = ICU::RatedPlayer.new(num, args)
|
74
75
|
end
|
75
76
|
|
data/lib/icu_ratings/util.rb
CHANGED
@@ -7,7 +7,7 @@ module ICU
|
|
7
7
|
|
8
8
|
== Parsing dates
|
9
9
|
|
10
|
-
|
10
|
+
The method _parsedate!_ parses strings into date objects, interpreting nn/nn/nnnn as dd/mm/yyyy. It raises an exception on error.
|
11
11
|
|
12
12
|
Util.parsedate!('1955-11-09') # => Date (1955-11-09)
|
13
13
|
Util.parsedate!('02/03/2009') # => Date (2009-03-02)
|
@@ -19,9 +19,19 @@ Note that the parse method of the Date class behaves differently in Ruby 1.8.7 a
|
|
19
19
|
In 1.8.7 it assumes American dates and will raise ArgumentError on "30/03/2003".
|
20
20
|
In 1.9.1 it assumes European dates and will raise ArgumentError on "03/30/2003".
|
21
21
|
|
22
|
+
== Diffing dates
|
23
|
+
|
24
|
+
The method _age_ returns the difference of two dates:
|
25
|
+
|
26
|
+
Util.age(born, date) # age in years at the given date (Float)
|
27
|
+
Util.age(born) # age in years now (today)
|
28
|
+
|
29
|
+
Internally it uses _parsedate!_ so can throw a exception if an invalid date is supplied.
|
30
|
+
|
22
31
|
=end
|
23
32
|
|
24
33
|
def self.parsedate!(date)
|
34
|
+
return date.clone if date.is_a?(Date)
|
25
35
|
string = date.to_s.strip
|
26
36
|
raise "invalid date (#{date})" unless string.match(/[1-9]/)
|
27
37
|
string = [$3].concat($2.to_i > 12 ? [$1, $2] : [$2, $1]).join('-') if string.match(/^(\d{1,2}).(\d{1,2}).(\d{4})$/)
|
@@ -31,5 +41,11 @@ In 1.9.1 it assumes European dates and will raise ArgumentError on "03/30/2003".
|
|
31
41
|
raise "invalid date (#{date})"
|
32
42
|
end
|
33
43
|
end
|
44
|
+
|
45
|
+
def self.age(born, date=Date.today)
|
46
|
+
born = parsedate!(born)
|
47
|
+
date = parsedate!(date)
|
48
|
+
date.year - born.year + (date.yday - born.yday) / 366.0
|
49
|
+
end
|
34
50
|
end
|
35
|
-
end
|
51
|
+
end
|
data/spec/player_spec.rb
CHANGED
@@ -136,6 +136,30 @@ module ICU
|
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
|
+
context "calculation of K-factor" do
|
140
|
+
it "should return 16 for players 2100 and above" do
|
141
|
+
ICU::RatedPlayer.kfactor(:rating => 2101, :start => '2010-07-10', :dob => '1955-11-09', :joined => '1974-01-01').should == 16
|
142
|
+
ICU::RatedPlayer.kfactor(:rating => 2100, :start => '2010-07-10', :dob => '1955-11-09', :joined => '1974-01-01').should == 16
|
143
|
+
ICU::RatedPlayer.kfactor(:rating => 2099, :start => '2010-07-10', :dob => '1955-11-09', :joined => '1974-01-01').should_not == 16
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should otherwise return 40 for players aged under 21 at the start of the tournament" do
|
147
|
+
ICU::RatedPlayer.kfactor(:rating => 2000, :start => '2010-07-10', :dob => '1989-07-11', :joined => '1999-01-01').should == 40
|
148
|
+
ICU::RatedPlayer.kfactor(:rating => 2000, :start => '2010-07-10', :dob => '1989-07-10', :joined => '1999-01-01').should_not == 40
|
149
|
+
ICU::RatedPlayer.kfactor(:rating => 2000, :start => '2010-07-10', :dob => '1989-07-09', :joined => '1999-01-01').should_not == 40
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should otherwise return 32 for players with under 8 years experience at the start of the tournament" do
|
153
|
+
ICU::RatedPlayer.kfactor(:rating => 2000, :start => '2010-07-10', :dob => '1989-01-01', :joined => '2002-07-11').should == 32
|
154
|
+
ICU::RatedPlayer.kfactor(:rating => 2000, :start => '2010-07-10', :dob => '1989-01-01', :joined => '2002-07-10').should_not == 32
|
155
|
+
ICU::RatedPlayer.kfactor(:rating => 2000, :start => '2010-07-10', :dob => '1989-01-01', :joined => '2002-07-09').should_not == 32
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should otherwise return 24" do
|
159
|
+
ICU::RatedPlayer.kfactor(:rating => 2000, :start => '2010-07-10', :dob => '1989-01-01', :joined => '2002-01-01').should == 24
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
139
163
|
context "Rdoc examples" do
|
140
164
|
before(:each) do
|
141
165
|
@t = ICU::RatedTournament.new
|
data/spec/tournament_spec.rb
CHANGED
@@ -27,6 +27,32 @@ module ICU
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
context "#add_player and calculation of K-factor" do
|
31
|
+
before(:each) do
|
32
|
+
@t = ICU::RatedTournament.new(:start => "2010-07-10")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set a K-factor of 16 for players with rating >= 2100" do
|
36
|
+
@p = @t.add_player(1, :rating => 2200, :kfactor => { :dob => "1955-11-09", :joined => "1976-09-01" })
|
37
|
+
@p.kfactor.should == 16
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should set a K-factor of 40 for players with rating < 2100 and age < 21" do
|
41
|
+
@p = @t.add_player(1, :rating => 2000, :kfactor => { :dob => "1995-01-10", :joined => "2009-09-01" })
|
42
|
+
@p.kfactor.should == 40
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should set a K-factor of 32 for players with rating < 2100, age >= 21 and experience < 8" do
|
46
|
+
@p = @t.add_player(1, :rating => 2000, :kfactor => { :dob => "1975-01-10", :joined => "2005-09-01" })
|
47
|
+
@p.kfactor.should == 32
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should set a K-factor of 24 for players with rating < 2100, age >= 21 and experience >= 8" do
|
51
|
+
@p = @t.add_player(1, :rating => 2000, :kfactor => { :dob => "1975-01-10", :joined => "1995-09-01" })
|
52
|
+
@p.kfactor.should == 24
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
30
56
|
context "#players and #player" do
|
31
57
|
before(:each) do
|
32
58
|
@t = ICU::RatedTournament.new
|
data/spec/util_spec.rb
CHANGED
@@ -45,5 +45,20 @@ module ICU
|
|
45
45
|
Util.parsedate!(Date.parse('2013-07-01')).should == Date.parse('2013-07-01')
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
49
|
+
context "#age" do
|
50
|
+
it "should return age in years" do
|
51
|
+
Util.age('2001-01-01', '2001-01-01').should == 0.0
|
52
|
+
Util.age('2001-01-01', '2002-01-01').should == 1.0
|
53
|
+
Util.age('2001-01-01', '2001-01-02').should be_close(1/365.0, 0.01)
|
54
|
+
Util.age('2001-01-01', '2001-02-01').should be_close(1/12.0, 0.01)
|
55
|
+
Util.age('1955-11-09', '2010-01-17').should be_close(54.2, 0.01)
|
56
|
+
Util.age('2001-01-01', '2000-01-01').should == -1.0
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should default second date to today" do
|
60
|
+
Util.age(Date.today).should == 0.0
|
61
|
+
end
|
62
|
+
end
|
48
63
|
end
|
49
64
|
end
|