TrueSkill™ is a rating system among game players. It has been used on Xbox Live to rank and match players. TrueSkill system quantizes “TRUE” skill points by a Bayesian inference algorithm.
This project is a Python package which implements TrueSkill™ rating system.
Install via PyPI with easy_install or pip command:
$ easy_install trueskill
$ pip install trueskill
or check out development version:
$ git clone git://github.com/sublee/trueskill.git
Let’s suppose that our sample game is 2v1. Rating objects mean each game players’ skill points:
>>> from trueskill import Rating
>>> r1, r2, r3 = Rating(), Rating(), Rating()
>>> team1 = (r1, r2)
>>> team2 = (r3,)
TrueSkill system uses Gaussian distribution as player’s skill point. The initial mu (\(\mu\); mean) of rating is 25 and the initial sigma (\(\sigma\); standard deviation) is \(\frac{ 25 }{ 3 } \approx 8.333\):
>>> [team1, team2]
[(
Rating(mu=25.000, sigma=8.333),
Rating(mu=25.000, sigma=8.333)
), (
Rating(mu=25.000, sigma=8.333)
)]
The first team has won the game. See the below transformation of the ratings:
>>> from trueskill import transform_ratings
>>> transform_ratings([team1, team2])
[(
Rating(mu=25.604, sigma=8.075),
Rating(mu=25.604, sigma=8.075)
), (
Rating(mu=24.396, sigma=8.075)
)]
The mu values in the first team transform from 25.000 to 25.604 and in the second team transform from 25.000 to 24.396. The ratings were transformed just a little. But, how does it work if the second team player has beaten 2 players in the first team, by himself?
>>> transform_ratings([team1, team2], ranks=[1, 0]) # reversed ranks
[(
Rating(mu=16.269, sigma=7.317),
Rating(mu=16.269, sigma=7.317)
), (
Rating(mu=33.731, sigma=7.317)
)]
In the first team, 25.000 to 16.269 and in the second team 25.000 to 33.731. Now we have large transformations because it is a surprising result that 1 player beats 2 players.
It is just a simplest example. TrueSkill can estimate accurate skills in this way. We only need enough game results!
We also can calculate the fairness of any games with match_quality() function:
>>> from trueskill import match_quality
>>> match_quality([team1, team2])
0.1346981464530322
The result shows that the probability of a draw game is 13.47%. Let’s see another result of a really fair game:
>>> match_quality([(Rating(25, 0.001),), (Rating(25, 0.001),)])
0.9999999712000012
A much exact skill point follows very low sigma value such as the above ratings (\(\sigma=0.001\)). Very low sigma value indicates that the rating is much more precise. Also, because of the same ratings, TrueSkill assures a draw of this game, a super-fair game.
This feature would help you implement a fair match making system.
A skill point is a numeric representation of a player’s ability. Someday, this value will be convergent to the value that’s exactly we are finding. But the value can be a less than the initial value (\(\mu=25\)). To prevent players from despairing by knowing their own rating directly, we need to deceive our players into growing up in general.
Okay, enough for the reason but how? Just use Rating.exposure property:
$$ E = \mu - 3\sigma $$
>>> Rating().exposure
0.0
>>> Rating(mu=24, sigma=7).exposure # mu -= 1
2.9999999999999964
>>> Rating(mu=22, sigma=6).exposure # mu -= 2
4.0
>>> Rating(mu=26, sigma=5).exposure # mu += 4
11.0
An exposure value starts from 0 instead of 25. It can decrease sometimes but the growth graph will go up on the whole.
Implements a TrueSkill environment. An environment could have customized constants. Every games have not same design and may need to customize TrueSkill constants. For example, 60% of matches in your game have finished as draw then you should set draw_probability to 0.60.
>>> my_env = TrueSkill(draw_probability=0.60)
| Parameters: |
|
|---|
For more details of the constants, see The Math Behind TrueSkill.
Initializes new Rating object, but it fixes default mu and sigma to the environment’s.
>>> env = TrueSkill(mu=0, sigma=1)
>>> env.Rating()
Rating(mu=0.000, sigma=1.000)
Calculates transformed ratings from the given rating groups by the ranking table.
rating_groups is a list of rating tuples that correspond each team of the match. ranks is rakings of the teams that can be omitted if the ranking is same as the order of rating_groups.
>>> env = TrueSkill()
>>> team1 = (env.Rating(20), env.Rating(21)) # winner
>>> team2 = (env.Rating(22), env.Rating(23)) # loser
>>> env.transform_ratings(rating_groups=[team1, team2])
...
[(Rating(mu=23.645, sigma=7.736), Rating(mu=24.645, sigma=7.736)),
(Rating(mu=18.355, sigma=7.736), Rating(mu=19.355, sigma=7.736))]
You can replace the old ratings like:
>>> (team1, team2) = tuple(env.transform_ratings([team1, team2]))
>>> team1[0]
Rating(mu=23.645, sigma=7.736)
| Parameters: |
|
|---|
Calculates the match quality of the given rating groups. A result is the draw probability in the association.
>>> env = TrueSkill()
>>> env.match_quality([(env.Rating(25, 0.001),),
... (env.Rating(25, 0.001),)])
0.9999999712000012
| Parameters: | rating_groups – a list of tuples that contain Rating objects |
|---|
A proxy function for TrueSkill.transform_ratings() of the global TrueSkill environment.
A proxy function for TrueSkill.match_quality() of the global TrueSkill environment.
Setups the global TrueSkill environment.
>>> Rating()
Rating(mu=25.000, sigma=8.333)
>>> setup(mu=50)
<TrueSkill mu=50...>
>>> Rating()
Rating(mu=50.000, sigma=8.333)
default initial mean of ratings
default initial standard deviation of ratings
default guarantee about an 80% chance of winning
default dynamic factor
default draw probability of the game
If you want to more details of the TrueSkill algorithm, see also:
This project licensed with BSD, so feel free to use and manipulate as long as you respect these licenses. See LICENSE for the details.
I’m Heungsub Lee, a game developer. Any regarding questions or patches are welcomed.