예제 #1
0
        /// <summary>
        /// Record a new result from a match between two players.
        /// </summary>
        /// <param name="winner"></param>
        /// <param name="loser"></param>
        /// <param name="isDraw"></param>
        public Result(Rating winner, Rating loser, bool isDraw = false)
        {
            if (!ValidPlayers(winner, loser))
            {
                throw new ArgumentException("Players winner and loser are the same player");
            }

            _winner = winner;
            _loser = loser;
            _isDraw = isDraw;
        }
예제 #2
0
        /// <summary>
        /// Given a particular player, returns the opponent.
        /// </summary>
        /// <param name="player"></param>
        /// <returns></returns>
        public Rating GetOpponent(Rating player)
        {
            Rating opponent;

            if (_winner == player)
            {
                opponent = _loser;
            }
            else if (_loser == player)
            {
                opponent = _winner;
            }
            else
            {
                throw new ArgumentException("Player did not participate in match", "player");
            }

            return opponent;
        }
예제 #3
0
        /// <summary>
        /// Returns the "score" for a match.
        /// </summary>
        /// <param name="player"></param>
        /// <returns></returns>
        public double GetScore(Rating player)
        {
            double score;

            if (_winner == player)
            {
                score = PointsForWin;
            }
            else if (_loser == player)
            {
                score = PointsForLoss;
            }
            else
            {
                throw new ArgumentException("Player did not participate in match", "player");
            }

            if (_isDraw)
            {
                score = PointsForDraw;
            }

            return score;
        }
예제 #4
0
 /// <summary>
 /// Check that we're not doing anything silly like recording a match with only one player.
 /// </summary>
 /// <param name="player1"></param>
 /// <param name="player2"></param>
 /// <returns></returns>
 private static bool ValidPlayers(Rating player1, Rating player2)
 {
     return player1 != player2;
 }
 /// <summary>
 /// This is a formula as per step 4 of Glickman's paper.
 /// </summary>
 /// <param name="player"></param>
 /// <param name="results"></param>
 /// <returns></returns>
 private double Delta(Rating player, IList<Result> results)
 {
     return V(player, results)*OutcomeBasedRating(player, results);
 }
예제 #6
0
 /// <summary>
 /// Test whether a particular player participated in the match represented by this result.
 /// </summary>
 /// <param name="player"></param>
 /// <returns></returns>
 public bool Participated(Rating player)
 {
     return player == _winner || player == _loser;
 }
        /// <summary>
        /// This is the main function in step 3 of Glickman's paper.
        /// </summary>
        /// <param name="player"></param>
        /// <param name="results"></param>
        /// <returns></returns>
        private static double V(Rating player, IEnumerable<Result> results)
        {
            var v = 0.0;

            foreach (var result in results)
            {
                v = v + (
                    (Math.Pow(G(result.GetOpponent(player).GetGlicko2RatingDeviation()), 2))
                    *E(player.GetGlicko2Rating(),
                        result.GetOpponent(player).GetGlicko2Rating(),
                        result.GetOpponent(player).GetGlicko2RatingDeviation())
                    *(1.0 - E(player.GetGlicko2Rating(),
                        result.GetOpponent(player).GetGlicko2Rating(),
                        result.GetOpponent(player).GetGlicko2RatingDeviation())
                        ));
            }

            return Math.Pow(v, -1);
        }
        /// <summary>
        /// This is the function processing described in step 5 of Glickman's paper.
        /// </summary>
        /// <param name="player"></param>
        /// <param name="results"></param>
        private void CalculateNewRating(Rating player, IList<Result> results)
        {
            var phi = player.GetGlicko2RatingDeviation();
            var sigma = player.GetVolatility();
            var a = Math.Log(Math.Pow(sigma, 2));
            var delta = Delta(player, results);
            var v = V(player, results);

            // step 5.2 - set the initial values of the iterative algorithm to come in step 5.4
            var A = a;
            double B;
            if (Math.Pow(delta, 2) > Math.Pow(phi, 2) + v)
            {
                B = Math.Log(Math.Pow(delta, 2) - Math.Pow(phi, 2) - v);
            }
            else
            {
                double k = 1;
                B = a - (k*Math.Abs(_tau));

                while (F(B, delta, phi, v, a, _tau) < 0)
                {
                    k++;
                    B = a - (k*Math.Abs(_tau));
                }
            }

            // step 5.3
            var fA = F(A, delta, phi, v, a, _tau);
            var fB = F(B, delta, phi, v, a, _tau);

            // step 5.4
            while (Math.Abs(B - A) > ConvergenceTolerance)
            {
                var C = A + (((A - B)*fA)/(fB - fA));
                var fC = F(C, delta, phi, v, a, _tau);

                if (fC*fB < 0)
                {
                    A = B;
                    fA = fB;
                }
                else
                {
                    fA = fA/2.0;
                }

                B = C;
                fB = fC;
            }

            var newSigma = Math.Exp(A/2.0);

            player.SetWorkingVolatility(newSigma);

            // Step 6
            var phiStar = CalculateNewRatingDeviation(phi, newSigma);

            // Step 7
            var newPhi = 1.0/Math.Sqrt((1.0/Math.Pow(phiStar, 2)) + (1.0/v));

            // note that the newly calculated rating values are stored in a "working" area in the Rating object
            // this avoids us attempting to calculate subsequent participants' ratings against a moving target
            player.SetWorkingRating(
                player.GetGlicko2Rating()
                + (Math.Pow(newPhi, 2)*OutcomeBasedRating(player, results)));
            player.SetWorkingRatingDeviation(newPhi);
            player.IncrementNumberOfResults(results.Count);
        }
        /// <summary>
        /// Add a result to the set.
        /// </summary>
        /// <param name="winner"></param>
        /// <param name="loser"></param>
        public void AddResult(Rating winner, Rating loser)
        {
            var result = new Result(winner, loser);

            _results.Add(result);
        }
