Initial version of Moserware.Skills TrueSkill calculator to go along with my Computing Your Skill blog post

This commit is contained in:
Jeff Moser
2010-03-18 07:39:48 -04:00
commit cb46631ff8
77 changed files with 6172 additions and 0 deletions

View File

@ -0,0 +1,51 @@
using Moserware.Skills;
using Moserware.Skills.Elo;
using NUnit.Framework;
namespace UnitTests.Elo
{
[TestFixture]
public class DuellingEloTest
{
private const double ErrorTolerance = 0.1;
[Test]
public void TwoOnTwoDuellingTest()
{
var calculator = new DuellingEloCalculator(new GaussianEloCalculator());
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating)
.AddPlayer(player2, gameInfo.DefaultRating);
var player3 = new Player(3);
var player4 = new Player(4);
var team2 = new Team()
.AddPlayer(player3, gameInfo.DefaultRating)
.AddPlayer(player4, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// TODO: Verify?
AssertRating(37, newRatingsWinLose[player1]);
AssertRating(37, newRatingsWinLose[player2]);
AssertRating(13, newRatingsWinLose[player3]);
AssertRating(13, newRatingsWinLose[player4]);
var quality = calculator.CalculateMatchQuality(gameInfo, teams);
Assert.AreEqual(1.0, quality, 0.001);
}
private static void AssertRating(double expected, Rating actual)
{
Assert.AreEqual(expected, actual.Mean, ErrorTolerance);
}
}
}

View File

@ -0,0 +1,37 @@
using Moserware.Skills;
using Moserware.Skills.Elo;
using NUnit.Framework;
namespace UnitTests.Elo
{
internal static class EloAssert
{
private const double ErrorTolerance = 0.1;
public static void AssertChessRating(TwoPlayerEloCalculator calculator,
double player1BeforeRating,
double player2BeforeRating,
PairwiseComparison player1Result,
double player1AfterRating,
double player2AfterRating)
{
var player1 = new Player(1);
var player2 = new Player(2);
var teams = Teams.Concat(
new Team(player1, new EloRating(player1BeforeRating)),
new Team(player2, new EloRating(player2BeforeRating)));
var chessGameInfo = new GameInfo(1200, 0, 200, 0, 0);
var result = calculator.CalculateNewRatings(chessGameInfo, teams,
(player1Result == PairwiseComparison.Win) ? new[] { 1, 2 } :
(player1Result == PairwiseComparison.Lose) ? new[] { 2, 1 } :
new[] { 1, 1 });
Assert.AreEqual(player1AfterRating, result[player1].Mean, ErrorTolerance);
Assert.AreEqual(player2AfterRating, result[player2].Mean, ErrorTolerance);
}
}
}

View File

@ -0,0 +1,36 @@
using Moserware.Skills;
using Moserware.Skills.Elo;
using NUnit.Framework;
namespace UnitTests.Elo
{
[TestFixture]
public class FideEloCalculatorTest
{
[Test]
public void FideProvisionalEloCalculatorTests()
{
// verified against http://ratings.fide.com/calculator_rtd.phtml
var calc = new FideEloCalculator(new FideKFactor.Provisional());
EloAssert.AssertChessRating(calc, 1200, 1500, PairwiseComparison.Win, 1221.25, 1478.75);
EloAssert.AssertChessRating(calc, 1200, 1500, PairwiseComparison.Draw, 1208.75, 1491.25);
EloAssert.AssertChessRating(calc, 1200, 1500, PairwiseComparison.Lose, 1196.25, 1503.75);
}
[Test]
public void FideNonProvisionalEloCalculatorTests()
{
// verified against http://ratings.fide.com/calculator_rtd.phtml
var calc = new FideEloCalculator();
EloAssert.AssertChessRating(calc, 1200, 1200, PairwiseComparison.Win, 1207.5, 1192.5);
EloAssert.AssertChessRating(calc, 1200, 1200, PairwiseComparison.Draw, 1200, 1200);
EloAssert.AssertChessRating(calc, 1200, 1200, PairwiseComparison.Lose, 1192.5, 1207.5);
EloAssert.AssertChessRating(calc, 2600, 2500, PairwiseComparison.Win, 2603.6, 2496.4);
EloAssert.AssertChessRating(calc, 2600, 2500, PairwiseComparison.Draw, 2598.6, 2501.4);
EloAssert.AssertChessRating(calc, 2600, 2500, PairwiseComparison.Lose, 2593.6, 2506.4);
}
}
}

View File

@ -0,0 +1,26 @@
using Moserware.Skills;
using Moserware.Skills.Elo;
using NUnit.Framework;
namespace UnitTests.Elo
{
[TestFixture]
public class GaussianEloCalculatorTest
{
[Test]
public void GaussianEloCalculatorTests()
{
const double defaultKFactor = 24.0;
var calc = new GaussianEloCalculator();
EloAssert.AssertChessRating(calc, 1200, 1200, PairwiseComparison.Win, 1212, 1188);
EloAssert.AssertChessRating(calc, 1200, 1200, PairwiseComparison.Draw, 1200, 1200);
EloAssert.AssertChessRating(calc, 1200, 1200, PairwiseComparison.Lose, 1188, 1212);
// verified using TrueSkill paper equation
EloAssert.AssertChessRating(calc, 1200, 1000, PairwiseComparison.Win, 1200 + ((1 - 0.76024993890652326884) * defaultKFactor), 1000 - (1 - 0.76024993890652326884) * defaultKFactor);
EloAssert.AssertChessRating(calc, 1200, 1000, PairwiseComparison.Draw, 1200 - (0.76024993890652326884 - 0.5) * defaultKFactor, 1000 + (0.76024993890652326884 - 0.5) * defaultKFactor);
EloAssert.AssertChessRating(calc, 1200, 1000, PairwiseComparison.Lose, 1200 - 0.76024993890652326884 * defaultKFactor, 1000 + 0.76024993890652326884 * defaultKFactor);
}
}
}

View File

