45 个版本 (26 个破坏性版本)
0.27.0 | 2024年6月8日 |
---|---|
0.26.0 | 2023年10月8日 |
0.25.1 | 2023年10月5日 |
0.25.0 | 2023年6月4日 |
0.21.0 | 2022年11月24日 |
#49 in 数学
每月下载量 84
470KB
8K SLoC
skillratings
Skillratings 提供了一组著名的(和不太著名的)技能评级算法,允许您即时评估玩家的技能水平。
您可以在 1 对 1 比赛、团队对抗比赛、自由对抗或多队比赛,或在锦标赛/评级期间,轻松地即时计算技能评级。
这个库非常轻量(默认无依赖),用户友好,当然,速度极快。
当前支持的算法
- Elo
- Glicko
- Glicko-2
- TrueSkill
- Weng-Lin (OpenSkill)
- FIFA 男子世界杯排名
- Sticko (Stephenson 评级系统)
- Glicko-Boost
- USCF (美国国际象棋联合会评级)
- EGF (欧洲围棋联合会评级)
- DWZ (德国评价数)
- Ingo
这些大多数都源于在线多人游戏中的使用。
点击上述链接的文档,了解更多关于特定评级算法及其优缺点的信息。
目录
安装
如果您使用的是 Rust 1.62 或更高版本,请使用 cargo add
安装最新版本
cargo add skillratings
或者,您可以手动将以下内容添加到您的 Cargo.toml
文件中
[dependencies]
skillratings = "0.27"
Serde 支持
Serde 支持由 serde
功能控制。您可以通过以下方式启用它
使用 cargo add
cargo add skillratings --features serde
通过手动编辑 Cargo.toml
[dependencies]
skillratings = {version = "0.27", features = ["serde"]}
用法和示例
以下是一些关于此crate用例的基本示例。
还有许多其他评分算法,这里没有涵盖许多有用的功能。
更多信息,请参阅文档。
玩家对玩家
这里包含的每个评分算法都可以用于1v1游戏。
以下示例中我们使用的是Glicko-2。
use skillratings::{
glicko2::{glicko2, Glicko2Config, Glicko2Rating},
Outcomes,
};
// Initialise a new player rating.
// The default values are: 1500, 350, and 0.06.
let player_one = Glicko2Rating::new();
// Or you can initialise it with your own values of course.
// Imagine these numbers being pulled from a database.
let (some_rating, some_deviation, some_volatility) = (1325.0, 230.0, 0.05932);
let player_two = Glicko2Rating {
rating: some_rating,
deviation: some_deviation,
volatility: some_volatility,
};
// The outcome of the match is from the perspective of player one.
let outcome = Outcomes::WIN;
// The config allows you to specify certain values in the Glicko-2 calculation.
let config = Glicko2Config::new();
// The glicko2 function will calculate the new ratings for both players and return them.
let (new_player_one, new_player_two) = glicko2(&player_one, &player_two, &outcome, &config);
// The first players rating increased by ~112 points.
assert_eq!(new_player_one.rating.round(), 1612.0);
团队对团队
一些算法,如TrueSkill或Weng-Lin,还允许您对基于团队的比赛进行评分。
以下示例展示了使用TrueSkill进行的3v3比赛。
use skillratings::{
trueskill::{trueskill_two_teams, TrueSkillConfig, TrueSkillRating},
Outcomes,
};
// We initialise Team One as a Vec of multiple TrueSkillRatings.
// The default values for the rating are: 25, 25/3 ≈ 8.33.
let team_one = vec![
TrueSkillRating {
rating: 33.3,
uncertainty: 3.3,
},
TrueSkillRating {
rating: 25.1,
uncertainty: 1.2,
},
TrueSkillRating {
rating: 43.2,
uncertainty: 2.0,
},
];
// Team Two will be made up of 3 new players, for simplicity.
// Note that teams do not necessarily have to be the same size.
let team_two = vec![
TrueSkillRating::new(),
TrueSkillRating::new(),
TrueSkillRating::new(),
];
// The outcome of the match is from the perspective of team one.
let outcome = Outcomes::LOSS;
// The config allows you to specify certain values in the TrueSkill calculation.
let config = TrueSkillConfig::new();
// The trueskill_two_teams function will calculate the new ratings for both teams and return them.
let (new_team_one, new_team_two) = trueskill_two_teams(&team_one, &team_two, &outcome, &config);
// The rating of the first player on team one decreased by around ~1.2 points.
assert_eq!(new_team_one[0].rating.round(), 32.0);
自由对抗和多队比赛
Weng-Lin和TrueSkill算法还支持对多队比赛进行评分。
以下是一个3队比赛,每队3个玩家的示例。
use skillratings::{
weng_lin::{weng_lin_multi_team, WengLinConfig, WengLinRating},
MultiTeamOutcome,
};
// Initialise the teams as Vecs of WengLinRatings.
// Note that teams do not necessarily have to be the same size.
// The default values for the rating are: 25, 25/3 ≈ 8.33.
let team_one = vec![
WengLinRating {
rating: 25.1,
uncertainty: 5.0,
},
WengLinRating {
rating: 24.0,
uncertainty: 1.2,
},
WengLinRating {
rating: 18.0,
uncertainty: 6.5,
},
];
let team_two = vec![
WengLinRating {
rating: 44.0,
uncertainty: 1.2,
},
WengLinRating {
rating: 32.0,
uncertainty: 2.0,
},
WengLinRating {
rating: 12.0,
uncertainty: 3.2,
},
];
// Using the default rating for team three for simplicity.
let team_three = vec![
WengLinRating::new(),
WengLinRating::new(),
WengLinRating::new(),
];
// Every team is assigned a rank, depending on their placement. The lower the rank, the better.
// If two or more teams tie with each other, assign them the same rank.
let rating_groups = vec![
(&team_one[..], MultiTeamOutcome::new(1)), // team one takes the 1st place.
(&team_two[..], MultiTeamOutcome::new(3)), // team two takes the 3rd place.
(&team_three[..], MultiTeamOutcome::new(2)), // team three takes the 2nd place.
];
// The weng_lin_multi_team function will calculate the new ratings for all teams and return them.
let new_teams = weng_lin_multi_team(&rating_groups, &WengLinConfig::new());
// The rating of the first player of team one increased by around ~2.9 points.
assert_eq!(new_teams[0][0].rating.round(), 28.0);
预期结果
每个评分算法都有一个expected_score
函数,您可以使用它来预测比赛的结局。
以下示例使用Glicko(不是Glicko-2)进行演示。
use skillratings::glicko::{expected_score, GlickoRating};
// Initialise a new player rating.
// The default values are: 1500, and 350.
let player_one = GlickoRating::new();
// Initialising a new rating with custom numbers.
let player_two = GlickoRating {
rating: 1812.0,
deviation: 195.0,
};
// The expected_score function will return two floats between 0 and 1 for each player.
// A value of 1 means guaranteed victory, 0 means certain loss.
// Values near 0.5 mean draws are likely to occur.
let (exp_one, exp_two) = expected_score(&player_one, &player_two);
// The expected score for player one is ~0.25.
// If these players would play 100 games, player one is expected to score around 25 points.
// (Win = 1 point, Draw = 0.5, Loss = 0)
assert_eq!((exp_one * 100.0).round(), 25.0);
评分周期
这里包含的每个评分算法都有一个..._rating_period
,允许您使用结果列表计算玩家的新评分。
这可以在锦标赛中使用,或者在您只在某个评分周期结束时更新评分的情况下很有用,正如其名称所示。
以下示例中我们使用的是Elo评分算法。
use skillratings::{
elo::{elo_rating_period, EloConfig, EloRating},
Outcomes,
};
// We initialise a new Elo Rating here.
// The default rating value is 1000.
let player = EloRating { rating: 1402.1 };
// We need a list of results to pass to the elo_rating_period function.
let mut results = Vec::new();
// And then we populate the list with tuples containing the opponent,
// and the outcome of the match from our perspective.
results.push((EloRating::new(), Outcomes::WIN));
results.push((EloRating { rating: 954.0 }, Outcomes::DRAW));
results.push((EloRating::new(), Outcomes::LOSS));
// The elo_rating_period function calculates the new rating for the player and returns it.
let new_player = elo_rating_period(&player, &results, &EloConfig::new());
// The rating of the player decreased by around ~40 points.
assert_eq!(new_player.rating.round(), 1362.0);
在不同评级系统之间切换
如果您想在不同评分系统之间切换,例如比较结果或进行科学分析,我们提供特质,以便尽可能快速地切换。
您只需要提供正确的评分系统配置即可。
免责声明:为了更精确和微调的计算,建议您直接使用评分系统模块。
特质主要适用于系统之间的比较。
以下示例中,我们使用Glicko-2与RatingSystem
(1v1)特质。
use skillratings::{
glicko2::{Glicko2, Glicko2Config},
Outcomes, Rating, RatingSystem,
;
// Initialise a new player rating with a rating value and uncertainty value.
// Not every rating system has an uncertainty value, so it may be discarded.
// Some rating systems might consider other values too (volatility, age, matches played etc.).
// If that is the case, we will use the default values for those.
let player_one = Rating::new(Some(1200.0), Some(120.0));
// Some rating systems might use widely different scales for measuring a player's skill.
// So if you always want the default values for every rating system, use None instead.
let player_two = Rating::new(None, None);
// The config needs to be specific to the rating system.
// When you swap rating systems, make sure to update the config.
let config = Glicko2Config::new();
// We want to rate 1v1 matches here so we are using the `RatingSystem` trait.
// You may also need to use a type annotation here for the compiler.
let rating_system: Glicko2 = RatingSystem::new(config);
// The outcome of the match is from the perspective of player one.
let outcome = Outcomes::WIN;
// Calculate the expected score of the match.
let expected_score = rating_system.expected_score(&player_one, &player_two);
// Calculate the new ratings.
let (new_one, new_two) = rating_system.rate(&player_one, &player_two, &outcome);
// After that, access new ratings and uncertainties with the functions below.
assert_eq!(new_one.rating().round(), 1241.0);
// Note that because not every rating system has an uncertainty value,
// the uncertainty function returns an Option<f64>.
assert_eq!(new_one.uncertainty().unwrap().round(), 118.0);
贡献
欢迎任何形式的贡献!
发现了错误或有什么功能请求?请提交新问题。
或者,如果您想添加功能或修复错误,请发起拉取请求。
当然,留下其他反馈也受到欢迎。
感谢所有抽出时间贡献的人。
许可
本项目采用MIT许可证或Apache许可证,版本2.0。