mirror of
				https://github.com/furyfire/trueskill.git
				synced 2025-11-04 10:12:28 +01:00 
			
		
		
		
	Naming tweak
This commit is contained in:
		
							
								
								
									
										19
									
								
								Skills/Elo/EloRating.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Skills/Elo/EloRating.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace Moserware\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
require_once(dirname(__FILE__) . '/../Rating.php');
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\Rating;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An Elo rating represented by a single number (mean).
 | 
			
		||||
 */
 | 
			
		||||
class EloRating extends Rating
 | 
			
		||||
{
 | 
			
		||||
    public function __construct($rating)        
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($rating, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
?>
 | 
			
		||||
							
								
								
									
										41
									
								
								Skills/Elo/FideEloCalculator.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								Skills/Elo/FideEloCalculator.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Moserware\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
require_once(dirname(__FILE__) . "/FideKFactor.php");
 | 
			
		||||
require_once(dirname(__FILE__) . "/TwoPlayerEloCalculator.php");
 | 
			
		||||
 | 
			
		||||
/** 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, $playerRating, $opponentRating)
 | 
			
		||||
    {
 | 
			
		||||
        $ratingDifference = $opponentRating - $playerRating;
 | 
			
		||||
 | 
			
		||||
        return 1.0
 | 
			
		||||
               /
 | 
			
		||||
               (
 | 
			
		||||
                   1.0 + pow(10.0, $ratingDifference / (2 * $gameInfo->getBeta()))
 | 
			
		||||
               );
 | 
			
		||||
    }        
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
?>
 | 
			
		||||
							
								
								
									
										30
									
								
								Skills/Elo/FideKFactor.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Skills/Elo/FideKFactor.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace Moserware\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
require_once(dirname(__FILE__) . "/KFactor.php");
 | 
			
		||||
 | 
			
		||||
// 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;
 | 
			
		||||
    }    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Indicates someone who has played less than 30 games.
 | 
			
		||||
 */
 | 
			
		||||
class ProvisionalFideKFactor extends FideKFactor
 | 
			
		||||
{
 | 
			
		||||
    public function getValueForRating($rating)
 | 
			
		||||
    {
 | 
			
		||||
        return 25;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
?>
 | 
			
		||||
							
								
								
									
										34
									
								
								Skills/Elo/GaussianEloCalculator.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Skills/Elo/GaussianEloCalculator.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace Moserware\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
require_once(dirname(__FILE__) . "/../GameInfo.php");
 | 
			
		||||
require_once(dirname(__FILE__) . "/../Numerics/GaussianDistribution.php");
 | 
			
		||||
require_once(dirname(__FILE__) . "/KFactor.php");
 | 
			
		||||
require_once(dirname(__FILE__) . "/TwoPlayerEloCalculator.php");
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\GameInfo;
 | 
			
		||||
use Moserware\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()));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
?>
 | 
			
		||||
							
								
								
									
										22
									
								
								Skills/Elo/KFactor.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Skills/Elo/KFactor.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Moserware\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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
?>
 | 
			
		||||
							
								
								
									
										105
									
								
								Skills/Elo/TwoPlayerEloCalculator.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								Skills/Elo/TwoPlayerEloCalculator.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Moserware\Skills\Elo;
 | 
			
		||||
 | 
			
		||||
require_once(dirname(__FILE__) . "/../PairwiseComparison.php");
 | 
			
		||||
require_once(dirname(__FILE__) . "/../RankSorter.php");
 | 
			
		||||
require_once(dirname(__FILE__) . "/../SkillCalculator.php");
 | 
			
		||||
 | 
			
		||||
require_once(dirname(__FILE__) . "/../PlayersRange.php");
 | 
			
		||||
require_once(dirname(__FILE__) . "/../TeamsRange.php");
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\PairwiseComparison;
 | 
			
		||||
use Moserware\Skills\RankSorter;
 | 
			
		||||
use Moserware\Skills\SkillCalculator;
 | 
			
		||||
use Moserware\Skills\SkillCalculatorSupportedOptions;
 | 
			
		||||
 | 
			
		||||
use Moserware\Skills\PlayersRange;
 | 
			
		||||
use Moserware\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,
 | 
			
		||||
                                        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, $playerRating, $opponentRating);
 | 
			
		||||
 | 
			
		||||
    public function calculateMatchQuality($gameInfo, array $teamsOfPlayerToRatings)
 | 
			
		||||
    {
 | 
			
		||||
        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(getPlayerWinProbability($gameInfo, $player1Rating, $player2Rating) - 0.5);
 | 
			
		||||
        return (0.5 - $deltaFrom50Percent) / 0.5;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
?>
 | 
			
		||||
		Reference in New Issue
	
	Block a user