Last active
January 3, 2016 09:09
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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