Skip to content

Commit

Permalink
Pass reference to all functions
Browse files Browse the repository at this point in the history
  • Loading branch information
atomflunder committed Sep 25, 2022
1 parent 13a2d0c commit cf61095
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 266 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

This is a broad overview of the changes that have been made over the lifespan of this library.

## v0.13.0 - 2022-09-25

- All functions now use references instead of taking ownership unnecessarily

## v0.12.0 - 2022-08-26

- Add Weng-Lin (A Bayesian Approximation Method for Online Ranking) calculations
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[package]
name = "skillratings"
version = "0.12.0"
version = "0.13.0"
edition = "2021"
description = "Calculate a player's skill rating using algorithms like Elo, Glicko, Glicko-2, TrueSkill and many more."
readme= "README.md"
readme = "README.md"
repository = "https://github.com/atomflunder/skillratings"
license = "MIT"
keywords = ["elo", "glicko", "glicko-2", "trueskill", "rating"]
categories = ["game-development", "algorithms", "mathematics"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
[dependencies]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Add the following to your `Cargo.toml` file:

```toml
[dependencies]
skillratings = "0.12.0"
skillratings = "0.13.0"
```

## Basic Usage
Expand Down
34 changes: 17 additions & 17 deletions src/dwz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use crate::{outcomes::Outcomes, rating::DWZRating};
///
/// let outcome = Outcomes::WIN;
///
/// let (player_one_new, player_two_new) = dwz(player_one, player_two, outcome);
/// let (player_one_new, player_two_new) = dwz(&player_one, &player_two, &outcome);
///
/// assert!((player_one_new.rating.round() - 1519.0).abs() < f64::EPSILON);
/// assert_eq!(player_one_new.index, 43);
Expand All @@ -59,9 +59,9 @@ use crate::{outcomes::Outcomes, rating::DWZRating};
/// assert_eq!(player_two_new.index, 13);
/// ```
pub fn dwz(
player_one: DWZRating,
player_two: DWZRating,
outcome: Outcomes,
player_one: &DWZRating,
player_two: &DWZRating,
outcome: &Outcomes,
) -> (DWZRating, DWZRating) {
let outcome1 = match outcome {
Outcomes::WIN => 1.0,
Expand Down Expand Up @@ -148,12 +148,12 @@ pub fn dwz(
///
/// let results = vec![(opponent1, Outcomes::WIN), (opponent2, Outcomes::DRAW)];
///
/// let new_player = dwz_rating_period(player, &results);
/// let new_player = dwz_rating_period(&player, &results);
///
/// assert!((new_player.rating.round() - 1635.0).abs() < f64::EPSILON);
/// assert_eq!(new_player.index, 18);
/// ```
pub fn dwz_rating_period(player: DWZRating, results: &Vec<(DWZRating, Outcomes)>) -> DWZRating {
pub fn dwz_rating_period(player: &DWZRating, results: &Vec<(DWZRating, Outcomes)>) -> DWZRating {
let points = results
.iter()
.map(|r| match r.1 {
Expand All @@ -165,7 +165,7 @@ pub fn dwz_rating_period(player: DWZRating, results: &Vec<(DWZRating, Outcomes)>

let expected_points = results
.iter()
.map(|r| expected_score(player, r.0).0)
.map(|r| expected_score(player, &r.0).0)
.sum::<f64>();

#[allow(clippy::as_conversions, clippy::cast_precision_loss)]
Expand Down Expand Up @@ -208,13 +208,13 @@ pub fn dwz_rating_period(player: DWZRating, results: &Vec<(DWZRating, Outcomes)>
/// age: 12,
/// };
///
/// let (exp_one, exp_two) = expected_score(player_one, player_two);
/// let (exp_one, exp_two) = expected_score(&player_one, &player_two);
///
///
/// assert!(((exp_one * 100.0).round() - 91.0).abs() < f64::EPSILON);
/// assert!(((exp_two * 100.0).round() - 9.0).abs() < f64::EPSILON);
/// ```
pub fn expected_score(player_one: DWZRating, player_two: DWZRating) -> (f64, f64) {
pub fn expected_score(player_one: &DWZRating, player_two: &DWZRating) -> (f64, f64) {
(
(1.0 + 10.0_f64.powf(-1.0 * (1.0 / 400.0) * (player_one.rating - player_two.rating)))
.recip(),
Expand Down Expand Up @@ -460,15 +460,15 @@ mod tests {
age: 39,
};

(player_one, player_two) = dwz(player_one, player_two, Outcomes::WIN);
(player_one, player_two) = dwz(&player_one, &player_two, &Outcomes::WIN);

assert!((player_one.rating.round() - 1564.0).abs() < f64::EPSILON);
assert_eq!(player_one.index, 23);

assert!((player_two.rating.round() - 1906.0).abs() < f64::EPSILON);
assert_eq!(player_two.index, 104);

(player_one, player_two) = dwz(player_one, player_two, Outcomes::DRAW);
(player_one, player_two) = dwz(&player_one, &player_two, &Outcomes::DRAW);

assert!((player_one.rating.round() - 1578.0).abs() < f64::EPSILON);
assert_eq!(player_one.index, 24);
Expand All @@ -478,7 +478,7 @@ mod tests {

player_two.age = 12;

(player_one, player_two) = dwz(player_one, player_two, Outcomes::LOSS);
(player_one, player_two) = dwz(&player_one, &player_two, &Outcomes::LOSS);

assert!((player_one.rating.round() - 1573.0).abs() < f64::EPSILON);
assert_eq!(player_one.index, 25);
Expand Down Expand Up @@ -513,7 +513,7 @@ mod tests {
(opponent1, Outcomes::LOSS),
];

let new_player = dwz_rating_period(player, &results);
let new_player = dwz_rating_period(&player, &results);

assert!((new_player.rating.round() - 1619.0).abs() < f64::EPSILON);
assert_eq!(new_player.index, 18);
Expand All @@ -534,7 +534,7 @@ mod tests {
};

(really_good_player, really_bad_player) =
dwz(really_good_player, really_bad_player, Outcomes::WIN);
dwz(&really_good_player, &really_bad_player, &Outcomes::WIN);

assert!((really_good_player.rating.round() - 3210.0).abs() < f64::EPSILON);
assert_eq!(really_good_player.index, 144);
Expand All @@ -546,7 +546,7 @@ mod tests {
really_good_player.rating = 32_477_324_874_238.0;

(really_good_player, really_bad_player) =
dwz(really_good_player, really_bad_player, Outcomes::WIN);
dwz(&really_good_player, &really_bad_player, &Outcomes::WIN);

assert!((really_good_player.rating.round() - 32_477_324_874_238.0).abs() < f64::EPSILON);

Expand All @@ -559,7 +559,7 @@ mod tests {
really_bad_player.age = 5;

(really_good_player, really_bad_player) =
dwz(really_good_player, really_bad_player, Outcomes::LOSS);
dwz(&really_good_player, &really_bad_player, &Outcomes::LOSS);

assert!((really_good_player.rating.round() + 1.0).abs() < f64::EPSILON);
assert!((really_bad_player.rating.round() - 68.0).abs() < f64::EPSILON);
Expand All @@ -579,7 +579,7 @@ mod tests {
age: 39,
};

let (exp1, exp2) = expected_score(player_one, player_two);
let (exp1, exp2) = expected_score(&player_one, &player_two);

assert!(((exp1 * 100.0).round() - 9.0).abs() < f64::EPSILON);
assert!(((exp2 * 100.0).round() - 91.0).abs() < f64::EPSILON);
Expand Down
50 changes: 25 additions & 25 deletions src/elo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ use crate::{config::EloConfig, outcomes::Outcomes, rating::EloRating};
///
/// let config = EloConfig::new();
///
/// let (player_one_new, player_two_new) = elo(player_one, player_two, outcome, &config);
/// let (player_one_new, player_two_new) = elo(&player_one, &player_two, &outcome, &config);
///
/// assert!((player_one_new.rating - 1016.0).abs() < f64::EPSILON);
/// assert!((player_two_new.rating - 984.0).abs() < f64::EPSILON);
/// ```
#[must_use]
pub fn elo(
player_one: EloRating,
player_two: EloRating,
outcome: Outcomes,
player_one: &EloRating,
player_two: &EloRating,
outcome: &Outcomes,
config: &EloConfig,
) -> (EloRating, EloRating) {
let (one_expected, two_expected) = expected_score(player_one, player_two);
Expand Down Expand Up @@ -86,7 +86,7 @@ pub fn elo(
/// let opponent3 = EloRating::new();
///
/// let new_player = elo_rating_period(
/// player,
/// &player,
/// &vec![
/// (opponent1, Outcomes::WIN),
/// (opponent2, Outcomes::WIN),
Expand All @@ -99,14 +99,14 @@ pub fn elo(
/// ```
#[must_use]
pub fn elo_rating_period(
player: EloRating,
player: &EloRating,
results: &Vec<(EloRating, Outcomes)>,
config: &EloConfig,
) -> EloRating {
let mut player = player;
let mut player = *player;

for (opponent, result) in results {
let (exp, _) = expected_score(player, *opponent);
let (exp, _) = expected_score(&player, opponent);

let o = match result {
Outcomes::WIN => 1.0,
Expand Down Expand Up @@ -134,13 +134,13 @@ pub fn elo_rating_period(
/// let player_one = EloRating { rating: 1320.0 };
/// let player_two = EloRating { rating: 1217.0 };
///
/// let (winner_exp, loser_exp) = expected_score(player_one, player_two);
/// let (winner_exp, loser_exp) = expected_score(&player_one, &player_two);
///
/// assert!(((winner_exp * 100.0).round() - 64.0).abs() < f64::EPSILON);
/// assert!(((loser_exp * 100.0).round() - 36.0).abs() < f64::EPSILON);
/// ```
#[must_use]
pub fn expected_score(player_one: EloRating, player_two: EloRating) -> (f64, f64) {
pub fn expected_score(player_one: &EloRating, player_two: &EloRating) -> (f64, f64) {
(
1.0 / (1.0 + 10_f64.powf((player_two.rating - player_one.rating) / 400.0)),
1.0 / (1.0 + 10_f64.powf((player_one.rating - player_two.rating) / 400.0)),
Expand All @@ -154,36 +154,36 @@ mod tests {
#[test]
fn test_elo() {
let (winner_new_elo, loser_new_elo) = elo(
EloRating { rating: 1000.0 },
EloRating { rating: 1000.0 },
Outcomes::WIN,
&EloRating { rating: 1000.0 },
&EloRating { rating: 1000.0 },
&Outcomes::WIN,
&EloConfig::new(),
);
assert!((winner_new_elo.rating - 1016.0).abs() < f64::EPSILON);
assert!((loser_new_elo.rating - 984.0).abs() < f64::EPSILON);

let (winner_new_elo, loser_new_elo) = elo(
EloRating { rating: 1000.0 },
EloRating { rating: 1000.0 },
Outcomes::LOSS,
&EloRating { rating: 1000.0 },
&EloRating { rating: 1000.0 },
&Outcomes::LOSS,
&EloConfig::new(),
);
assert!((winner_new_elo.rating - 984.0).abs() < f64::EPSILON);
assert!((loser_new_elo.rating - 1016.0).abs() < f64::EPSILON);

let (winner_new_elo, loser_new_elo) = elo(
EloRating { rating: 1000.0 },
EloRating { rating: 1000.0 },
Outcomes::DRAW,
&EloRating { rating: 1000.0 },
&EloRating { rating: 1000.0 },
&Outcomes::DRAW,
&EloConfig::new(),
);
assert!((winner_new_elo.rating - 1000.0).abs() < f64::EPSILON);
assert!((loser_new_elo.rating - 1000.0).abs() < f64::EPSILON);

let (winner_new_elo, loser_new_elo) = elo(
EloRating { rating: 500.0 },
EloRating { rating: 1500.0 },
Outcomes::WIN,
&EloRating { rating: 500.0 },
&EloRating { rating: 1500.0 },
&Outcomes::WIN,
&EloConfig::default(),
);
assert!((winner_new_elo.rating.round() - 532.0).abs() < f64::EPSILON);
Expand All @@ -199,7 +199,7 @@ mod tests {
let opponent3 = EloRating::new();

let new_player = elo_rating_period(
player,
&player,
&vec![
(opponent1, Outcomes::WIN),
(opponent2, Outcomes::DRAW),
Expand All @@ -216,15 +216,15 @@ mod tests {
let player_one = EloRating::new();
let player_two = EloRating::default();

let (winner_expected, loser_expected) = expected_score(player_one, player_two);
let (winner_expected, loser_expected) = expected_score(&player_one, &player_two);

assert!((winner_expected - 0.5).abs() < f64::EPSILON);
assert!((loser_expected - 0.5).abs() < f64::EPSILON);

let player_one = EloRating { rating: 2251.0 };
let player_two = EloRating { rating: 1934.0 };

let (winner_expected, loser_expected) = expected_score(player_one, player_two);
let (winner_expected, loser_expected) = expected_score(&player_one, &player_two);

assert!(((winner_expected * 100.0).round() - 86.0).abs() < f64::EPSILON);
assert!(((loser_expected * 100.0).round() - 14.0).abs() < f64::EPSILON);
Expand Down
Loading

0 comments on commit cf61095

Please sign in to comment.