@ -0,0 +1,68 @@
using System;
using Moserware.Numerics;
using NUnit.Framework;
namespace UnitTests.Numerics
{
[TestFixture]
public class GaussianDistributionTests
{
private const double ErrorTolerance = 0.000001;
[Test]
public void MultiplicationTests()
{
// I verified this against the formula at http://www.tina-vision.net/tina-knoppix/tina-memo/2003-003.pdf
var standardNormal = new GaussianDistribution(0, 1);
var shiftedGaussian = new GaussianDistribution(2, 3);
var product = standardNormal * shiftedGaussian;
Assert.AreEqual(0.2, product.Mean, ErrorTolerance);
Assert.AreEqual(3.0 / Math.Sqrt(10), product.StandardDeviation, ErrorTolerance);
var m4s5 = new GaussianDistribution(4, 5);
var m6s7 = new GaussianDistribution(6, 7);
var product2 = m4s5 * m6s7;
Func<double, double> square = x => x*x;
var expectedMean = (4 * square(7) + 6 * square(5)) / (square(5) + square(7));
Assert.AreEqual(expectedMean, product2.Mean, ErrorTolerance);
var expectedSigma = Math.Sqrt(((square(5) * square(7)) / (square(5) + square(7))));
Assert.AreEqual(expectedSigma, product2.StandardDeviation, ErrorTolerance);
}
[Test]
public void DivisionTests()
{
// Since the multiplication was worked out by hand, we use the same numbers but work backwards
var product = new GaussianDistribution(0.2, 3.0 / Math.Sqrt(10));
var standardNormal = new GaussianDistribution(0, 1);
var productDividedByStandardNormal = product / standardNormal;
Assert.AreEqual(2.0, productDividedByStandardNormal.Mean, ErrorTolerance);
Assert.AreEqual(3.0, productDividedByStandardNormal.StandardDeviation, ErrorTolerance);
Func<double, double> square = x => x * x;
var product2 = new GaussianDistribution((4 * square(7) + 6 * square(5)) / (square(5) + square(7)), Math.Sqrt(((square(5) * square(7)) / (square(5) + square(7)))));
var m4s5 = new GaussianDistribution(4,5);
var product2DividedByM4S5 = product2 / m4s5;
Assert.AreEqual(6.0, product2DividedByM4S5.Mean, ErrorTolerance);
Assert.AreEqual(7.0, product2DividedByM4S5.StandardDeviation, ErrorTolerance);
}
[Test]
public void LogProductNormalizationTests()
{
var m4s5 = new GaussianDistribution(4, 5);
var m6s7 = new GaussianDistribution(6, 7);
var product2 = m4s5 * m6s7;
var normConstant = 1.0 / (Math.Sqrt(2 * Math.PI) * product2.StandardDeviation);
var lpn = GaussianDistribution.LogProductNormalization(m4s5, m6s7);
}
}
}

View File

@ -0,0 +1,186 @@
using Moserware.Numerics;
using NUnit.Framework;
namespace UnitTests.Numerics
{
[TestFixture]
public class MatrixTests
{
[Test]
public void TwoByTwoDeterminantTests()
{
var a = new SquareMatrix(1, 2,
3, 4);
Assert.AreEqual(-2, a.Determinant);
var b = new SquareMatrix(3, 4,
5, 6);
Assert.AreEqual(-2, b.Determinant);
var c = new SquareMatrix(1, 1,
1, 1);
Assert.AreEqual(0, c.Determinant);
var d = new SquareMatrix(12, 15,
17, 21);
Assert.AreEqual(12 * 21 - 15 * 17, d.Determinant);
}
[Test]
public void ThreeByThreeDeterminantTests()
{
var a = new SquareMatrix(1, 2, 3,
4, 5, 6,
7, 8, 9);
Assert.AreEqual(0, a.Determinant);
var π = new SquareMatrix(3, 1, 4,
1, 5, 9,
2, 6, 5);
// Verified against http://www.wolframalpha.com/input/?i=determinant+%7B%7B3%2C1%2C4%7D%2C%7B1%2C5%2C9%7D%2C%7B2%2C6%2C5%7D%7D
Assert.AreEqual(-90, π.Determinant);
}
[Test]
public void FourByFourDeterminantTests()
{
var a = new SquareMatrix( 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
Assert.AreEqual(0, a.Determinant);
var π = new SquareMatrix(3, 1, 4, 1,
5, 9, 2, 6,
5, 3, 5, 8,
9, 7, 9, 3);
// Verified against http://www.wolframalpha.com/input/?i=determinant+%7B+%7B3%2C1%2C4%2C1%7D%2C+%7B5%2C9%2C2%2C6%7D%2C+%7B5%2C3%2C5%2C8%7D%2C+%7B9%2C7%2C9%2C3%7D%7D
Assert.AreEqual(98, π.Determinant);
}
[Test]
public void EightByEightDeterminantTests()
{
var a = new SquareMatrix( 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 32, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64);
Assert.AreEqual(0, a.Determinant);
var π = new SquareMatrix(3, 1, 4, 1, 5, 9, 2, 6,
5, 3, 5, 8, 9, 7, 9, 3,
2, 3, 8, 4, 6, 2, 6, 4,
3, 3, 8, 3, 2, 7, 9, 5,
0, 2, 8, 8, 4, 1, 9, 7,
1, 6, 9, 3, 9, 9, 3, 7,
5, 1, 0, 5, 8, 2, 0, 9,
7, 4, 9, 4, 4, 5, 9, 2);
// Verified against http://www.wolframalpha.com/input/?i=det+%7B%7B3%2C1%2C4%2C1%2C5%2C9%2C2%2C6%7D%2C%7B5%2C3%2C5%2C8%2C9%2C7%2C9%2C3%7D%2C%7B2%2C3%2C8%2C4%2C6%2C2%2C6%2C4%7D%2C%7B3%2C3%2C8%2C3%2C2%2C7%2C9%2C5%7D%2C%7B0%2C2%2C8%2C8%2C4%2C1%2C9%2C7%7D%2C%7B1%2C6%2C9%2C3%2C9%2C9%2C3%2C7%7D%2C%7B5%2C1%2C0%2C5%2C8%2C2%2C0%2C9%7D%2C%7B7%2C4%2C9%2C4%2C4%2C5%2C9%2C2%7D%7D
Assert.AreEqual(1378143, π.Determinant);
}
[Test]
public void EqualsTest()
{
var a = new SquareMatrix(1, 2,
3, 4);
var b = new SquareMatrix(1, 2,
3, 4);
Assert.IsTrue(a == b);
Assert.AreEqual(a, b);
var c = new Matrix(2, 3,
1, 2, 3,
4, 5, 6);
var d = new Matrix(2, 3,
1, 2, 3,
4, 5, 6);
Assert.IsTrue(c == d);
Assert.AreEqual(c, d);
var e = new Matrix(3, 2,
1, 4,
2, 5,
3, 6);
var f = e.Transpose;
Assert.IsTrue(d == f);
Assert.AreEqual(d, f);
Assert.AreEqual(d.GetHashCode(), f.GetHashCode());
}
[Test]
public void AdjugateTests()
{
// From Wikipedia: http://en.wikipedia.org/wiki/Adjugate_matrix
var a = new SquareMatrix(1, 2,
3, 4);
var b = new SquareMatrix( 4, -2,
-3, 1);
Assert.AreEqual(b, a.Adjugate);
var c = new SquareMatrix(-3, 2, -5,
-1, 0, -2,
3, -4, 1);
var d = new SquareMatrix(-8, 18, -4,
-5, 12, -1,
4, -6, 2);
Assert.AreEqual(d, c.Adjugate);
}
[Test]
public void InverseTests()
{
// see http://www.mathwords.com/i/inverse_of_a_matrix.htm
var a = new SquareMatrix(4, 3,
3, 2);
var b = new SquareMatrix(-2, 3,
3, -4);
var aInverse = a.Inverse;
Assert.AreEqual(b, aInverse);
var identity2x2 = new IdentityMatrix(2);
var aaInverse = a * aInverse;
Assert.IsTrue(identity2x2 == aaInverse);
var c = new SquareMatrix(1, 2, 3,
0, 4, 5,
1, 0, 6);
var cInverse = c.Inverse;
var d = (1.0 / 22) * new SquareMatrix(24, -12, -2,
5, 3, -5,
-4, 2, 4);
Assert.IsTrue(d == cInverse);
var identity3x3 = new IdentityMatrix(3);
var ccInverse = c * cInverse;
Assert.IsTrue(identity3x3 == ccInverse);
}
}
}

View File

@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnitTests")]
[assembly: AssemblyDescription("Unit tests for Moserware.Skills")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Jeff Moser")]
[assembly: AssemblyProduct("UnitTests")]
[assembly: AssemblyCopyright("Copyright © Jeff Moser 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ddd7d430-f9c0-45c8-9576-70418d766e1f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

23
UnitTests/README.txt Normal file
View File

@ -0,0 +1,23 @@
These tests were written using NUnit 2.5.2 that is available for download
at:
http://sourceforge.net/projects/nunit/files/NUnit%20Version%202/NUnit-2.5.2.9222.msi/download
If you have a different version or setup, you'll need to update the path under
the UnitTests project properties by right clicking on UnitTests and then
click "properties" and then click the "debug" tab. The "start external program"
points to the NUnit test runner.
I did it this way so you didn't need more than the express version of
Visual Studio to run. If you have a fancy test runner already, feel
free to use that.
Additionally, it should be easy to update the tests to your tool
of choice.
Finally, realize that these tests test *all* of the calculators
implementations. For that reason, they create a new instance of
a particular calculator. If you're using this code in your application,
you can just use the convenience helper class of "TrueSkillCalculator"
that has static methods. If you do that, you won't have to worry
about creating your own instances.

View File

@ -0,0 +1,34 @@
using System.Collections.Generic;
using Moserware.Skills;
using NUnit.Framework;
namespace UnitTests
{
[TestFixture]
public class RankSorterTest
{
[Test]
public void SortAlreadySortedTest()
{
IEnumerable<string> people = new[] { "One", "Two", "Three" };
int[] ranks = new[] { 1, 2, 3 };
RankSorter.Sort(ref people, ref ranks);
CollectionAssert.AreEqual(new[] { "One", "Two", "Three" }, people);
CollectionAssert.AreEqual(new[] { 1, 2, 3 }, ranks);
}
[Test]
public void SortUnsortedTest()
{
IEnumerable<string> people = new[] { "Five", "Two1", "Two2", "One", "Four" };
int[] ranks = new[] { 5, 2, 2, 1, 4 };
RankSorter.Sort(ref people, ref ranks);
CollectionAssert.AreEqual(new[] { "One", "Two1", "Two2", "Four", "Five" }, people);
CollectionAssert.AreEqual(new[] { 1, 2, 2, 4, 5 }, ranks);
}
}
}

View File

@ -0,0 +1,27 @@
using Moserware.Skills.TrueSkill;
using NUnit.Framework;
namespace UnitTests.TrueSkill
{
[TestFixture]
public class DrawMarginTest
{
private const double ErrorTolerance = .000001;
[Test]
public void GetDrawMarginFromDrawProbabilityTest()
{
double beta = 25.0 / 6.0;
// The expected values were compared against Ralf Herbrich's implementation in F#
AssertDrawMargin(0.10, beta, 0.74046637542690541);
AssertDrawMargin(0.25, beta, 1.87760059883033);
AssertDrawMargin(0.33, beta, 2.5111010132487492);
}
private static void AssertDrawMargin(double drawProbability, double beta, double expected)
{
double actual = DrawMargin.GetDrawMarginFromDrawProbability(drawProbability, beta);
Assert.AreEqual(expected, actual, ErrorTolerance);
}
}
}

View File

@ -0,0 +1,22 @@
using Moserware.Skills.TrueSkill;
using NUnit.Framework;
namespace UnitTests.TrueSkill
{
[TestFixture]
public class FactorGraphTrueSkillCalculatorTests
{
[Test]
public void FullFactorGraphCalculatorTests()
{
var calculator = new FactorGraphTrueSkillCalculator();
// We can test all classes
TrueSkillCalculatorTests.TestAllTwoPlayerScenarios(calculator);
TrueSkillCalculatorTests.TestAllTwoTeamScenarios(calculator);
TrueSkillCalculatorTests.TestAllMultipleTeamScenarios(calculator);
TrueSkillCalculatorTests.TestPartialPlayScenarios(calculator);
}
}
}

View File

@ -0,0 +1,987 @@
using Moserware.Skills;
using NUnit.Framework;
namespace UnitTests.TrueSkill
{
public static class TrueSkillCalculatorTests
{
private const double ErrorTolerance = 0.085;
// These are the roll-up ones
public static void TestAllTwoPlayerScenarios(SkillCalculator calculator)
{
TwoPlayerTestNotDrawn(calculator);
TwoPlayerTestDrawn(calculator);
OneOnOneMassiveUpsetDrawTest(calculator);
TwoPlayerChessTestNotDrawn(calculator);
}
public static void TestAllTwoTeamScenarios(SkillCalculator calculator)
{
OneOnTwoSimpleTest(calculator);
OneOnTwoDrawTest(calculator);
OneOnTwoSomewhatBalanced(calculator);
OneOnThreeDrawTest(calculator);
OneOnThreeSimpleTest(calculator);
OneOnSevenSimpleTest(calculator);
TwoOnTwoSimpleTest(calculator);
TwoOnTwoUnbalancedDrawTest(calculator);
TwoOnTwoDrawTest(calculator);
TwoOnTwoUpsetTest(calculator);
ThreeOnTwoTests(calculator);
FourOnFourSimpleTest(calculator);
}
public static void TestAllMultipleTeamScenarios(SkillCalculator calculator)
{
ThreeTeamsOfOneNotDrawn(calculator);
ThreeTeamsOfOneDrawn(calculator);
FourTeamsOfOneNotDrawn(calculator);
FiveTeamsOfOneNotDrawn(calculator);
EightTeamsOfOneDrawn(calculator);
EightTeamsOfOneUpset(calculator);
SixteenTeamsOfOneNotDrawn(calculator);
TwoOnFourOnTwoWinDraw(calculator);
}
public static void TestPartialPlayScenarios(SkillCalculator calculator)
{
OneOnTwoBalancedPartialPlay(calculator);
}
//------------------- Actual Tests ---------------------------
// If you see more than 3 digits of precision in the decimal point, then the expected values calculated from
// F# RalfH's implementation with the same input. It didn't support teams, so team values all came from the
// online calculator at http://atom.research.microsoft.com/trueskill/rankcalculator.aspx
//
// All match quality expected values came from the online calculator
// In both cases, there may be some discrepancy after the first decimal point. I think this is due to my implementation
// using slightly higher precision in GaussianDistribution.
//------------------------------------------------------------------------------
// Two Player Tests
//------------------------------------------------------------------------------
private static void TwoPlayerTestNotDrawn(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, gameInfo.DefaultRating);
var team2 = new Team(player2, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
var player1NewRating = newRatings[player1];
AssertRating(29.39583201999924, 7.171475587326186, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(20.60416798000076, 7.171475587326186, player2NewRating);
AssertMatchQuality(0.447, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void TwoPlayerTestDrawn(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, gameInfo.DefaultRating);
var team2 = new Team(player2, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 1);
var player1NewRating = newRatings[player1];
AssertRating(25.0, 6.4575196623173081, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(25.0, 6.4575196623173081, player2NewRating);
AssertMatchQuality(0.447, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void TwoPlayerChessTestNotDrawn(SkillCalculator calculator)
{
// Inspired by a real bug :-)
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = new GameInfo(1200.0, 1200.0 / 3.0, 200.0, 1200.0 / 300.0, 0.03);
var team1 = new Team(player1, new Rating(1301.0007, 42.9232));
var team2 = new Team(player2, new Rating(1188.7560, 42.5570));
var newRatings = calculator.CalculateNewRatings(gameInfo, Teams.Concat(team1, team2), 1, 2);
var player1NewRating = newRatings[player1];
AssertRating(1304.7820836053318, 42.843513887848658, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(1185.0383099003536, 42.485604606897752, player2NewRating);
}
private static void OneOnOneMassiveUpsetDrawTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating);
var player2 = new Player(2);
var team2 = new Team()
.AddPlayer(player2, new Rating(50, 12.5));
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 1);
// Winners
AssertRating(31.662, 7.137, newRatingsWinLose[player1]);
// Losers
AssertRating(35.010, 7.910, newRatingsWinLose[player2]);
AssertMatchQuality(0.110, calculator.CalculateMatchQuality(gameInfo, teams));
}
//------------------------------------------------------------------------------
// Two Team Tests
//------------------------------------------------------------------------------
private static void TwoOnTwoSimpleTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating)
.AddPlayer(player2, gameInfo.DefaultRating);
var player3 = new Player(3);
var player4 = new Player(4);
var team2 = new Team()
.AddPlayer(player3, gameInfo.DefaultRating)
.AddPlayer(player4, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// Winners
AssertRating(28.108, 7.774, newRatingsWinLose[player1]);
AssertRating(28.108, 7.774, newRatingsWinLose[player2]);
// Losers
AssertRating(21.892, 7.774, newRatingsWinLose[player3]);
AssertRating(21.892, 7.774, newRatingsWinLose[player4]);
AssertMatchQuality(0.447, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void TwoOnTwoDrawTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating)
.AddPlayer(player2, gameInfo.DefaultRating);
var player3 = new Player(3);
var player4 = new Player(4);
var team2 = new Team()
.AddPlayer(player3, gameInfo.DefaultRating)
.AddPlayer(player4, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 1);
// Winners
AssertRating(25, 7.455, newRatingsWinLose[player1]);
AssertRating(25, 7.455, newRatingsWinLose[player2]);
// Losers
AssertRating(25, 7.455, newRatingsWinLose[player3]);
AssertRating(25, 7.455, newRatingsWinLose[player4]);
AssertMatchQuality(0.447, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void TwoOnTwoUnbalancedDrawTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, new Rating(15, 8))
.AddPlayer(player2, new Rating(20, 6));
var player3 = new Player(3);
var player4 = new Player(4);
var team2 = new Team()
.AddPlayer(player3, new Rating(25, 4))
.AddPlayer(player4, new Rating(30, 3));
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 1);
// Winners
AssertRating(21.570, 6.556, newRatingsWinLose[player1]);
AssertRating(23.696, 5.418, newRatingsWinLose[player2]);
// Losers
AssertRating(23.357, 3.833, newRatingsWinLose[player3]);
AssertRating(29.075, 2.931, newRatingsWinLose[player4]);
AssertMatchQuality(0.214, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void TwoOnTwoUpsetTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, new Rating(20, 8))
.AddPlayer(player2, new Rating(25, 6));
var player3 = new Player(3);
var player4 = new Player(4);
var team2 = new Team()
.AddPlayer(player3, new Rating(35, 7))
.AddPlayer(player4, new Rating(40, 5));
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// Winners
AssertRating(29.698, 7.008, newRatingsWinLose[player1]);
AssertRating(30.455, 5.594, newRatingsWinLose[player2]);
// Losers
AssertRating(27.575, 6.346, newRatingsWinLose[player3]);
AssertRating(36.211, 4.768, newRatingsWinLose[player4]);
AssertMatchQuality(0.084, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void FourOnFourSimpleTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating)
.AddPlayer(player2, gameInfo.DefaultRating)
.AddPlayer(player3, gameInfo.DefaultRating)
.AddPlayer(player4, gameInfo.DefaultRating);
var player5 = new Player(5);
var player6 = new Player(6);
var player7 = new Player(7);
var player8 = new Player(8);
var team2 = new Team()
.AddPlayer(player5, gameInfo.DefaultRating)
.AddPlayer(player6, gameInfo.DefaultRating)
.AddPlayer(player7, gameInfo.DefaultRating)
.AddPlayer(player8, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// Winners
AssertRating(27.198, 8.059, newRatingsWinLose[player1]);
AssertRating(27.198, 8.059, newRatingsWinLose[player2]);
AssertRating(27.198, 8.059, newRatingsWinLose[player3]);
AssertRating(27.198, 8.059, newRatingsWinLose[player4]);
// Losers
AssertRating(22.802, 8.059, newRatingsWinLose[player5]);
AssertRating(22.802, 8.059, newRatingsWinLose[player6]);
AssertRating(22.802, 8.059, newRatingsWinLose[player7]);
AssertRating(22.802, 8.059, newRatingsWinLose[player8]);
AssertMatchQuality(0.447, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void OneOnTwoSimpleTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating);
var player2 = new Player(2);
var player3 = new Player(3);
var team2 = new Team()
.AddPlayer(player2, gameInfo.DefaultRating)
.AddPlayer(player3, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// Winners
AssertRating(33.730, 7.317, newRatingsWinLose[player1]);
// Losers
AssertRating(16.270, 7.317, newRatingsWinLose[player2]);
AssertRating(16.270, 7.317, newRatingsWinLose[player3]);
AssertMatchQuality(0.135, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void OneOnTwoSomewhatBalanced(SkillCalculator calculator)
{
var player1 = new Player(1);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, new Rating(40, 6));
var player2 = new Player(2);
var player3 = new Player(3);
var team2 = new Team()
.AddPlayer(player2, new Rating(20, 7))
.AddPlayer(player3, new Rating(25, 8));
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// Winners
AssertRating(42.744, 5.602, newRatingsWinLose[player1]);
// Losers
AssertRating(16.266, 6.359, newRatingsWinLose[player2]);
AssertRating(20.123, 7.028, newRatingsWinLose[player3]);
AssertMatchQuality(0.478, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void OneOnThreeSimpleTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var team2 = new Team()
.AddPlayer(player2, gameInfo.DefaultRating)
.AddPlayer(player3, gameInfo.DefaultRating)
.AddPlayer(player4, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// Winners
AssertRating(36.337, 7.527, newRatingsWinLose[player1]);
// Losers
AssertRating(13.663, 7.527, newRatingsWinLose[player2]);
AssertRating(13.663, 7.527, newRatingsWinLose[player3]);
AssertRating(13.663, 7.527, newRatingsWinLose[player4]);
AssertMatchQuality(0.012, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void OneOnTwoDrawTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating);
var player2 = new Player(2);
var player3 = new Player(3);
var team2 = new Team()
.AddPlayer(player2, gameInfo.DefaultRating)
.AddPlayer(player3, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 1);
// Winners
AssertRating(31.660, 7.138, newRatingsWinLose[player1]);
// Losers
AssertRating(18.340, 7.138, newRatingsWinLose[player2]);
AssertRating(18.340, 7.138, newRatingsWinLose[player3]);
AssertMatchQuality(0.135, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void OneOnThreeDrawTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var team2 = new Team()
.AddPlayer(player2, gameInfo.DefaultRating)
.AddPlayer(player3, gameInfo.DefaultRating)
.AddPlayer(player4, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 1);
// Winners
AssertRating(34.990, 7.455, newRatingsWinLose[player1]);
// Losers
AssertRating(15.010, 7.455, newRatingsWinLose[player2]);
AssertRating(15.010, 7.455, newRatingsWinLose[player3]);
AssertRating(15.010, 7.455, newRatingsWinLose[player4]);
AssertMatchQuality(0.012, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void OneOnSevenSimpleTest(SkillCalculator calculator)
{
var player1 = new Player(1);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, gameInfo.DefaultRating);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var player5 = new Player(5);
var player6 = new Player(6);
var player7 = new Player(7);
var player8 = new Player(8);
var team2 = new Team()
.AddPlayer(player2, gameInfo.DefaultRating)
.AddPlayer(player3, gameInfo.DefaultRating)
.AddPlayer(player4, gameInfo.DefaultRating)
.AddPlayer(player5, gameInfo.DefaultRating)
.AddPlayer(player6, gameInfo.DefaultRating)
.AddPlayer(player7, gameInfo.DefaultRating)
.AddPlayer(player8, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// Winners
AssertRating(40.582, 7.917, newRatingsWinLose[player1]);
// Losers
AssertRating(9.418, 7.917, newRatingsWinLose[player2]);
AssertRating(9.418, 7.917, newRatingsWinLose[player3]);
AssertRating(9.418, 7.917, newRatingsWinLose[player4]);
AssertRating(9.418, 7.917, newRatingsWinLose[player5]);
AssertRating(9.418, 7.917, newRatingsWinLose[player6]);
AssertRating(9.418, 7.917, newRatingsWinLose[player7]);
AssertRating(9.418, 7.917, newRatingsWinLose[player8]);
AssertMatchQuality(0.000, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void ThreeOnTwoTests(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var team1 = new Team()
.AddPlayer(player1, new Rating(28, 7))
.AddPlayer(player2, new Rating(27, 6))
.AddPlayer(player3, new Rating(26, 5));
var player4 = new Player(4);
var player5 = new Player(5);
var team2 = new Team()
.AddPlayer(player4, new Rating(30, 4))
.AddPlayer(player5, new Rating(31, 3));
var gameInfo = GameInfo.DefaultGameInfo;
var teams = Teams.Concat(team1, team2);
var newRatingsWinLoseExpected = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
// Winners
AssertRating(28.658, 6.770, newRatingsWinLoseExpected[player1]);
AssertRating(27.484, 5.856, newRatingsWinLoseExpected[player2]);
AssertRating(26.336, 4.917, newRatingsWinLoseExpected[player3]);
// Losers
AssertRating(29.785, 3.958, newRatingsWinLoseExpected[player4]);
AssertRating(30.879, 2.983, newRatingsWinLoseExpected[player5]);
var newRatingsWinLoseUpset = calculator.CalculateNewRatings(gameInfo, Teams.Concat(team1, team2), 2, 1);
// Winners
AssertRating(32.012, 3.877, newRatingsWinLoseUpset[player4]);
AssertRating(32.132, 2.949, newRatingsWinLoseUpset[player5]);
// Losers
AssertRating(21.840, 6.314, newRatingsWinLoseUpset[player1]);
AssertRating(22.474, 5.575, newRatingsWinLoseUpset[player2]);
AssertRating(22.857, 4.757, newRatingsWinLoseUpset[player3]);
AssertMatchQuality(0.254, calculator.CalculateMatchQuality(gameInfo, teams));
}
//------------------------------------------------------------------------------
// Multiple Teams Tests
//------------------------------------------------------------------------------
private static void TwoOnFourOnTwoWinDraw(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team()
.AddPlayer(player1, new Rating(40,4))
.AddPlayer(player2, new Rating(45,3));
var player3 = new Player(3);
var player4 = new Player(4);
var player5 = new Player(5);
var player6 = new Player(6);
var team2 = new Team()
.AddPlayer(player3, new Rating(20, 7))
.AddPlayer(player4, new Rating(19, 6))
.AddPlayer(player5, new Rating(30, 9))
.AddPlayer(player6, new Rating(10, 4));
var player7 = new Player(7);
var player8 = new Player(8);
var team3 = new Team()
.AddPlayer(player7, new Rating(50,5))
.AddPlayer(player8, new Rating(30,2));
var teams = Teams.Concat(team1, team2, team3);
var newRatingsWinLose = calculator.CalculateNewRatings(gameInfo, teams, 1, 2, 2);
// Winners
AssertRating(40.877, 3.840, newRatingsWinLose[player1]);
AssertRating(45.493, 2.934, newRatingsWinLose[player2]);
AssertRating(19.609, 6.396, newRatingsWinLose[player3]);
AssertRating(18.712, 5.625, newRatingsWinLose[player4]);
AssertRating(29.353, 7.673, newRatingsWinLose[player5]);
AssertRating(9.872, 3.891, newRatingsWinLose[player6]);
AssertRating(48.830, 4.590, newRatingsWinLose[player7]);
AssertRating(29.813, 1.976, newRatingsWinLose[player8]);
AssertMatchQuality(0.367, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void ThreeTeamsOfOneNotDrawn(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, gameInfo.DefaultRating);
var team2 = new Team(player2, gameInfo.DefaultRating);
var team3 = new Team(player3, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2, team3);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 2, 3);
var player1NewRating = newRatings[player1];
AssertRating(31.675352419172107, 6.6559853776206905, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(25.000000000003912, 6.2078966412243233, player2NewRating);
var player3NewRating = newRatings[player3];
AssertRating(18.324647580823971, 6.6559853776218318, player3NewRating);
AssertMatchQuality(0.200, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void ThreeTeamsOfOneDrawn(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, gameInfo.DefaultRating);
var team2 = new Team(player2, gameInfo.DefaultRating);
var team3 = new Team(player3, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2, team3);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 1, 1);
var player1NewRating = newRatings[player1];
AssertRating(25.000, 5.698, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(25.000, 5.695, player2NewRating);
var player3NewRating = newRatings[player3];
AssertRating(25.000, 5.698, player3NewRating);
AssertMatchQuality(0.200, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void FourTeamsOfOneNotDrawn(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, gameInfo.DefaultRating);
var team2 = new Team(player2, gameInfo.DefaultRating);
var team3 = new Team(player3, gameInfo.DefaultRating);
var team4 = new Team(player4, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2, team3, team4);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 2, 3, 4);
var player1NewRating = newRatings[player1];
AssertRating(33.206680965631264, 6.3481091698077057, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(27.401454693843323, 5.7871629348447584, player2NewRating);
var player3NewRating = newRatings[player3];
AssertRating(22.598545306188374, 5.7871629348413451, player3NewRating);
var player4NewRating = newRatings[player4];
AssertRating(16.793319034361271, 6.3481091698144967, player4NewRating);
AssertMatchQuality(0.089, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void FiveTeamsOfOneNotDrawn(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var player5 = new Player(5);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, gameInfo.DefaultRating);
var team2 = new Team(player2, gameInfo.DefaultRating);
var team3 = new Team(player3, gameInfo.DefaultRating);
var team4 = new Team(player4, gameInfo.DefaultRating);
var team5 = new Team(player5, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2, team3, team4, team5);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 2, 3, 4, 5);
var player1NewRating = newRatings[player1];
AssertRating(34.363135705841188, 6.1361528798112692, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(29.058448805636779, 5.5358352402833413, player2NewRating);
var player3NewRating = newRatings[player3];
AssertRating(25.000000000031758, 5.4200805474429847, player3NewRating);
var player4NewRating = newRatings[player4];
AssertRating(20.941551194426314, 5.5358352402709672, player4NewRating);
var player5NewRating = newRatings[player5];
AssertRating(15.636864294158848, 6.136152879829349, player5NewRating);
AssertMatchQuality(0.040, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void EightTeamsOfOneDrawn(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var player5 = new Player(5);
var player6 = new Player(6);
var player7 = new Player(7);
var player8 = new Player(8);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, gameInfo.DefaultRating);
var team2 = new Team(player2, gameInfo.DefaultRating);
var team3 = new Team(player3, gameInfo.DefaultRating);
var team4 = new Team(player4, gameInfo.DefaultRating);
var team5 = new Team(player5, gameInfo.DefaultRating);
var team6 = new Team(player6, gameInfo.DefaultRating);
var team7 = new Team(player7, gameInfo.DefaultRating);
var team8 = new Team(player8, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2, team3, team4, team5, team6, team7, team8);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 1, 1, 1, 1, 1, 1, 1);
var player1NewRating = newRatings[player1];
AssertRating(25.000, 4.592, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(25.000, 4.583, player2NewRating);
var player3NewRating = newRatings[player3];
AssertRating(25.000, 4.576, player3NewRating);
var player4NewRating = newRatings[player4];
AssertRating(25.000, 4.573, player4NewRating);
var player5NewRating = newRatings[player5];
AssertRating(25.000, 4.573, player5NewRating);
var player6NewRating = newRatings[player6];
AssertRating(25.000, 4.576, player6NewRating);
var player7NewRating = newRatings[player7];
AssertRating(25.000, 4.583, player7NewRating);
var player8NewRating = newRatings[player8];
AssertRating(25.000, 4.592, player8NewRating);
AssertMatchQuality(0.004, calculator.CalculateMatchQuality(gameInfo, teams));
}
private static void EightTeamsOfOneUpset(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var player5 = new Player(5);
var player6 = new Player(6);
var player7 = new Player(7);
var player8 = new Player(8);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, new Rating(10, 8));
var team2 = new Team(player2, new Rating(15, 7));
var team3 = new Team(player3, new Rating(20, 6));
var team4 = new Team(player4, new Rating(25, 5));
var team5 = new Team(player5, new Rating(30, 4));
var team6 = new Team(player6, new Rating(35, 3));
var team7 = new Team(player7, new Rating(40, 2));
var team8 = new Team(player8, new Rating(45, 1));
var teams = Teams.Concat(team1, team2, team3, team4, team5, team6, team7, team8);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 2, 3, 4, 5, 6, 7, 8);
var player1NewRating = newRatings[player1];
AssertRating(35.135, 4.506, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(32.585, 4.037, player2NewRating);
var player3NewRating = newRatings[player3];
AssertRating(31.329, 3.756, player3NewRating);
var player4NewRating = newRatings[player4];
AssertRating(30.984, 3.453, player4NewRating);
var player5NewRating = newRatings[player5];
AssertRating(31.751, 3.064, player5NewRating);
var player6NewRating = newRatings[player6];
AssertRating(34.051, 2.541, player6NewRating);
var player7NewRating = newRatings[player7];
AssertRating(38.263, 1.849, player7NewRating);
var player8NewRating = newRatings[player8];
AssertRating(44.118, 0.983, player8NewRating);
AssertMatchQuality(0.000, calculator.CalculateMatchQuality(gameInfo,teams));
}
private static void SixteenTeamsOfOneNotDrawn(SkillCalculator calculator)
{
var player1 = new Player(1);
var player2 = new Player(2);
var player3 = new Player(3);
var player4 = new Player(4);
var player5 = new Player(5);
var player6 = new Player(6);
var player7 = new Player(7);
var player8 = new Player(8);
var player9 = new Player(9);
var player10 = new Player(10);
var player11 = new Player(11);
var player12 = new Player(12);
var player13 = new Player(13);
var player14 = new Player(14);
var player15 = new Player(15);
var player16 = new Player(16);
var gameInfo = GameInfo.DefaultGameInfo;
var team1 = new Team(player1, gameInfo.DefaultRating);
var team2 = new Team(player2, gameInfo.DefaultRating);
var team3 = new Team(player3, gameInfo.DefaultRating);
var team4 = new Team(player4, gameInfo.DefaultRating);
var team5 = new Team(player5, gameInfo.DefaultRating);
var team6 = new Team(player6, gameInfo.DefaultRating);
var team7 = new Team(player7, gameInfo.DefaultRating);
var team8 = new Team(player8, gameInfo.DefaultRating);
var team9 = new Team(player9, gameInfo.DefaultRating);
var team10 = new Team(player10, gameInfo.DefaultRating);
var team11 = new Team(player11, gameInfo.DefaultRating);
var team12 = new Team(player12, gameInfo.DefaultRating);
var team13 = new Team(player13, gameInfo.DefaultRating);
var team14 = new Team(player14, gameInfo.DefaultRating);
var team15 = new Team(player15, gameInfo.DefaultRating);
var team16 = new Team(player16, gameInfo.DefaultRating);
var newRatings =
calculator.CalculateNewRatings(
gameInfo,
Teams.Concat(
team1, team2, team3, team4, team5,
team6, team7, team8, team9, team10,
team11, team12, team13, team14, team15,
team16),
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
var player1NewRating = newRatings[player1];
AssertRating(40.53945776946920, 5.27581643889050, player1NewRating);
var player2NewRating = newRatings[player2];
AssertRating(36.80951229454210, 4.71121217610266, player2NewRating);
var player3NewRating = newRatings[player3];
AssertRating(34.34726355544460, 4.52440328139991, player3NewRating);
var player4NewRating = newRatings[player4];
AssertRating(32.33614722608720, 4.43258628279632, player4NewRating);
var player5NewRating = newRatings[player5];
AssertRating(30.55048814671730, 4.38010805034365, player5NewRating);
var player6NewRating = newRatings[player6];
AssertRating(28.89277312234790, 4.34859291776483, player6NewRating);
var player7NewRating = newRatings[player7];
AssertRating(27.30952161972210, 4.33037679041216, player7NewRating);
var player8NewRating = newRatings[player8];
AssertRating(25.76571046519540, 4.32197078088701, player8NewRating);
var player9NewRating = newRatings[player9];
AssertRating(24.23428953480470, 4.32197078088703, player9NewRating);
var player10NewRating = newRatings[player10];
AssertRating(22.69047838027800, 4.33037679041219, player10NewRating);
var player11NewRating = newRatings[player11];
AssertRating(21.10722687765220, 4.34859291776488, player11NewRating);
var player12NewRating = newRatings[player12];
AssertRating(19.44951185328290, 4.38010805034375, player12NewRating);
var player13NewRating = newRatings[player13];
AssertRating(17.66385277391300, 4.43258628279643, player13NewRating);
var player14NewRating = newRatings[player14];
AssertRating(15.65273644455550, 4.52440328139996, player14NewRating);
var player15NewRating = newRatings[player15];
AssertRating(13.19048770545810, 4.71121217610273, player15NewRating);
var player16NewRating = newRatings[player16];
AssertRating(9.46054223053080, 5.27581643889032, player16NewRating);
}
//------------------------------------------------------------------------------
// Partial Play Tests
//------------------------------------------------------------------------------
private static void OneOnTwoBalancedPartialPlay(SkillCalculator calculator)
{
var gameInfo = GameInfo.DefaultGameInfo;
var p1 = new Player(1);
var team1 = new Team(p1, gameInfo.DefaultRating);
var p2 = new Player(2, 0.0);
var p3 = new Player(3, 1.00);
var team2 = new Team()
.AddPlayer(p2, gameInfo.DefaultRating)
.AddPlayer(p3, gameInfo.DefaultRating);
var teams = Teams.Concat(team1, team2);
var newRatings = calculator.CalculateNewRatings(gameInfo, teams, 1, 2);
var matchQuality = calculator.CalculateMatchQuality(gameInfo, teams);
}
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
private static void AssertRating(double expectedMean, double expectedStandardDeviation, Rating actual)
{
Assert.AreEqual(expectedMean, actual.Mean, ErrorTolerance);
Assert.AreEqual(expectedStandardDeviation, actual.StandardDeviation, ErrorTolerance);
}
private static void AssertMatchQuality(double expectedMatchQuality, double actualMatchQuality)
{
Assert.AreEqual(expectedMatchQuality, actualMatchQuality, 0.0005);
}
}
}

View File

@ -0,0 +1,20 @@
using Moserware.Skills.TrueSkill;
using NUnit.Framework;
namespace UnitTests.TrueSkill
{
[TestFixture]
public class TwoPlayerTrueSkillCalculatorTest
{
[Test]
public void TwoPlayerTrueSkillCalculatorTests()
{
var calculator = new TwoPlayerTrueSkillCalculator();
// We only support two players
TrueSkillCalculatorTests.TestAllTwoPlayerScenarios(calculator);
// TODO: Assert failures for larger teams
}
}
}

View File

@ -0,0 +1,19 @@
using Moserware.Skills.TrueSkill;
using NUnit.Framework;
namespace UnitTests.TrueSkill
{
[TestFixture]
public class TwoTeamTrueSkillCalculatorTest
{
[Test]
public void TwoTeamTrueSkillCalculatorTests()
{
var calculator = new TwoTeamTrueSkillCalculator();
// This calculator supports up to two teams with many players each
TrueSkillCalculatorTests.TestAllTwoPlayerScenarios(calculator);
TrueSkillCalculatorTests.TestAllTwoTeamScenarios(calculator);
}
}
}

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6F80946D-AC8B-4063-8588-96841C18BF0A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnitTests</RootNamespace>
<AssemblyName>UnitTests</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework, Version=2.5.2.9222, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Elo\DuellingEloTest.cs" />
<Compile Include="Elo\EloAssert.cs" />
<Compile Include="Elo\GaussianEloCalculatorTest.cs" />
<Compile Include="TrueSkill\DrawMarginTest.cs" />
<Compile Include="TrueSkill\FactorGraphTrueSkillCalculatorTests.cs" />
<Compile Include="Elo\FideEloCalculatorTest.cs" />
<Compile Include="Numerics\GaussianDistributionTests.cs" />
<Compile Include="Numerics\MatrixTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RankSorterTest.cs" />
<Compile Include="TrueSkill\TrueSkillCalculatorTests.cs" />
<Compile Include="TrueSkill\TwoPlayerTrueSkillCalculatorTest.cs" />
<Compile Include="TrueSkill\TwoTeamTrueSkillCalculatorTest.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Skills\Skills.csproj">
<Project>{15AD1345-984C-48ED-AF9A-2EAB44E5AA2B}</Project>
<Name>Skills</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="README.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,9 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<StartAction>Program</StartAction>
<StartProgram>C:\Program Files (x86)\NUnit 2.5.2\bin\net-2.0\nunit.exe</StartProgram>
<StartWorkingDirectory>
</StartWorkingDirectory>
<StartArguments>UnitTests.dll</StartArguments>
</PropertyGroup>
</Project>