| Crates.io | whr |
| lib.rs | whr |
| version | 0.3.0 |
| created_at | 2024-08-30 08:04:52.819977+00 |
| updated_at | 2025-06-18 16:53:44.349997+00 |
| description | Implementation of Rémi Coulom's Whole-History Rating (WHR) algorithm for Rust |
| homepage | |
| repository | https://github.com/aloisrtr/whr |
| max_upload_size | |
| id | 1357466 |
| size | 37,389 |
Implementation of Rémi Coulom's Whole History Rating (WHR) algorithm as a Rust library, with support for draws and handicaps.
WHR is used to rate players in competitive games, akin to the Elo or TrueSkill systems. It can estimate the probability of winning between two players even if they have never competed against one another. It is more accurate than other rating systems because it uses the entire match history of players instead of updating estimations incrementally. This comes at the cost of higher computational costs, but most game servers should be able to support it without issue.
WHR is notably used in Go, Warcraft 3, Renju, and is even used in some sports!
I hope to generalize the library further, notably by supporting games with:
It's also difficult for me to assess how well the structure of this library matches the needs of larger projects. If you'd like to use it and have trouble making it work without friction, feel free to open up an issue.
The library can be used in any Cargo project by running:
cargo add whr
or by adding the following to your Cargo.toml:
[dependencies]
whr = "0.3"
Whole History Rating, as the name suggests, derives ratings from the entire history of each player. When using this library, this is done in two steps:
This is done using the builder pattern.
use whr::{WhrBuilder, MatchRecord};
let whr = WhrBuilder::default()
// Register matches, with:
// - two named players,
// - an optional winner,
// - a timestep,
// - and optional handicap (first player advantage)
.with_match(MatchRecord::new("alice", "bob", Some("bob"), 1, None)?)
.with_match(MatchRecord::new("alice", "bob", None, 2, None)?)
.with_match(MatchRecord::new("bob", "alice", Some("alice"), 2, None)?)
// You can even add multiple games at once from an iterator
.with_matches([
MatchRecord::new("bob", "alice", Some("alice"), 1, None)?,
MatchRecord::new("alice", "charlie", Some("charlie"), 4, None)?
]);
Timesteps are discrete values indicating an order for the matches. This may be matched
with tournaments, for example. WhrBuilder is generic over both the player's identification
(so that you can use whatever your infrastructure uses: strings, integers, etc)
and timesteps (as long as they are ordered values).
Once the matches have been added to the history, you can call WhrBuilder::build
to compute a Whr structure. This structure allows you to access individual players'
ratings over timesteps, along with the uncertainety of this rating.
The computation step can be configured within WhrBuilder, by setting the number
of iterations to stabilize ratings, a maximum duration, batch size, etc.
All of these parameters and the methods used to set them are described in the documentation.