Skip to content

Instantly share code, notes, and snippets.

@MatthewVines
Last active January 3, 2016 09:09
Show Gist options
  • Save MatthewVines/8440886 to your computer and use it in GitHub Desktop.
Save MatthewVines/8440886 to your computer and use it in GitHub Desktop.
A set of classes that will calculate the ELO rankings of 2 players after a match.
using System;
namespace ELO
{
public class ELORanker
{
private readonly IKResolver _kResolver;
public ELORanker() : this(new DefaultKResolver()){}
public ELORanker(IKResolver kResolver)
{
_kResolver = kResolver;
}
public double GetPlayerExpectedScore(int playerRanking, int opponentRanking)
{
return 1 / (1 + Math.Pow(10, ((opponentRanking - playerRanking) / 400d)));
}
public MatchSummary ResolveMatch(int aRanking, int bRanking, MatchOutcome outcome)
{
double aExpectedScore = GetPlayerExpectedScore(aRanking, bRanking);
double bExpectedScore = 1d - aExpectedScore;
Tuple<double, double> actualScores = GetScoreFromMatchOutcome(outcome);
double aActualScore = actualScores.Item1;
double bActualScore = actualScores.Item2;
int aK = _kResolver.GetKValueForRanking(aRanking);
int bK = _kResolver.GetKValueForRanking(bRanking);
int aNewRanking = (int)Math.Floor(aRanking + (aK*(aActualScore - aExpectedScore)));
int bNewRanking = (int)Math.Floor(bRanking + (bK*(bActualScore - bExpectedScore)));
return new MatchSummary(aRanking, bRanking, outcome, aNewRanking, bNewRanking);
}
private Tuple<double, double> GetScoreFromMatchOutcome(MatchOutcome outcome)
{
switch (outcome)
{
case MatchOutcome.AWin:
return new Tuple<double, double>(1, 0);
case MatchOutcome.BWin:
return new Tuple<double, double>(0, 1);
case MatchOutcome.Draw:
default:
return new Tuple<double, double>(.5d, .5d);
}
}
}
public struct MatchSummary
{
public int AOldRanking { get; private set; }
public int BOldRanking { get; private set; }
public MatchOutcome Outcome { get; private set; }
public int ANewRanking { get; private set; }
public int BNewRanking { get; private set; }
public MatchSummary(int aOldRanking, int bOldRanking, MatchOutcome outcome, int aNewRanking, int bNewRanking) : this()
{
AOldRanking = aOldRanking;
BOldRanking = bOldRanking;
Outcome = outcome;
ANewRanking = aNewRanking;
BNewRanking = bNewRanking;
}
}
public enum MatchOutcome
{
AWin,
BWin,
Draw
}
public interface IKResolver
{
int GetKValueForRanking(int ranking);
}
public class DefaultKResolver : IKResolver
{
public int GetKValueForRanking(int ranking)
{
if (ranking < 2100)
{
return 32;
}
else if (ranking >= 2100 && ranking < 2400)
{
return 24;
}
else // if (ranking >= 2400)
{
return 16;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment