EloSystem::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 4
nc 1
nop 3
1
<?php
2
3
namespace Alcalyn\Elo;
4
5
use Alcalyn\Elo\Exception\EloCoefficientException;
6
7
class EloSystem
8
{
9
    /**
10
     * F Factor. Determines how quickly elo scores change.
11
     * Default is 16
12
     * 
13
     * @var integer
14
     */
15
    private $kFactor;
16
    
17
    /**
18
     * Defines the range of elo.
19
     * Default is 400
20
     * 
21
     * @var integer 
22
     */
23
    private $interval;
24
    
25
    /**
26
     * Defines approximatively the power between intervals.
27
     * Default is 10
28
     * 
29
     * @var integer
30
     */
31
    private $pow;
32
    
33
    /**
34
     * Constructor
35
     * 
36
     * @param integer $kFactor
37
     * @param integer $interval
38
     * @param integer $pow
39
     */
40
    public function __construct($kFactor = 16, $interval = 400, $pow = 10)
41
    {
42
        $this->kFactor = $kFactor;
43
        $this->interval = $interval;
44
        $this->pow = $pow;
45
    }
46
    
47
    /**
48
     * Calculate new elo scores
49
     * 
50
     * @param double $elo0 elo score of player 0
51
     * @param double $elo1 elo score of player 1
52
     * @param double $win win coef for player 0. Set 1 to say that player 0 won
53
     * @param double $reliability0 elo reliability for player 0
54
     * @param double $reliability1 elo reliability for player 1
55
     * @param integer $kFactor0 override k factor for player 0
56
     * @param integer $kFactor1 override k factor for player 1
57
     * 
58
     * @return double[] with new elo score at indexes 0 and 1 for player 0 and 1
59
     */
60
    public function calculate($elo0, $elo1, $win, $reliability0 = 1.0, $reliability1 = 1.0, $kFactor0 = null, $kFactor1 = null)
61
    {
62
        self::checkCoef($reliability0, 'reliability0');
63
        self::checkCoef($reliability1, 'reliability1');
64
        self::checkCoef($win, 'win');
65
        
66
        $kFactor0 = (null === $kFactor0) ? $this->kFactor : $kFactor0;
67
        $kFactor1 = (null === $kFactor1) ? $this->kFactor : $kFactor1;
68
        
69
        /**
70
         * Calculate probability 0 have to beat 1
71
         */
72
        $proba = $this->proba($elo0, $elo1);
73
        
74
        /**
75
         * Calculate elo changement
76
         */
77
        $eloUpdate0 = $win - $proba;
78
        $eloUpdate1 = -$eloUpdate0;
79
        
80
        /**
81
         * Calculate local reliability to avoid 0 and 0 reliability for new players
82
         * (if two new players have 0 and 0.1 reliability, they are rectified to 0.9 and 1)
83
         */
84
        self::rectifyReliabilityCoefs($reliability0, $reliability1);
85
        
86
        /**
87
         * Apply coefs K-factor and reliability of each other
88
         */
89
        $eloUpdate0 *= $kFactor0 * $reliability1 ;
90
        $eloUpdate1 *= $kFactor1 * $reliability0 ;
91
        
92
        return array($elo0 + $eloUpdate0, $elo1 + $eloUpdate1);
93
    }
94
    
95
    /**
96
     * Player 0 beat player 1
97
     * 
98
     * @param double $elo0 elo score of player 0
99
     * @param double $elo1 elo score of player 1
100
     * @param double $reliability0 elo reliability for player 0
101
     * @param double $reliability1 elo reliability for player 1
102
     * 
103
     * @return double[] with new elo score at indexes 0 and 1 for player 0 and 1
104
     */
105
    public function win($elo0, $elo1, $reliability0 = 1.0, $reliability1 = 1.0, $kFactor0 = null, $kFactor1 = null)
106
    {
107
        return $this->calculate($elo0, $elo1, 1, $reliability0, $reliability1, $kFactor0, $kFactor1);
108
    }
109
    
110
    /**
111
     * Player 0 lose against player 1
112
     * 
113
     * @param double $elo0 elo score of player 0
114
     * @param double $elo1 elo score of player 1
115
     * @param double $reliability0 elo reliability for player 0
116
     * @param double $reliability1 elo reliability for player 1
117
     * 
118
     * @return double[] with new elo score at indexes 0 and 1 for player 0 and 1
119
     */
120
    public function lose($elo0, $elo1, $reliability0 = 1.0, $reliability1 = 1.0, $kFactor0 = null, $kFactor1 = null)
121
    {
122
        return $this->calculate($elo0, $elo1, 0, $reliability0, $reliability1, $kFactor0, $kFactor1);
123
    }
124
    
125
    /**
126
     * Player 0 and player 1 have made a draw game
127
     * 
128
     * @param double $elo0 elo score of player 0
129
     * @param double $elo1 elo score of player 1
130
     * @param double $reliability0 elo reliability for player 0
131
     * @param double $reliability1 elo reliability for player 1
132
     * 
133
     * @return double[] with new elo score at indexes 0 and 1 for player 0 and 1
134
     */
135
    public function draw($elo0, $elo1, $reliability0 = 1.0, $reliability1 = 1.0, $kFactor0 = null, $kFactor1 = null)
136
    {
137
        return $this->calculate($elo0, $elo1, 0.5, $reliability0, $reliability1, $kFactor0, $kFactor1);
138
    }
139
    
140
    /**
141
     * Return probability rate that $elo0 beat $elo1
142
     * 
143
     * @param double $elo0
144
     * @param double $elo1
145
     * 
146
     * @return double
147
     */
148
    public function proba($elo0, $elo1)
149
    {
150
        return 1 / (1 + pow($this->pow, ($elo1 - $elo0) / $this->interval)) ;
151
    }
152
    
153
    /**
154
     * Increase coefficients the same value so one of them reaches 1
155
     * 
156
     * @param double $coef0
157
     * @param double $coef1
158
     */
159
    private static function rectifyReliabilityCoefs(&$coef0, &$coef1)
160
    {
161
        $reliabilityRectification = 1 - max($coef0, $coef1);
162
        
163
        $coef0 += $reliabilityRectification;
164
        $coef1 += $reliabilityRectification;
165
    }
166
    
167
    /**
168
     * Check if $coef is in range [0;1]
169
     * 
170
     * @param double $coef
171
     * @param string $variableName
172
     */
173
    private static function checkCoef($coef, $variableName)
174
    {
175
        if (($coef < 0) || ($coef > 1)) {
176
            throw new EloCoefficientException($coef, $variableName);
177
        }
178
    }
179
}
180