Initial commit
[games-ratings-logisticelo.git] / lib / Games / Ratings / LogisticElo.pm
1 package Games::Ratings::LogisticElo;
2
3 use 5.014000;
4 use strict;
5 use warnings;
6 use parent qw/Exporter Games::Ratings/;
7
8 our @EXPORT_OK = qw/multi_elo/;
9 our @EXPORT = qw//;
10 our $VERSION = '0.001';
11
12 use List::Util qw/sum/;
13
14 sub get_rating_change {
15 my ($self) = @_;
16
17 my $own_rating = $self->get_rating;
18 my $K = $self->get_coefficient;
19
20 my $expected = sum map {
21 my $exp = ($_->{opponent_rating} - $own_rating) / 400;
22 1 / (1 + 10 ** $exp)
23 } $self->get_all_games;
24
25 my $actual = sum map {
26 Games::Ratings::_get_numerical_result($_->{result})
27 } $self->get_all_games;
28
29 $K * ($actual - $expected)
30 }
31
32 sub get_new_rating {
33 my ($self) = @_;
34 $self->get_rating + $self->get_rating_change
35 }
36
37 sub multi_elo {
38 my @args = @_;
39 my $K = ref $args[0] ? 15 : shift @args;
40
41 my @newratings = map {
42 my $player = __PACKAGE__->new;
43 $player->set_rating($_->[0]);
44 $player->set_coefficient($K);
45 for my $opponent (@args) {
46 $player->add_game({
47 opponent_rating => $opponent->[0],
48 result =>
49 $_->[1] > $opponent->[1] ? 'win' :
50 $_->[1] < $opponent->[1] ? 'loss' : 'draw'
51 })
52 }
53 $player->get_new_rating
54 } @args;
55
56 wantarray ? @newratings : \@newratings
57 }
58
59 1;
60 __END__
61
62 =encoding utf-8
63
64 =head1 NAME
65
66 Games::Ratings::LogisticElo - calculate changes to logistic curve Elo ratings
67
68 =head1 SYNOPSIS
69
70 use Games::Ratings::LogisticElo;
71 my $player = Games::Ratings::LogisticElo->new;
72 $player->set_rating(2240);
73 $player->set_coefficient(15);
74 $player->add_game({
75 opponent_rating => 2114,
76 result => 'win', ## or 'draw' or 'loss'
77 });
78 say 'Rating change: ' . $player->get_rating_change;
79 say 'New rating: ' . $player->get_new_rating;
80
81 use Games::Ratings::LogisticElo qw/multi_elo/;
82 my @results = [2240, 3], [2114, 2], [2300, 1];
83 my @new_ratings = multi_elo 15, @results;
84 say 'Rating changes for this comp: ', join ', ',
85 map { $new_ratings[$_] - $results[$_]->[0] } 0 .. $#results;
86
87 =head1 DESCRIPTION
88
89 This module provides methods to calculate Elo rating changes. Unlike
90 L<Games::Ratings::Chess::FIDE>, this Elo implementation uses the
91 logistic distribution instead of the standard distribution.
92
93 This module can be used both for a single player who played multiple
94 rated games, and for a single competition with an arbitrary number of
95 players.
96
97 =head1 FUNCTIONS
98
99 Games::Ratings::LogisticElo inherits from L<Games::Ratings>, see that
100 module's documentation for information about the inherited methods.
101
102 Nothing is exported by default, the function B<multi_elo> can be
103 exported on request.
104
105 =over
106
107 =item B<$self>->I<get_rating_change>
108
109 Computes and returns how much a player's rating changes after the
110 games added.
111
112 =item B<$self>->I<get_new_rating>
113
114 Adds the result of I<get_rating_change> to the old rating of the
115 player and returns this.
116
117 =item B<multi_elo> [$coefficient], @results
118
119 Computes the ratings after a competition with an arbitrary number of
120 players.
121
122 The first argument is the coefficient. It is optional, with the
123 default coefficient being 15. The next arguments are the results of
124 the players. Each result is a 2-element arrayref, the first element
125 being the Elo rating of the player, and the second element being the
126 score that player obtained. The scores are only used to compare
127 players, their absolute values are irrelevant.
128
129 The return value is a list (in list context) or arrayref (in scalar
130 context) of ratings of all players after the competition, in the same
131 order as the arguments.
132
133 This function computes the ratings by considering that each player
134 played a game with every other player, with the winner of every game
135 being the player who got the highest score.
136
137 =back
138
139
140 =head1 SEE ALSO
141
142 L<Games::Ratings::Chess::FIDE>, L<Games::Ratings>
143
144 L<https://en.wikipedia.org/wiki/Elo_rating>
145
146 =head1 AUTHOR
147
148 Marius Gavrilescu <marius@ieval.ro>
149
150 =head1 COPYRIGHT AND LICENSE
151
152 Copyright (C) 2016 by Marius Gavrilescu
153
154 This library is free software; you can redistribute it and/or modify
155 it under the same terms as Perl itself, either Perl version 5.22.2 or,
156 at your option, any later version of Perl 5 you may have available.
157
158
159 =cut
This page took 0.02528 seconds and 4 git commands to generate.