#rating #elo #glicko #glicko-2

instant-glicko-2

实现Glicko-2评级系统,允许游戏后立即提供反馈,而不仅仅是评级周期结束后

2个不稳定版本

0.2.0 2023年11月12日
0.1.0 2022年3月31日

#292 in 数学

MIT许可证

96KB
1.5K SLoC

Instant Glicko-2

这个crate提供了一个Glicko-2评级系统的实现。由于评级周期的概念,Glicko-2存在一个问题,那就是在比赛结束后不能轻松地立即更新排名。

这个实现旨在通过允许分数评级周期来解决该问题,因此可以在每场比赛后直接更新评级,而不仅仅是评级周期结束后。这受到了开源国际象棋网站Lichess的评级系统实现以及Ryan Juckett在INVERSUS Deluxe上的技能评级博客文章12)的启发。

关于实现的更多内容,我在这里写了些东西。

该crate的文档可以在Docs.rs上找到。

要将此作为依赖项使用,请将以下行添加到您的Cargo.toml依赖项

instant-glicko-2 = "0.1.0"

示例

使用algorithmGlickman的论文中获取的示例计算

use instant_glicko_2::{Parameters, PublicRating, IntoWithParameters};
use instant_glicko_2::algorithm::{self, PublicGame};

let parameters = Parameters::default().with_volatility_change(0.5);

// Create our player's rating
let mut player = PublicRating::new(1500.0, 200.0, 0.06);

// Create our opponents
// Their volatility is not specified in the paper and it doesn't matter in the calculation,
// so we're just using the default starting volatility.
let opponent_a = PublicRating::new(1400.0, 30.0, parameters.start_rating().volatility());
let opponent_b = PublicRating::new(1550.0, 100.0, parameters.start_rating().volatility());
let opponent_c = PublicRating::new(1700.0, 300.0, parameters.start_rating().volatility());

// Create match results for our player
let results = [
    // Wins first game (score 1.0)
    PublicGame::new(opponent_a, 1.0).into_with_parameters(parameters),
    // Loses second game (score 0.0)
    PublicGame::new(opponent_b, 0.0).into_with_parameters(parameters),
    // Loses third game (score 0.0)
    PublicGame::new(opponent_c, 0.0).into_with_parameters(parameters),
];

// Update rating after rating period
let new_rating: PublicRating = algorithm::rate_games_untimed(player.into_with_parameters(parameters), &results, 1.0, parameters).into_with_parameters(parameters);

// The rating after the rating period are very close to the results from the paper
assert!((new_rating.rating() - 1464.06).abs() < 0.01);
assert!((new_rating.deviation() - 151.52).abs() < 0.01);
assert!((new_rating.volatility() - 0.05999).abs() < 0.0001);

使用RatingEngine的不同示例

use std::time::Duration;
use instant_glicko_2::{Parameters, PublicRating};
use instant_glicko_2::engine::{MatchResult, RatingEngine};

let parameters = Parameters::default();

// Create a RatingEngine with a one day rating period duration
// The first rating period starts instantly
let mut engine = RatingEngine::start_new(
    Duration::from_secs(60 * 60 * 24),
    Parameters::default(),
);

// Register two players
// The first player is relatively strong
let player_1_rating_old = PublicRating::new(1700.0, 300.0, 0.06);
let player_1 = engine.register_player(player_1_rating_old).0;

// The second player hasn't played any games
let player_2_rating_old = parameters.start_rating();
let player_2 = engine.register_player(player_2_rating_old).0;

// They play and player_2 wins
engine.register_result(
    player_1,
    player_2,
    &MatchResult::Loss,
);

// Print the new ratings
// Type signatures are needed because we could also work with the internal InternalRating
// That skips one step of calculation,
// but the rating values are not as pretty and not comparable to the original Glicko ratings
let player_1_rating_new: PublicRating = engine.player_rating(player_1).0;
println!("Player 1 old rating: {player_1_rating_old:?}, new rating: {player_1_rating_new:?}");
let player_2_rating_new: PublicRating = engine.player_rating(player_2).0;
println!("Player 2 old rating: {player_2_rating_old:?}, new rating: {player_2_rating_new:?}");

// Loser's rating goes down, winner's rating goes up
assert!(player_1_rating_old.rating() > player_1_rating_new.rating());
assert!(player_2_rating_old.rating() < player_2_rating_new.rating());

依赖项

~170KB