예제 #10
0
        /// <summary>
        /// This is a formula as per step 4 of Glickman's paper.
        /// </summary>
        /// <param name="player"></param>
        /// <param name="results"></param>
        /// <returns>Expected rating based on outcomes.</returns>
        private static double OutcomeBasedRating(Rating player, IEnumerable<Result> results)
        {
            double outcomeBasedRating = 0;

            foreach (var result in results)
            {
                outcomeBasedRating = outcomeBasedRating
                                     + (G(result.GetOpponent(player).GetGlicko2RatingDeviation())
                                        *(result.GetScore(player) - E(
                                            player.GetGlicko2Rating(),
                                            result.GetOpponent(player).GetGlicko2Rating(),
                                            result.GetOpponent(player).GetGlicko2RatingDeviation()))
                                         );
            }

            return outcomeBasedRating;
        }
 /// <summary>
 /// Add a participant to the rating period, e.g. so that their rating will
 /// still be calculated even if they don't actually compete.
 /// </summary>
 /// <param name="rating"></param>
 public void AddParticipant(Rating rating)
 {
     _participants.Add(rating);
 }
        /// <summary>
        /// Record a draw between two players and add to the set.
        /// </summary>
        /// <param name="player1"></param>
        /// <param name="player2"></param>
        public void AddDraw(Rating player1, Rating player2)
        {
            var result = new Result(player1, player2, true);

            _results.Add(result);
        }
        /// <summary>
        /// Get a list of the results for a given player.
        /// </summary>
        /// <param name="player"></param>
        /// <returns></returns>
        public IList<Result> GetResults(Rating player)
        {
            var filteredResults = new List<Result>();

            foreach (var result in _results)
            {
                if (result.Participated(player))
                {
                    filteredResults.Add(result);
                }
            }

            return filteredResults;
        }
예제 #14
0
 /// <summary>
 /// Test whether a particular player participated in the match represented by this result.
 /// </summary>
 /// <param name="player"></param>
 /// <returns></returns>
 public bool Participated(Rating player)
 {
     return(player == _winner || player == _loser);
 }
예제 #15
0
 /// <summary>
 /// Check that we're not doing anything silly like recording a match with only one player.
 /// </summary>
 /// <param name="player1"></param>
 /// <param name="player2"></param>
 /// <returns></returns>
 private static bool ValidPlayers(Rating player1, Rating player2)
 {
     return(player1 != player2);
 }