public ScorePlayer Calculate(ScorePlayer player, IEnumerable <Tuple <ScorePlayer, double> > opponents, double factor = 1.0) { // Step 3 double v = 0.0; foreach (var opponent in opponents) { var e = this.E(player.RatingScaled, opponent.Item1.RatingScaled, opponent.Item1.RdScaled); v += Math.Pow(this.G(opponent.Item1.RdScaled), 2) * e * (1 - e); } v = Math.Pow(v, -1.0); // Step 4 double delta = 0.0; foreach (var opponent in opponents) { delta += this.G(opponent.Item1.RdScaled) * (opponent.Item2 - this.E(player.RatingScaled, opponent.Item1.RatingScaled, opponent.Item1.RdScaled)); } delta *= v; // Step 5 const double epsilon = 0.000001; double A, a, B; A = a = Math.Log(Math.Pow(player.Vol, 2)); var delta2 = delta * delta; var rd2 = player.RdScaled * player.RdScaled; if (delta2 > rd2 + v) { B = Math.Log(delta2 - rd2 - v); } else { int k = 0; while (this.F(delta, a, player.RdScaled, v, a - k * Config.Tau) < 0) { ++k; } B = a - k * Config.Tau; } // Step 5.3 double fa = this.F(delta, a, player.RdScaled, v, A); double fb = this.F(delta, a, player.RdScaled, v, B); // Step 5.4 while (Math.Abs(B - A) > epsilon) { double C = A + (A - B) * fa / (fb - fa); double fc = this.F(delta, a, player.RdScaled, v, C); if (fc * fb < 0) { A = B; fa = fb; } else { fa = fa / 2.0; } B = C; fb = fc; } // Step 5.5 double vol1 = Math.Pow(Math.E, A / 2.0); // Step 6 double rdstar = Math.Sqrt(rd2 + vol1 * vol1); // Step 7 double rdnew = 1.0 / Math.Sqrt(1 / (rdstar * rdstar) + 1 / v); double ratingnew = 0.0; foreach (var opponent in opponents) { ratingnew += (rdnew * rdnew) * this.G(opponent.Item1.RatingScaled) * (opponent.Item2 - this.E(player.RatingScaled, opponent.Item1.RatingScaled, opponent.Item1.RdScaled)); } // Step 8 var result = new ScorePlayer(player.Id); result.RatingScaled = player.RatingScaled + ratingnew * factor; result.RdScaled = (rdnew - player.RdScaled) * factor + player.RdScaled; return(result); }
public ScorePlayer Calculate(ScorePlayer player, IEnumerable<Tuple<ScorePlayer, double>> opponents, double factor = 1.0) { // Step 3 double v = 0.0; foreach(var opponent in opponents) { var e = this.E(player.RatingScaled, opponent.Item1.RatingScaled, opponent.Item1.RdScaled); v += Math.Pow(this.G(opponent.Item1.RdScaled), 2) * e * (1 - e); } v = Math.Pow(v, -1.0); // Step 4 double delta = 0.0; foreach(var opponent in opponents) { delta += this.G(opponent.Item1.RdScaled) * (opponent.Item2 - this.E(player.RatingScaled, opponent.Item1.RatingScaled, opponent.Item1.RdScaled)); } delta *= v; // Step 5 const double epsilon = 0.000001; double A, a, B; A = a = Math.Log(Math.Pow(player.Vol, 2)); var delta2 = delta * delta; var rd2 = player.RdScaled * player.RdScaled; if (delta2 > rd2 + v) { B = Math.Log(delta2 - rd2 - v); } else { int k = 0; while (this.F(delta, a, player.RdScaled, v, a - k * Config.Tau) < 0) { ++k; } B = a - k * Config.Tau; } // Step 5.3 double fa = this.F(delta, a, player.RdScaled, v, A); double fb = this.F(delta, a, player.RdScaled, v, B); // Step 5.4 while (Math.Abs(B - A) > epsilon) { double C = A + (A - B) * fa / (fb - fa); double fc = this.F(delta, a, player.RdScaled, v, C); if (fc * fb < 0) { A = B; fa = fb; } else { fa = fa / 2.0; } B = C; fb = fc; } // Step 5.5 double vol1 = Math.Pow(Math.E, A / 2.0); // Step 6 double rdstar = Math.Sqrt(rd2 + vol1 * vol1); // Step 7 double rdnew = 1.0 / Math.Sqrt(1 / (rdstar * rdstar) + 1 / v); double ratingnew = 0.0; foreach(var opponent in opponents) { ratingnew += (rdnew * rdnew) * this.G(opponent.Item1.RatingScaled) * (opponent.Item2 - this.E(player.RatingScaled, opponent.Item1.RatingScaled, opponent.Item1.RdScaled)); } // Step 8 var result = new ScorePlayer(player.Id); result.RatingScaled = player.RatingScaled + ratingnew * factor; result.RdScaled = (rdnew - player.RdScaled) * factor + player.RdScaled; return result; }