mirror of
				https://github.com/furyfire/trueskill.git
				synced 2025-11-04 10:12:28 +01:00 
			
		
		
		
	PHPUnit version bump and removed ELO
This commit is contained in:
		@@ -6,7 +6,7 @@
 | 
			
		||||
    "php": "^8.1"
 | 
			
		||||
  },
 | 
			
		||||
  "require-dev": {
 | 
			
		||||
    "phpunit/phpunit": "~4.0"
 | 
			
		||||
    "phpunit/phpunit": "^9.0"
 | 
			
		||||
  },
 | 
			
		||||
  "autoload": {
 | 
			
		||||
    "psr-4": {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1674
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1674
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										20
									
								
								phpunit.xml
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								phpunit.xml
									
									
									
									
									
								
							@@ -1,21 +1,13 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<phpunit backupGlobals="false"
 | 
			
		||||
         backupStaticAttributes="false"
 | 
			
		||||
         bootstrap="vendor/autoload.php"
 | 
			
		||||
         colors="true"
 | 
			
		||||
         convertErrorsToExceptions="true"
 | 
			
		||||
         convertNoticesToExceptions="true"
 | 
			
		||||
         convertWarningsToExceptions="true"
 | 
			
		||||
         processIsolation="false"
 | 
			
		||||
         stopOnFailure="false">
 | 
			
		||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false" bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
 | 
			
		||||
  <coverage>
 | 
			
		||||
    <include>
 | 
			
		||||
      <directory suffix=".php">src/</directory>
 | 
			
		||||
    </include>
 | 
			
		||||
  </coverage>
 | 
			
		||||
  <testsuites>
 | 
			
		||||
    <testsuite name="PHPSkills Test Suite">
 | 
			
		||||
      <directory>./tests/</directory>
 | 
			
		||||
    </testsuite>
 | 
			
		||||
  </testsuites>
 | 
			
		||||
    <filter>
 | 
			
		||||
        <whitelist>
 | 
			
		||||
            <directory suffix=".php">src/</directory>
 | 
			
		||||
        </whitelist>
 | 
			
		||||
    </filter>
 | 
			
		||||
</phpunit>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
use DNW\Skills\Rating;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An Elo rating represented by a single number (mean).
 | 
			
		||||
 */
 | 
			
		||||
class EloRating extends Rating
 | 
			
		||||
{
 | 
			
		||||
    public function __construct($rating)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($rating, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
use DNW\Skills\GameInfo;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Including Elo's scheme as a simple comparison.
 | 
			
		||||
 * See http://en.wikipedia.org/wiki/Elo_rating_system#Theory
 | 
			
		||||
 * for more details
 | 
			
		||||
 */
 | 
			
		||||
class FideEloCalculator extends TwoPlayerEloCalculator
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(FideKFactor $kFactor)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($kFactor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function createWithDefaultKFactor()
 | 
			
		||||
    {
 | 
			
		||||
        return new FideEloCalculator(new FideKFactor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function createWithProvisionalKFactor()
 | 
			
		||||
    {
 | 
			
		||||
        return new FideEloCalculator(new ProvisionalFideKFactor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPlayerWinProbability(GameInfo $gameInfo, $playerRating, $opponentRating)
 | 
			
		||||
    {
 | 
			
		||||
        $ratingDifference = $opponentRating - $playerRating;
 | 
			
		||||
 | 
			
		||||
        return 1.0
 | 
			
		||||
        /
 | 
			
		||||
        (
 | 
			
		||||
            1.0 + pow(10.0, $ratingDifference / (2 * $gameInfo->getBeta()))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
// see http://ratings.fide.com/calculator_rtd.phtml for details
 | 
			
		||||
class FideKFactor extends KFactor
 | 
			
		||||
{
 | 
			
		||||
    public function getValueForRating($rating)
 | 
			
		||||
    {
 | 
			
		||||
        if ($rating < 2400) {
 | 
			
		||||
            return 15;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 10;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
use DNW\Skills\GameInfo;
 | 
			
		||||
use DNW\Skills\Numerics\GaussianDistribution;
 | 
			
		||||
 | 
			
		||||
class GaussianEloCalculator extends TwoPlayerEloCalculator
 | 
			
		||||
{
 | 
			
		||||
    // From the paper
 | 
			
		||||
    const STABLE_KFACTOR = 24;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(new KFactor(self::STABLE_KFACTOR));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPlayerWinProbability(GameInfo $gameInfo, $playerRating, $opponentRating)
 | 
			
		||||
    {
 | 
			
		||||
        $ratingDifference = $playerRating - $opponentRating;
 | 
			
		||||
 | 
			
		||||
        // See equation 1.1 in the TrueSkill paper
 | 
			
		||||
        return GaussianDistribution::cumulativeTo(
 | 
			
		||||
            $ratingDifference
 | 
			
		||||
            /
 | 
			
		||||
            (sqrt(2) * $gameInfo->getBeta())
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,18 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
class KFactor
 | 
			
		||||
{
 | 
			
		||||
    const DEFAULT_KFACTOR = 24;
 | 
			
		||||
 | 
			
		||||
    private $_value;
 | 
			
		||||
 | 
			
		||||
    public function __construct($exactKFactor = self::DEFAULT_KFACTOR)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_value = $exactKFactor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getValueForRating($rating)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_value;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Indicates someone who has played less than 30 games.
 | 
			
		||||
 */
 | 
			
		||||
class ProvisionalFideKFactor extends FideKFactor
 | 
			
		||||
{
 | 
			
		||||
    public function getValueForRating($rating)
 | 
			
		||||
    {
 | 
			
		||||
        return 25;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,93 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use DNW\Skills\GameInfo;
 | 
			
		||||
use DNW\Skills\PairwiseComparison;
 | 
			
		||||
use DNW\Skills\RankSorter;
 | 
			
		||||
use DNW\Skills\SkillCalculator;
 | 
			
		||||
use DNW\Skills\SkillCalculatorSupportedOptions;
 | 
			
		||||
use DNW\Skills\PlayersRange;
 | 
			
		||||
use DNW\Skills\TeamsRange;
 | 
			
		||||
 | 
			
		||||
abstract class TwoPlayerEloCalculator extends SkillCalculator
 | 
			
		||||
{
 | 
			
		||||
    protected $_kFactor;
 | 
			
		||||
 | 
			
		||||
    protected function __construct(KFactor $kFactor)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct(SkillCalculatorSupportedOptions::NONE, TeamsRange::exactly(2), PlayersRange::exactly(1));
 | 
			
		||||
        $this->_kFactor = $kFactor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function calculateNewRatings(GameInfo $gameInfo, array $teamsOfPlayerToRatings, array $teamRanks)
 | 
			
		||||
    {
 | 
			
		||||
        $this->validateTeamCountAndPlayersCountPerTeam($teamsOfPlayerToRatings);
 | 
			
		||||
        RankSorter::sort($teamsOfPlayerToRatings, $teamRanks);
 | 
			
		||||
 | 
			
		||||
        $result = array();
 | 
			
		||||
        $isDraw = ($teamRanks[0] === $teamRanks[1]);
 | 
			
		||||
 | 
			
		||||
        $team1 = $teamsOfPlayerToRatings[0];
 | 
			
		||||
        $team2 = $teamsOfPlayerToRatings[1];
 | 
			
		||||
 | 
			
		||||
        $player1 = each($team1);
 | 
			
		||||
        $player2 = each($team2);
 | 
			
		||||
 | 
			
		||||
        $player1Rating = $player1["value"]->getMean();
 | 
			
		||||
        $player2Rating = $player2["value"]->getMean();
 | 
			
		||||
 | 
			
		||||
        $result[$player1["key"]] = $this->calculateNewRating($gameInfo, $player1Rating, $player2Rating, $isDraw ? PairwiseComparison::DRAW : PairwiseComparison::WIN);
 | 
			
		||||
        $result[$player2["key"]] = $this->calculateNewRating($gameInfo, $player2Rating, $player1Rating, $isDraw ? PairwiseComparison::DRAW : PairwiseComparison::LOSE);
 | 
			
		||||
 | 
			
		||||
        return $result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function calculateNewRating($gameInfo, $selfRating, $opponentRating, $selfToOpponentComparison)
 | 
			
		||||
    {
 | 
			
		||||
        $expectedProbability = $this->getPlayerWinProbability($gameInfo, $selfRating, $opponentRating);
 | 
			
		||||
        $actualProbability = $this->getScoreFromComparison($selfToOpponentComparison);
 | 
			
		||||
        $k = $this->_kFactor->getValueForRating($selfRating);
 | 
			
		||||
        $ratingChange = $k * ($actualProbability - $expectedProbability);
 | 
			
		||||
        $newRating = $selfRating + $ratingChange;
 | 
			
		||||
 | 
			
		||||
        return new EloRating($newRating);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function getScoreFromComparison($comparison)
 | 
			
		||||
    {
 | 
			
		||||
        switch ($comparison)
 | 
			
		||||
        {
 | 
			
		||||
            case PairwiseComparison::WIN:
 | 
			
		||||
                return 1;
 | 
			
		||||
            case PairwiseComparison::DRAW:
 | 
			
		||||
                return 0.5;
 | 
			
		||||
            case PairwiseComparison::LOSE:
 | 
			
		||||
                return 0;
 | 
			
		||||
            default:
 | 
			
		||||
                throw new Exception("Unexpected comparison");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public abstract function getPlayerWinProbability(GameInfo $gameInfo, $playerRating, $opponentRating);
 | 
			
		||||
 | 
			
		||||
    public function calculateMatchQuality(GameInfo $gameInfo, array $teamsOfPlayerToRatings)
 | 
			
		||||
    {
 | 
			
		||||
        $this->validateTeamCountAndPlayersCountPerTeam($teamsOfPlayerToRatings);
 | 
			
		||||
        $team1 = $teamsOfPlayerToRatings[0];
 | 
			
		||||
        $team2 = $teamsOfPlayerToRatings[1];
 | 
			
		||||
 | 
			
		||||
        $player1 = $team1[0];
 | 
			
		||||
        $player2 = $team2[0];
 | 
			
		||||
 | 
			
		||||
        $player1Rating = $player1[1]->getMean();
 | 
			
		||||
        $player2Rating = $player2[1]->getMean();
 | 
			
		||||
 | 
			
		||||
        $ratingDifference = $player1Rating - $player2Rating;
 | 
			
		||||
 | 
			
		||||
        // The TrueSkill paper mentions that they used s1 - s2 (rating difference) to
 | 
			
		||||
        // determine match quality. I convert that to a percentage as a delta from 50%
 | 
			
		||||
        // using the cumulative density function of the specific curve being used
 | 
			
		||||
        $deltaFrom50Percent = abs($this->getPlayerWinProbability($gameInfo, $player1Rating, $player2Rating) - 0.5);
 | 
			
		||||
        return (0.5 - $deltaFrom50Percent) / 0.5;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -57,10 +57,6 @@ class Player implements ISupportPartialPlay, ISupportPartialUpdate
 | 
			
		||||
 | 
			
		||||
    public function __toString()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->_Id != null) {
 | 
			
		||||
        return (string)$this->_Id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        return parent::__toString();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,43 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Tests\Elo;
 | 
			
		||||
 | 
			
		||||
use DNW\Skills\Elo\EloRating;
 | 
			
		||||
use DNW\Skills\Elo\FideEloCalculator;
 | 
			
		||||
use DNW\Skills\GameInfo;
 | 
			
		||||
use DNW\Skills\PairwiseComparison;
 | 
			
		||||
use DNW\Skills\Tests\TestCase;
 | 
			
		||||
 | 
			
		||||
class EloAssert
 | 
			
		||||
{
 | 
			
		||||
    const ERROR_TOLERANCE = 0.1;
 | 
			
		||||
 | 
			
		||||
    public static function assertChessRating(
 | 
			
		||||
        TestCase $testClass,
 | 
			
		||||
        FideEloCalculator $twoPlayerEloCalculator,
 | 
			
		||||
        $player1BeforeRating,
 | 
			
		||||
        $player2BeforeRating,
 | 
			
		||||
        $player1Result,
 | 
			
		||||
        $player1AfterRating,
 | 
			
		||||
        $player2AfterRating)
 | 
			
		||||
    {
 | 
			
		||||
        $player1 = "Player1";
 | 
			
		||||
        $player2 = "Player2";
 | 
			
		||||
 | 
			
		||||
        $teams = array(
 | 
			
		||||
            array($player1 => new EloRating($player1BeforeRating)),
 | 
			
		||||
            array($player2 => new EloRating($player2BeforeRating))
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $chessGameInfo = new GameInfo(1200, 0, 200);
 | 
			
		||||
 | 
			
		||||
        $ranks = PairwiseComparison::getRankFromComparison($player1Result);
 | 
			
		||||
 | 
			
		||||
        $result = $twoPlayerEloCalculator->calculateNewRatings(
 | 
			
		||||
            $chessGameInfo,
 | 
			
		||||
            $teams,
 | 
			
		||||
            $ranks
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $testClass->assertEquals($player1AfterRating, $result[$player1]->getMean(), '', self::ERROR_TOLERANCE);
 | 
			
		||||
        $testClass->assertEquals($player2AfterRating, $result[$player2]->getMean(), '', self::ERROR_TOLERANCE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
<?php namespace DNW\Skills\Tests\Elo;
 | 
			
		||||
 | 
			
		||||
use DNW\Skills\Elo\FideEloCalculator;
 | 
			
		||||
use DNW\Skills\Elo\ProvisionalFideKFactor;
 | 
			
		||||
use DNW\Skills\PairwiseComparison;
 | 
			
		||||
use DNW\Skills\Tests\TestCase;
 | 
			
		||||
 | 
			
		||||
class FideEloCalculatorTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    public function testFideProvisionalEloCalculator()
 | 
			
		||||
    {
 | 
			
		||||
        // verified against http://ratings.fide.com/calculator_rtd.phtml
 | 
			
		||||
        $calc = new FideEloCalculator(new ProvisionalFideKFactor());
 | 
			
		||||
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 1200, 1500, PairwiseComparison::WIN, 1221.25, 1478.75);
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 1200, 1500, PairwiseComparison::DRAW, 1208.75, 1491.25);
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 1200, 1500, PairwiseComparison::LOSE, 1196.25, 1503.75);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFideNonProvisionalEloCalculator()
 | 
			
		||||
    {
 | 
			
		||||
        // verified against http://ratings.fide.com/calculator_rtd.phtml
 | 
			
		||||
        $calc = FideEloCalculator::createWithDefaultKFactor();
 | 
			
		||||
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 1200, 1200, PairwiseComparison::WIN, 1207.5, 1192.5);
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 1200, 1200, PairwiseComparison::DRAW, 1200, 1200);
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 1200, 1200, PairwiseComparison::LOSE, 1192.5, 1207.5);
 | 
			
		||||
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 2600, 2500, PairwiseComparison::WIN, 2603.6, 2496.4);
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 2600, 2500, PairwiseComparison::DRAW, 2598.6, 2501.4);
 | 
			
		||||
        EloAssert::assertChessRating($this, $calc, 2600, 2500, PairwiseComparison::LOSE, 2593.6, 2506.4);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<?php namespace DNW\Skills\Tests;
 | 
			
		||||
 | 
			
		||||
class TestCase extends \PHPUnit_Framework_TestCase
 | 
			
		||||
class TestCase extends \PHPUnit\Framework\TestCase
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user