File Coverage

blib/lib/Games/Ratings/Go/EGF.pm
Criterion Covered Total %
statement 66 90 73.3
branch 22 44 50.0
condition n/a
subroutine 13 14 92.8
pod 3 3 100.0
total 104 151 68.8


line stmt bran cond sub pod time code
1             package Games::Ratings::Go::EGF;
2              
3             ## TODO: check arguments for subroutines (use Data::Checker)?
4             ## TODO: Error handling
5             ## * croak()
6             ## * perldoc anpassen
7             ## TODO: $self->set_rating() checken: >= 100
8              
9 1     1   674 use strict;
  1         2  
  1         29  
10 1     1   4 use warnings;
  1         2  
  1         22  
11 1     1   5 use Carp;
  1         1  
  1         89  
12              
13 1     1   11 use 5.6.1; # 'our' was introduced in perl 5.6
  1         3  
  1         41  
14 1     1   898 use version; our $VERSION = qv('0.0.5');
  1         2082  
  1         5  
15              
16             ## look in Games::Ratings for methods not provide by this package
17 1     1   75 use base qw ( Games::Ratings );
  1         1  
  1         572  
18              
19             ## epsilon (inflation factor)
20             our $e = 0.014;
21              
22             ## calculate rating change
23             sub get_rating_change {
24 7     7 1 19 my ($self) = @_;
25              
26             ## get own rating
27 7         16 my $own_rating = $self->get_rating();
28              
29 7         8 my $rating_change_total;
30             ## calculate rating change for each game separately
31 7         16 foreach my $game_ref ( $self->get_all_games() ) {
32             ## add rating change for single game to total rating change
33 7         25 $rating_change_total += _calc_rating_change_for_single_game(
34             $own_rating,
35             $game_ref->{opponent_rating},
36             $game_ref->{result},
37             $game_ref->{handicap},
38             );
39             }
40              
41             ## return total rating change
42 7         32 return $rating_change_total;
43             }
44              
45             ## calculate new rating
46             sub get_new_rating {
47 6     6 1 28 my ($self) = @_;
48              
49             ## $R_o -- old rating
50 6         13 my $R_o = $self->get_rating();
51              
52             ## $R_n -- new rating (rounded)
53 6         12 my $R_n = sprintf( "%.f", $R_o + $self->get_rating_change() );
54              
55             ## return new rating
56 6         15 return $R_n;
57             }
58              
59             ## calculate expected points
60             sub get_points_expected {
61 0     0 1 0 my ($self) = @_;
62              
63             ## $W_e -- expected points
64 0         0 my $W_e;
65              
66             ## get value for $A_rating
67 0         0 my $A_rating = $self->get_rating();
68              
69             ## sum up expected points for all games
70 0         0 foreach my $game_ref ( $self->get_all_games() ) {
71             ## get values for $B_rating, $A_handicap
72 0         0 my $B_rating = $game_ref->{opponent_rating};
73 0         0 my $A_handicap = $game_ref->{handicap};
74              
75             ## check whether handicap is provided -- otherwise set to zero
76 0 0       0 if (! defined $A_handicap) {
77 0         0 $A_handicap = 0;
78             }
79              
80             ## sum up individual scoring probabilities
81 0         0 $W_e += _get_scoring_probability_for_single_game(
82             $A_rating,
83             $B_rating,
84             $A_handicap,
85             );
86              
87             }
88              
89             ## return expected points
90 0         0 return $W_e;
91             }
92              
93             ########################
94             ## internal functions ##
95             ########################
96              
97             ## calculate rating change for single game
98             sub _calc_rating_change_for_single_game {
99 7     7   13 my ($A_rating, $B_rating, $result, $A_handicap) = @_;
100              
101             ## check whether handicap is provided -- otherwise set to zero
102 7 100       17 if (! defined $A_handicap) {
103 5         7 $A_handicap = 0;
104             }
105            
106             ## get numerical result ( win=>1 draw=>0.5 loss=>0 )
107 7         17 my $numerical_result = Games::Ratings::_get_numerical_result($result);
108              
109             ## calculate parameter 'con' according to $A_rating
110 7         13 my $A_con = _get_con($A_rating);
111              
112             ## get scoring probability for player A
113 7         15 my $A_exp = _get_scoring_probability_for_single_game(
114             $A_rating,
115             $B_rating,
116             $A_handicap,
117             );
118              
119             ## compute rating changes for player A
120 7         17 my $A_rating_change = $A_con * ($numerical_result-$A_exp);
121            
122             ## return rating changes for player A
123 7         20 return ($A_rating_change);
124             }
125              
126             ## calculate scoring probability for a single game
127             sub _get_scoring_probability_for_single_game {
128 7     7   9 my ($A_rating,$B_rating,$A_handicap) = @_;
129              
130             ## scoring probability for player A
131 7         6 my $A_exp;
132              
133             ## scoring probability for weaker player is computed first
134 7 100       12 if ($A_rating > $B_rating) {
135             ## determine rating difference for calculation of scoring probability
136 2         4 my $rating_difference = _get_rating_difference(
137             $B_rating,
138             $A_rating,
139             -$A_handicap,
140             );
141             ## calculate parameter a
142 2         5 my $a = _get_a($B_rating, -$A_handicap);
143              
144             ## get scoring probability for player A (1 - e - Se(B))
145 2         6 $A_exp = 1 - $e - 1 / ( 1 + exp($rating_difference/$a) );
146             }
147             else {
148             ## determine rating difference for calculation of scoring probability
149 5         10 my $rating_difference = _get_rating_difference(
150             $A_rating,
151             $B_rating,
152             $A_handicap,
153             );
154             ## calculate parameter a
155 5         10 my $a = _get_a($A_rating, $A_handicap);
156              
157             ## get scoring probability for player A
158 5         25 $A_exp = 1 / ( 1 + exp($rating_difference/$a) );
159             }
160              
161             ## return scoring probability for weaker player
162 7         12 return ($A_exp);
163             }
164              
165             ## calculate rating difference which is used to calc the scoring probability
166             sub _get_rating_difference {
167 7     7   11 my ($A, $B, $A_handicap) = @_;
168              
169             ## compute real rating difference
170 7         8 my $rating_difference = ( $B-$A );
171              
172             ## rating difference is adjusted when handicaps are given
173 7 100       12 if ($A_handicap > 0) {
174 2         4 $rating_difference = $rating_difference
175             - 100 * ($A_handicap - 0.5);
176             }
177 7 50       14 if ($A_handicap < 0) {
178 0         0 $rating_difference = $rating_difference
179             + 100 * (-$A_handicap - 0.5);
180             }
181              
182             ## return rating difference used for rating calculations
183 7         9 return $rating_difference;
184             }
185              
186             ## calculate paramater 'a'
187             sub _get_a {
188 7     7   8 my ($player_rating,$player_handicap) = @_;
189              
190             ## $player_rating is adjusted for calculation of $a if handicap exists
191 7 100       13 if ($player_handicap != 0) {
192 2         4 $player_rating = $player_rating + 100*( $player_handicap-0.5 );
193             }
194              
195             ## compute parameter 'a' -- some values are given, rest interpolated
196 7         7 my $a;
197 7 50       15 if ($player_rating > 2700) {
    50          
198 0         0 $a = 70;
199             }
200             ## adjusted $player_rating could fall below 100 (with given handicap)
201             elsif ($player_rating < 100) {
202 0         0 $a = 200;
203             }
204             else {
205 7         12 $a = 200 - ( 200-70 ) * ($player_rating-100)/(2700-100);
206             }
207              
208             ## return parameter 'a'
209 7         11 return $a;
210             }
211              
212             ## calculate paramater 'con'
213             sub _get_con {
214 7     7   6 my ($player_rating) = @_;
215              
216             ## compute parameter 'con' -- some values are given, rest interpolated
217 7         8 my $con;
218 7 50       39 if ($player_rating == 100) {
    50          
    50          
    100          
    50          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
219 0         0 $con = 116;
220             }
221             elsif ($player_rating < 200) {
222 0         0 $con = 116 - ( 116-110 )*( $player_rating-100 )/(200-100);
223             }
224             elsif ($player_rating == 200) {
225 0         0 $con = 110;
226             }
227             elsif ($player_rating < 1300) {
228 3         7 $con = 110 - ( 110-55 )*( $player_rating-200 )/(1300-200);
229             }
230             elsif ($player_rating == 1300) {
231 0         0 $con = 55;
232             }
233             elsif ($player_rating < 2000) {
234 1         3 $con = 55 - ( 55-27 )*( $player_rating-1300 )/(2000-1300);
235             }
236             elsif ($player_rating == 2000) {
237 0         0 $con = 27;
238             }
239             elsif ($player_rating < 2400) {
240 0         0 $con = 27 - ( 27-15 )*( $player_rating-2000 )/(2400-2000);
241             }
242             elsif ($player_rating == 2400) {
243 3         4 $con = 15;
244             }
245             elsif ($player_rating < 2600) {
246 0         0 $con = 15 - ( 15-11 )*( $player_rating-2400 )/(2600-2400);
247             }
248             elsif ($player_rating == 2600) {
249 0         0 $con = 11;
250             }
251             elsif ($player_rating < 2700) {
252 0         0 $con = 11 - ( 11-10 )*( $player_rating-2600 )/100;
253             }
254             elsif ($player_rating == 2700) {
255 0         0 $con = 10;
256             }
257             elsif ($player_rating > 2700) {
258 0         0 $con = 10;
259             }
260              
261             ## return parameter 'con'
262 7         9 return $con;
263             }
264              
265             1; # Magic true value required at end of module
266             __END__