diff --git a/CHANGELOG.md b/CHANGELOG.md index ed8f2a7..dec6882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This is a broad overview of the changes that have been made over the lifespan of this library. +## v0.10.1 - 2022-08-25 + +- Overhauled documentation + ## v0.10.0 - 2022-08-24 - Add team calculations for TrueSkill diff --git a/Cargo.toml b/Cargo.toml index 605fc22..fcffa33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "skillratings" -version = "0.10.0" +version = "0.10.1" edition = "2021" description = "Calculate a player's skill rating using Elo, DWZ, Ingo, TrueSkill, Glicko and Glicko-2 algorithms." readme= "README.md" diff --git a/README.md b/README.md index 0f3bdb4..d152c4d 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Add the following to your `Cargo.toml` file: ```toml [dependencies] -skillratings = "0.10.0" +skillratings = "0.10.1" ``` ## Basic Usage diff --git a/src/config.rs b/src/config.rs index 1536489..9b966c5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,9 @@ +//! Contains structs to configure key variables used in the different rating algorithms. + /// Constants used in the `Elo` calculation. pub struct EloConfig { /// The k-value is the maximum amount of rating change from a single match. - /// In chess, k-values from 40 to 10 are used, with the most common being 32, 24 or 16. + /// In chess, k-values from 40 to 10 are used, with the most common being 32, 24, 16 or 10. /// The higher the number, the more volatile the ranking. /// Here the default is 32. pub k: f64, diff --git a/src/dwz.rs b/src/dwz.rs index dfbe829..616984d 100644 --- a/src/dwz.rs +++ b/src/dwz.rs @@ -1,11 +1,27 @@ +//! The DWZ (Deutsche Wertungszahl) algorithm used in the german chess leagues alongside Elo. +//! DWZ continues to be enhanced over the years, while having similar scores to Elo. +//! +//! DWZ allows young players to rise and fall in the ranks more quickly, while more experienced players ratings are slower to change. +//! Overachieving players gain more rating while underperforming weak players do not lose rating points as quickly. +//! +//! These factors make DWZ more dynamic than Elo while producing accurate ratings more quickly. +//! +//! # More Information +//! +//! - [Wikipedia Article](https://en.wikipedia.org/wiki/Deutsche_Wertungszahl) +//! - [DWZ Calculator (German)](http://www.wertungszahl.de/) +//! - [DWZ Top 100 Ratings](https://www.schachbund.de/top-100.html) +//! - [Official DWZ scoring system rules (German)](https://www.schachbund.de/wertungsordnung.html) +//! - [Probability Table](https://www.schachbund.de/wertungsordnung-anhang-2-tabellen/articles/wertungsordnung-anhang-21-wahrscheinlichkeitstabelle.html) + use std::collections::HashMap; use crate::{outcomes::Outcomes, rating::DWZRating}; #[must_use] -/// Calculates the DWZ (Deutsche Wertungszahl) ratings of two players based on their ratings, index, age and outcome of the game. +/// Calculates new [`DWZRating`] of two players based on their old rating, index, age and outcome of the game. /// -/// Takes in two players and the outcome of the game. +/// Takes in two players as [`DWZRating`]s and an [`Outcome`](Outcomes). /// /// Instead of the traditional way of calculating the DWZ for only one player only using a list of results, /// we are calculating the DWZ rating for two players at once, like in the Elo calculation, @@ -15,9 +31,9 @@ use crate::{outcomes::Outcomes, rating::DWZRating}; /// To get a first DWZ rating, please see [`get_first_dwz`]. /// /// The outcome of the match is in the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// This means [`Outcomes::WIN`] is a win for `player_one` and [`Outcomes::LOSS`] is a win for `player_two`. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{dwz::dwz, outcomes::Outcomes, rating::DWZRating}; /// @@ -105,12 +121,13 @@ pub fn dwz( #[must_use] /// The "traditional" way of calculating a DWZ Rating of a player in a rating period or tournament. /// -/// Takes in a player and their results as a Vec of tuples containing the opponent and the outcome. +/// Takes in a player as an [`DWZRating`] and their results as a Vec of tuples containing the opponent as an [`DWZRating`] +/// and the outcome of the game as an [`Outcome`](Outcomes). /// -/// All of the outcomes are from the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// All of the outcomes are from the perspective of the player. +/// This means [`Outcomes::WIN`] is a win for the player and [`Outcomes::LOSS`] is a win for the opponent. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{dwz::dwz_rating_period, outcomes::Outcomes, rating::DWZRating}; /// @@ -175,11 +192,11 @@ pub fn dwz_rating_period(player: DWZRating, results: &Vec<(DWZRating, Outcomes)> #[must_use] /// Calculates the expected outcome of two players based on DWZ. /// -/// Takes in two players and returns the probability of victory for each player. +/// Takes in two players as [`DWZRating`]s and returns the probability of victory for each player as an [`f64`] between 1.0 and 0.0. /// 1.0 means a certain victory for the player, 0.0 means certain loss. /// Values near 0.5 mean a draw is likely to occur. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{dwz::expected_score, rating::DWZRating}; /// @@ -211,18 +228,18 @@ pub fn expected_score(player_one: DWZRating, player_two: DWZRating) -> (f64, f64 #[allow(clippy::as_conversions, clippy::cast_precision_loss)] #[must_use] -/// Gets a proper first DWZ rating. +/// Gets a proper first [`DWZRating`]. /// -/// If you do not have enough opponents, and have an [`crate::rating::EloRating`] -/// consider using `DWZRating::from(EloRating { ... })`. +/// If you do not have enough opponents, and have an [`EloRating`](crate::rating::EloRating) +/// consider using [`DWZRating::from()`](DWZRating#impl-From). /// /// Takes in the player's age and their results as a Vec of tuples containing the opponent and the outcome. /// If the actual player's age is unavailable or unknown, choose something `>25`. /// /// This only returns a DWZ rating if the results include at least 5 matches, -/// and you don't have a 100% or a 0% win record. Otherwise it will return `None`. +/// and you don't have a 100% or a 0% win record. Otherwise it will return [`None`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{dwz::get_first_dwz, outcomes::Outcomes, rating::DWZRating}; /// diff --git a/src/elo.rs b/src/elo.rs index 100508c..8552b97 100644 --- a/src/elo.rs +++ b/src/elo.rs @@ -1,13 +1,26 @@ +//! he Elo algorithm, the most widespread rating system and the gold-standard in chess and other games. +//! Used in the official FIDE chess ratings, FIFA World Rankings, and many online video games. +//! +//! The higher the Elo rating number, the stronger the player. +//! Compared to other rating algorithms, Elo ratings are relatively static, but very transparent and simple to calculate. +//! +//! # More Information +//! +//! - [Wikipedia Article](https://en.wikipedia.org/wiki/Elo_rating_system) +//! - [Elo Calculator](https://www.omnicalculator.com/sports/elo) +//! - [FIDE Ratings](https://ratings.fide.com/) +//! - [FIFA Ratings](https://www.fifa.com/fifa-world-ranking) + use crate::{config::EloConfig, outcomes::Outcomes, rating::EloRating}; -/// Calculates the elo scores of two players based on their ratings and the outcome of the game. +/// Calculates the [`EloRating`]s of two players based on their old ratings and the outcome of the game. /// -/// Takes in two players, the outcome of the game and an [`EloConfig`]. +/// Takes in two players as [`EloRating`]s, an [`Outcome`](Outcomes) and an [`EloConfig`]. /// /// The outcome of the match is in the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// This means [`Outcomes::WIN`] is a win for `player_one` and [`Outcomes::LOSS`] is a win for `player_two`. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{elo::elo, outcomes::Outcomes, rating::EloRating, config::EloConfig}; /// @@ -25,7 +38,8 @@ use crate::{config::EloConfig, outcomes::Outcomes, rating::EloRating}; /// ``` /// /// # More -/// [Wikipedia Article on the Elo system](https://en.wikipedia.org/wiki/Elo_rating_system). +/// [Wikipedia Article on the Elo system](https://en.wikipedia.org/wiki/Elo_rating_system) +/// [Elo Calculator](https://www.omnicalculator.com/sports/elo) #[must_use] pub fn elo( player_one: EloRating, @@ -56,15 +70,16 @@ pub fn elo( ) } -/// Calculates a Elo Rating in a non-traditional way using a rating period, +/// Calculates an [`EloRating`] in a non-traditional way using a rating period, /// for compatibility with the other algorithms. /// -/// Takes in a player and their results as a Vec of tuples containing the opponent and the outcome. +/// Takes in a player as an [`EloRating`] and their results as a Vec of tuples containing the opponent as an [`EloRating`] +/// and the outcome of the game as an [`Outcome`](Outcomes). /// -/// All of the outcomes are from the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// All of the outcomes are from the perspective of the player. +/// This means [`Outcomes::WIN`] is a win for the player and [`Outcomes::LOSS`] is a win for the opponent. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{elo::elo_rating_period, outcomes::Outcomes, rating::EloRating, config::EloConfig}; /// @@ -112,10 +127,11 @@ pub fn elo_rating_period( /// Calculates the expected score of two players based on their elo rating. /// Meant for usage in the elo function, but you can also use it to predict games yourself. /// -/// Takes in two elo scores and returns the expected score of each player. -/// A score of 1.0 means certain win, a score of 0.0 means certain loss, and a score of 0.5 is a draw. +/// Takes in two players as [`EloRating`]s and returns the probability of victory for each player as an [`f64`] between 1.0 and 0.0. +/// 1.0 means a certain victory for the player, 0.0 means certain loss. +/// Values near 0.5 mean a draw is likely to occur. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{elo::expected_score, rating::EloRating}; /// diff --git a/src/glicko.rs b/src/glicko.rs index 7f428c1..c7cc21e 100644 --- a/src/glicko.rs +++ b/src/glicko.rs @@ -1,12 +1,28 @@ +//! The Glicko algorithm, developed by Mark Glickman as an improvement on Elo. +//! It is still being used in some games in favor Glicko-2, such as Pokémon Showdown and Quake Live. +//! +//! For Glicko-2, please see [`crate::glicko2`]. +//! +//! The main improvement over Elo is the rating deviation introduced, +//! which decreases over time as the player plays more matches and the rating becomes more reliable. +//! This allows players to rise and fall through the ranks quickly at the beginning, +//! and not gain or lose as much rating points after completing more matches. +//! +//! # More Information +//! +//! - [Wikipedia Article](https://en.wikipedia.org/wiki/Glicko_rating_system) +//! - [Original Paper by Mark Glickman](http://www.glicko.net/glicko/glicko.pdf) +//! - [Glicko Calculator](http://www.bjcox.com/?page_id=2) + use crate::{config::GlickoConfig, outcomes::Outcomes, rating::GlickoRating}; use std::f64::consts::PI; #[must_use] -/// Calculates the glicko scores of two players based on their ratings, deviations, and the outcome of the game. +/// Calculates the [`GlickoRating`]s of two players based on their old ratings, deviations, and the outcome of the game. /// /// Please see [`crate::glicko2::glicko2`] for calculating with the improved version. /// -/// Takes in two players and the outcome of the game. +/// Takes in two players as [`GlickoRating`]s, and an [`Outcome`](Outcomes). /// /// Instead of the traditional way of calculating the Glicko for only one player only using a list of results, /// we are calculating the Glicko rating for two players at once, like in the Elo calculation, @@ -15,9 +31,9 @@ use std::f64::consts::PI; /// For the traditional way of calculating a Glicko rating please see [`glicko_rating_period`]. /// /// The outcome of the match is in the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// This means [`Outcomes::WIN`] is a win for `player_one` and [`Outcomes::LOSS`] is a win for `player_two`. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{glicko::glicko, outcomes::Outcomes, rating::GlickoRating}; /// @@ -101,16 +117,17 @@ pub fn glicko( ) } -/// The "traditional" way of calculating a Glicko Rating of a player in a rating period. +/// The "traditional" way of calculating a [`GlickoRating`] of a player in a rating period. /// -/// Takes in a player, their results as a Vec of tuples containing the opponent and the outcome, and a [`GlickoConfig`]. +/// Takes in a player as an [`GlickoRating`] and their results as a Vec of tuples containing the opponent as an [`GlickoRating`], +/// the outcome of the game as an [`Outcome`](Outcomes) and a [`GlickoConfig`]. /// -/// All of the outcomes are from the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// The outcome of the match is in the perspective of the player. +/// This means [`Outcomes::WIN`] is a win for the player and [`Outcomes::LOSS`] is a win for the opponent. /// /// If the player's results are empty, the player's rating deviation will automatically be decayed using [`decay_deviation`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{glicko::glicko_rating_period, outcomes::Outcomes, rating::GlickoRating, config::GlickoConfig}; /// @@ -192,11 +209,11 @@ pub fn glicko_rating_period( #[must_use] /// Calculates the expected outcome of two players based on glicko. /// -/// Takes in two players and returns the probability of victory for each player. +/// Takes in two players as [`GlickoRating`]s and returns the probability of victory for each player as an [`f64`] between 1.0 and 0.0. /// 1.0 means a certain victory for the player, 0.0 means certain loss. /// Values near 0.5 mean a draw is likely to occur. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{glicko::expected_score, rating::GlickoRating}; /// @@ -227,9 +244,9 @@ pub fn expected_score(player_one: GlickoRating, player_two: GlickoRating) -> (f6 /// /// The length of the rating period and thus the number of missed periods per player is something to decide and track yourself. /// -/// Takes in a player and a [`GlickoConfig`], that describes how much the rating should change. +/// Takes in a player as a [`GlickoRating`] and a [`GlickoConfig`], that describes how much the rating should change, and returns the decayed [`GlickoRating`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{glicko::decay_deviation, rating::GlickoRating, config::GlickoConfig}; /// @@ -258,7 +275,9 @@ pub fn decay_deviation(player: GlickoRating, config: &GlickoConfig) -> GlickoRat /// /// The system is 95% sure that the "true skill" of the player is in-between these values. /// -/// # Example +/// Takes in a player as a [`GlickoRating`] and returns two [`f64`]s that describe the lowest and highest rating. +/// +/// # Examples /// ```rust /// use skillratings::{rating::GlickoRating, glicko::confidence_interval}; /// diff --git a/src/glicko2.rs b/src/glicko2.rs index 2434d07..0cc7314 100644 --- a/src/glicko2.rs +++ b/src/glicko2.rs @@ -1,9 +1,25 @@ +//! The Glicko-2 algorithm, an improvement on Glicko and widely used in online games, +//! like Counter Strike: Global Offensive, Team Fortress 2, Splatoon 2 and most online chess platforms. +//! +//! //! For Glicko, please see [`crate::glicko`]. +//! +//! The main improvement over Glicko is the rating volatility which is the expected fluctuation of a players rating, +//! based on how consistent a player is performing. The lower the volatility, the more consistent a player performs. +//! +//! # More Information +//! +//! - [Wikipedia Article](https://en.wikipedia.org/wiki/Glicko_rating_system) +//! - [Original Paper by Mark Glickman](http://www.glicko.net/glicko/glicko2.pdf) +//! - [Glicko-2 Calculator](https://fsmosca-glicko2calculator-glicko2calculator-vik8k0.streamlitapp.com/) + use crate::{config::Glicko2Config, outcomes::Outcomes, rating::Glicko2Rating}; use std::f64::consts::PI; -/// Calculates the glicko-2 scores of two players based on their ratings, deviations, and the outcome of the game. +/// Calculates the [`Glicko2Rating`]s of two players based on their old ratings, deviations, volatilities, and the outcome of the game. +/// +/// For the original version, please see [`crate::glicko::glicko`]. /// -/// Takes in two players, the outcome of the game and a [`Glicko2Config`]. +/// Takes in two players as [`Glicko2Rating`]s, an [`Outcome`](Outcomes), and a [`Glicko2Config`]. /// /// Instead of the traditional way of calculating the Glicko-2 for only one player only using a list of results, /// we are calculating the Glicko-2 rating for two players at once, like in the Elo calculation, @@ -12,9 +28,9 @@ use std::f64::consts::PI; /// For the traditional way of calculating a Glicko-2 rating please see [`glicko2_rating_period`]. /// /// The outcome of the match is in the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// This means [`Outcomes::WIN`] is a win for `player_one` and [`Outcomes::LOSS`] is a win for `player_two`. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{glicko2::glicko2, outcomes::Outcomes, rating::Glicko2Rating, config::Glicko2Config}; /// @@ -123,16 +139,17 @@ pub fn glicko2( (player_one_new, player_two_new) } -/// The "traditional" way of calculating a Glicko-2 Rating of a player in a rating period. +/// The "traditional" way of calculating a [`Glicko2Rating`] of a player in a rating period. /// -/// Takes in a player, their results as a Vec of tuples containing the opponent and the outcome, and a [`Glicko2Config`]. +/// Takes in a player as an [`Glicko2Rating`] and their results as a Vec of tuples containing the opponent as an [`Glicko2Rating`], +/// the outcome of the game as an [`Outcome`](Outcomes) and a [`Glicko2Config`]. /// -/// All of the outcomes are from the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// The outcome of the match is in the perspective of the player. +/// This means [`Outcomes::WIN`] is a win for the player and [`Outcomes::LOSS`] is a win for the opponent. /// /// If the player's results are empty, the player's rating deviation will automatically be decayed using [`decay_deviation`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{glicko2::glicko2_rating_period, outcomes::Outcomes, rating::Glicko2Rating, config::Glicko2Config}; /// @@ -229,11 +246,11 @@ pub fn glicko2_rating_period( /// Calculates the expected outcome of two players based on glicko-2. /// -/// Takes in two players and returns the probability of victory for each player. +/// Takes in two players as [`Glicko2Rating`]s and returns the probability of victory for each player as an [`f64`] between 1.0 and 0.0. /// 1.0 means a certain victory for the player, 0.0 means certain loss. /// Values near 0.5 mean a draw is likely to occur. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{glicko2::expected_score, rating::Glicko2Rating}; /// @@ -284,9 +301,9 @@ pub fn expected_score(player_one: Glicko2Rating, player_two: Glicko2Rating) -> ( /// /// The length of the rating period and thus the number of missed periods per player is something to decide and track yourself. /// -/// Takes in a player and returns the player with the Rating Deviation Value adjusted. +/// Takes in a player as a [`Glicko2Rating`] and returns the decayed [`Glicko2Rating`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{glicko2::decay_deviation, rating::Glicko2Rating}; /// @@ -317,7 +334,9 @@ pub fn decay_deviation(player: Glicko2Rating) -> Glicko2Rating { /// /// The system is 95% sure that the "true skill" of the player is inbetween these values. /// -/// # Example +/// Takes in a player as a [`Glicko2Rating`] and returns two [`f64`]s that describe the lowest and highest rating. +/// +/// # Examples /// ```rust /// use skillratings::{rating::Glicko2Rating, glicko2::confidence_interval}; /// diff --git a/src/ingo.rs b/src/ingo.rs index 6928ced..ae0c5c1 100644 --- a/src/ingo.rs +++ b/src/ingo.rs @@ -1,21 +1,35 @@ +//! The Ingo algorithm, the predecessor of DWZ and one of the first rating algorihms invented in 1947. +//! Sometimes still used in Xiangqi ("Chinese Chess"). +//! +//! Unlike with the other rating systems, with Ingo a lower rating is more desirable, +//! and negative values are possible, though unlikely. +//! A player with an Ingo rating of 0 has an equivalent Elo rating of 2840, and an Ingo rating of -1 equals 2848 Elo. +//! +//! +//! # More Information +//! +//! - [Wikipedia Article (German, no english version available)](https://de.wikipedia.org/wiki/Ingo-Zahl) +//! - [Archive of Ingo Ratings (German)](https://www.schachbund.de/ingo-spiegel.html) +//! - [Ingo Rules (German, PDF Download)](https://www.schachbund.de/ingo-spiegel.html?file=files/dsb/historie/ingo-spiegel/Ingo-Regeln.pdf&cid=28120) + use crate::{outcomes::Outcomes, rating::IngoRating}; #[must_use] -/// Calculates the Ingo ratings of two players based on their ratings, and the outcome of the game. +/// Calculates the [`IngoRating`]s of two players based on their ratings, and the outcome of the game. /// -/// Takes in two players and the outcome of the game. +/// Takes in two players as [`IngoRating`]s, and an [`Outcome`](Outcomes). /// /// Instead of the traditional way of calculating the Ingo for only one player only using a list of results, /// we are calculating the Ingo rating for two players at once, like in the Elo calculation, /// to make it easier to see instant results. /// /// The outcome of the match is in the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// This means [`Outcomes::WIN`] is a win for `player_one` and [`Outcomes::LOSS`] is a win for `player_two`. /// /// A lower Ingo rating is more desirable, and while negative values are possible, /// a player with an Ingo rating of 0 has an equivalent Elo rating of 2840. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{ingo::ingo, outcomes::Outcomes, rating::IngoRating}; /// @@ -82,14 +96,15 @@ pub fn ingo( #[allow(clippy::as_conversions, clippy::cast_precision_loss)] #[must_use] -/// The "traditional" way of calculating an Ingo Rating of a player in a rating period or tournament. +/// The "traditional" way of calculating a [`IngoRating`] of a player in a rating period. /// -/// Takes in a player and their results as a Vec of tuples containing the opponent and the outcome. +/// Takes in a player as an [`IngoRating`] and their results as a Vec of tuples containing the opponent as an [`IngoRating`], +/// and the outcome of the game as an [`Outcome`](Outcomes) /// -/// All of the outcomes are from the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// The outcome of the match is in the perspective of the player. +/// This means [`Outcomes::WIN`] is a win for the player and [`Outcomes::LOSS`] is a win for the opponent. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{ingo::ingo_rating_period, rating::IngoRating, outcomes::Outcomes}; /// @@ -163,11 +178,11 @@ pub fn ingo_rating_period(player: IngoRating, results: &Vec<(IngoRating, Outcome #[must_use] /// Calculates the expected outcome of two players based on Ingo. /// -/// Takes in two players and returns the probability of victory for each player. +/// Takes in two players as [`IngoRating`]s and returns the probability of victory for each player as an [`f64`] between 1.0 and 0.0. /// 1.0 means a certain victory for the player, 0.0 means certain loss. /// Values near 0.5 mean a draw is likely to occur. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{ingo::expected_score, outcomes::Outcomes, rating::IngoRating}; /// diff --git a/src/lib.rs b/src/lib.rs index 09ce7d3..b5b8b80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,52 +6,41 @@ clippy::expect_used, clippy::as_conversions )] -#![allow(clippy::module_name_repetitions)] +#![allow(clippy::module_name_repetitions, clippy::doc_markdown)] -//! Skillratings provides functions on calculating a player's skill rating in 1v1 games. +//! Skillratings provides functions on calculating a player's skill rating. //! //! Currently we support these skill rating systems: -//! [`Elo`](https://en.wikipedia.org/wiki/Elo_rating_system), -//! [`DWZ`](https://en.wikipedia.org/wiki/Deutsche_Wertungszahl), -//! [`Ingo`](https://de.wikipedia.org/wiki/Ingo-Zahl), -//! [`TrueSkill`](https://en.wikipedia.org/wiki/TrueSkill), -//! [`Glicko`](https://en.wikipedia.org/wiki/Glicko_rating_system) -//! and [`Glicko-2`](https://en.wikipedia.org/wiki/Glicko-2). +//! **[`Elo`](crate::elo)**, +//! **[`DWZ`](crate::dwz)**, +//! **[`Ingo`](crate::ingo)**, +//! **[`TrueSkill`](crate::trueskill)**, +//! **[`Glicko`](crate::glicko)** +//! and **[`Glicko-2`](crate::glicko2)**. //! //! You can use this crate to calculate results for two players instantly, //! or for one player in a rating period with the algorithms mentioned above. //! -//! Read the linked wikipedia articles for more information about them and their advantages and disadvantages. +//! Head over to the modules above or below for more information about the specific rating algorithms, their advantages and disadvantages. +//! +//! # Installation +//! +//! Add the following to your `Cargo.toml` file: +//! ```toml +//! [dependencies] +//! skillratings = "0.10.0" +//! ``` +//! +//! # Examples and Usage +//! +//! Check out the `Examples` section for every function contained in the modules to see how they can be used. -/// Contains structs to configure key variables used in the different rating algorithms. pub mod config; - -/// The `Elo` algorithm, the most used and recognised rating system and the gold-standard in standard chess. -pub mod elo; - -/// The `DWZ (Deutsche Wertungszahl)` algorithm used in the german chess leagues alongside Elo. -/// DWZ continues to be enhanced over the years, while having similar scores to Elo. pub mod dwz; - -/// The `Ingo` algorithm, the predecessor of DWZ and one of the first rating algorihms invented in 1947. -/// Note that a lower score here is more desirable. -pub mod ingo; - -/// Calculate a player's skill rating using the `Glicko` algorithm, developed by Mark Glickman as an improvement on Elo. +pub mod elo; pub mod glicko; - -/// Calculate a player's skill rating using the `Glicko-2` algorithm, an improvement on Glicko and widely used in online games, -/// like Counter Strike: Global Offensive, Team Fortress 2, Splatoon 2 and most online chess platforms. pub mod glicko2; - -/// Calculate a player's skill rating using the `TrueSkill` algorithm, developed by Microsoft for Halo 3. -/// Used in the Halo games, the Forza Games, Tom Clancy's: Rainbow Six Siege, and most Xbox Live games. -/// Unlike the other rating algorithms, `TrueSkill` supports teams. -/// **Caution:** `TrueSkill` is patented, so if you have a commercial project, it is recommended to use another algorihm included here. -pub mod trueskill; - -/// Contains possible outcomes of a match. +pub mod ingo; pub mod outcomes; - -/// Contains structs to initialize player's ratings in the format of the different rating algorithms used. pub mod rating; +pub mod trueskill; diff --git a/src/outcomes.rs b/src/outcomes.rs index 02b78c0..797efc6 100644 --- a/src/outcomes.rs +++ b/src/outcomes.rs @@ -1,3 +1,5 @@ +//! The possible outcomes of a match. + /// The possible outcomes for a match: Win, Draw, Loss. /// Note that this is always from the perspective of player one. /// So a win is a win for player one and a loss is a win for player two. diff --git a/src/rating.rs b/src/rating.rs index 2797050..f931319 100644 --- a/src/rating.rs +++ b/src/rating.rs @@ -1,3 +1,5 @@ +//! Structs for initializing a player's rating for the different rating algorithms used. + /// The Elo rating of a player. /// /// The default rating is 1000.0. diff --git a/src/trueskill.rs b/src/trueskill.rs index 07b20fb..3b9812b 100644 --- a/src/trueskill.rs +++ b/src/trueskill.rs @@ -1,22 +1,49 @@ +//! The TrueSkill rating algorithm, developed by Microsoft for Halo 3. +//! Used in the Halo games, the Forza Games, Tom Clancy's: Rainbow Six Siege, and most Xbox Live games. +//! Unlike the other rating algorithms, TrueSkill supports teams. +//! +//! **Caution:** TrueSkill is patented. If you have a commercial project, it is recommended to use another algorithm included here. +//! +//! TrueSkill uses a normal distribution with a skill rating (μ) and an uncertainty value (σ) to represent a players skill level, +//! similar to [`Glicko`](crate::glicko) and [`Glicko-2`](crate::glicko2). +//! TrueSkill is good at assessing a player's skill level quickly. +//! The amount of matches needed depends on the game mode, as follows (The actual numbers may vary): +//! +//! | Match type | Matches needed | +//! | ---------- | -------------- | +//! | 1 Player vs 1 Player | 12 | +//! | 4 Players vs 4 Players | 46 | +//! | 8 Players vs 8 Players | 91 | +//! +//! Whereas other algorithms might need more matches in the same circumstances. +//! +//! The drawback is that the calculations are complex, and thus players may find it unintuitive in certain scenarios. +//! For example, players might gain rank(s) when losing a match due to the uncertainty value decreasing. +//! +//! # More Information +//! - [Wikipedia Article](https://en.wikipedia.org/wiki/TrueSkill) +//! - [TrueSkill Ranking System](https://www.microsoft.com/en-us/research/project/trueskill-ranking-system/) +//! - [Original Paper (PDF)](https://proceedings.neurips.cc/paper/2006/file/f44ee263952e65b3610b8ba51229d1f9-Paper.pdf) +//! - [The math behind TrueSkill (PDF)](http://www.moserware.com/assets/computing-your-skill/The%20Math%20Behind%20TrueSkill.pdf) +//! - [Moserware: Computing Your Skill](http://www.moserware.com/2010/03/computing-your-skill.html) use std::f64::consts::{FRAC_1_SQRT_2, PI, SQRT_2}; use crate::{config::TrueSkillConfig, outcomes::Outcomes, rating::TrueSkillRating}; -#[allow(clippy::doc_markdown)] #[must_use] -/// Calculates the TrueSkill rating of two players based on their ratings, uncertainties, and the outcome of the game. +/// Calculates the [`TrueSkillRating`]s of two players based on their old ratings, uncertainties, and the outcome of the game. /// -/// Takes in two players, outcome of the game and a [`TrueSkillConfig`]. +/// Takes in two players as [`TrueSkillRating`]s, an [`Outcome`](Outcomes), and a [`TrueSkillConfig`]. /// /// The outcome of the match is in the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// This means [`Outcomes::WIN`] is a win for `player_one` and [`Outcomes::LOSS`] is a win for `player_two`. /// /// Similar to [`trueskill_rating_period`] and [`trueskill_teams`]. /// -/// **Caution regarding usage of TrueSkill**: -/// Microsoft permits only Xbox Live games or non-commercial projects to use TrueSkill(TM). +/// **Caution regarding usage of TrueSkill**: +/// Microsoft permits only Xbox Live games or non-commercial projects to use TrueSkill. /// If your project is commercial, you should use another rating system included here. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{rating::TrueSkillRating, trueskill::trueskill, outcomes::Outcomes, config::TrueSkillConfig}; /// @@ -116,22 +143,22 @@ pub fn trueskill( } #[must_use] -#[allow(clippy::doc_markdown)] -/// Calculates a TrueSkill Rating in a non-traditional way using a rating period, +/// Calculates a [`TrueSkillRating`] in a non-traditional way using a rating period, /// for compatibility with the other algorithms. /// -/// Takes in a player and their results as a Vec of tuples containing the opponent and the outcome. +/// Takes in a player as an [`TrueSkillRating`] and their results as a Vec of tuples containing the opponent as an [`TrueSkillRating`], +/// the outcome of the game as an [`Outcome`](Outcomes) and a [`TrueSkillConfig`]. /// -/// All of the outcomes are from the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// The outcome of the match is in the perspective of the player. +/// This means [`Outcomes::WIN`] is a win for the player and [`Outcomes::LOSS`] is a win for the opponent. /// -/// Similar to [`trueskill`]. +/// Similar to [`trueskill`] or [`trueskill_teams`]. /// -/// **Caution regarding usage of TrueSkill**: -/// Microsoft permits only Xbox Live games or non-commercial projects to use TrueSkill(TM). +/// **Caution regarding usage of TrueSkill**: +/// Microsoft permits only Xbox Live games or non-commercial projects to use TrueSkill. /// If your project is commercial, you should use another rating system included here. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{ /// rating::TrueSkillRating, trueskill::trueskill_rating_period, outcomes::Outcomes, config::TrueSkillConfig @@ -224,17 +251,13 @@ pub fn trueskill_rating_period( } #[must_use] -#[allow( - clippy::as_conversions, - clippy::cast_precision_loss, - clippy::doc_markdown -)] -/// Calculates the TrueSkill rating of two teams based on their ratings, uncertainties, and the outcome of the game. +#[allow(clippy::as_conversions, clippy::cast_precision_loss)] +/// Calculates the [`TrueSkillRating`] of two teams based on their ratings, uncertainties, and the outcome of the game. /// -/// Takes in two teams as a Vec of `TrueSkillRating`'s, the outcome of the game and a [`TrueSkillConfig`]. +/// Takes in two teams as a Vec of [`TrueSkillRating`]s, the outcome of the game as an [`Outcome`](Outcomes) and a [`TrueSkillConfig`]. /// -/// The outcome of the match is in the perspective of `player_one`. -/// This means `Outcomes::WIN` is a win for `player_one` and `Outcomes::LOSS` is a win for `player_two`. +/// The outcome of the match is in the perspective of `team_one`. +/// This means [`Outcomes::WIN`] is a win for `team_one` and [`Outcomes::LOSS`] is a win for `team_two`. /// /// Similar to [`trueskill`]. /// @@ -242,7 +265,7 @@ pub fn trueskill_rating_period( /// Microsoft permits only Xbox Live games or non-commercial projects to use TrueSkill(TM). /// If your project is commercial, you should use another rating system included here. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{ /// trueskill::trueskill_teams, rating::TrueSkillRating, outcomes::Outcomes, config::TrueSkillConfig @@ -353,9 +376,11 @@ pub fn trueskill_teams( /// Gets the quality of the match, which is equal to the probability that the match will end in a draw. /// The higher the Value, the better the quality of the match. /// +/// Takes in two players as [`TrueSkillRating`]s and returns the probability of a draw occurring as an [`f64`] between 1.0 and 0.0. +/// /// Similar to [`match_quality_teams`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{rating::TrueSkillRating, trueskill::match_quality, config::TrueSkillConfig}; /// @@ -400,12 +425,14 @@ pub fn match_quality( clippy::cast_precision_loss, clippy::needless_pass_by_value )] -/// Gets the quality of a match between two teams, which is equal to the probability that the match will end in a draw. +/// Gets the quality of the match, which is equal to the probability that the match will end in a draw. /// The higher the Value, the better the quality of the match. /// +/// Takes in two teams as Vec of [`TrueSkillRating`]s and returns the probability of a draw occurring as an [`f64`] between 1.0 and 0.0. +/// /// Similar to [`match_quality`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{rating::TrueSkillRating, trueskill::match_quality_teams, config::TrueSkillConfig}; /// @@ -463,9 +490,9 @@ pub fn match_quality_teams( } #[must_use] -/// Calculates the expected outcome of two players based on `TrueSkill`. +/// Calculates the expected outcome of two players based on TrueSkill. /// -/// Takes in two players and the config and returns the probability of victory for each player. +/// Takes in two players as [`TrueSkillRating`]s and returns the probability of victory for each player as an [`f64`] between 1.0 and 0.0. /// 1.0 means a certain victory for the player, 0.0 means certain loss. /// Values near 0.5 mean a draw is likely to occur. /// @@ -473,7 +500,7 @@ pub fn match_quality_teams( /// /// To see the actual chances of a draw occurring, please use [`match_quality`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{rating::TrueSkillRating, trueskill::expected_score, config::TrueSkillConfig}; /// @@ -537,15 +564,15 @@ pub fn expected_score( )] /// Calculates the expected outcome of two teams based on `TrueSkill`. /// -/// Takes in two teams as Vec of players and the config and returns the probability of victory for each team. -/// 1.0 means a certain victory for the team, 0.0 means certain loss. +/// Takes in two teams as Vec of [`TrueSkillRating`]s and returns the probability of victory for each player as an [`f64`] between 1.0 and 0.0. +/// 1.0 means a certain victory for the player, 0.0 means certain loss. /// Values near 0.5 mean a draw is likely to occur. /// /// Similar to [`expected_score`]. /// /// To see the actual chances of a draw occurring, please use [`match_quality_teams`]. /// -/// # Example +/// # Examples /// ``` /// use skillratings::{rating::TrueSkillRating, trueskill::expected_score_teams, config::TrueSkillConfig}; /// @@ -617,6 +644,8 @@ pub fn expected_score_teams( /// This is a conservative estimate of player skill, /// the system is 99% sure the player's skill is higher than displayed. /// +/// Takes in a player as a [`TrueSkillRating`] and returns the rank as an [`f64`]. +/// /// The recommended scale used for Xbox Live is 0 (lowest, starting value) to 50 (highest). /// /// # Example