fn is_rating_okay(rating: f32, ssrs: &[f32], delta_multiplier: f32) -> bool {
let max_power_sum: f64 = 2f64.powf(rating as f64 * 0.1);
let power_sum: f64 = ssrs
.iter()
.map(|&ssr| (2.0 / libm::erfcf(delta_multiplier * (ssr - rating)) - 2.0) as f64)
.filter(|&x| x > 0.0)
.sum();
power_sum < max_power_sum
}
fn calc_rating(ssrs: &[f32], final_multiplier: f32, delta_multiplier: f32) -> f32 {
let num_iters: u32 = 11;
let mut rating: f32 = 0.0;
let mut resolution: f32 = 10.24;
for _ in 0..num_iters {
while !is_rating_okay(rating + resolution, ssrs, delta_multiplier) {
rating += resolution;
}
resolution /= 2.0;
}
rating += resolution * 2.0;
rating * final_multiplier
}
pub fn calculate_score_overall(skillsets: &[f32; 7]) -> f32 {
calc_rating(skillsets, 1.11, 0.25)
}
pub fn calculate_player_skillset_rating(ssrs: &[f32]) -> f32 {
calc_rating(ssrs, 1.05, 0.1)
}
pub fn calculate_player_skillset_rating_pre_070(ssrs: &[f32]) -> f32 {
calc_rating(ssrs, 1.04, 0.1)
}
pub fn calculate_player_overall(skillsets: &[f32; 7]) -> f32 {
calc_rating(skillsets, 1.125, 0.1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_everything() {
#[allow(clippy::excessive_precision)] let test_values: &[([f32; 7], f32, f32, f32, f32)] = &[
(
[21.0, 24.0, 23.0, 14.0, 17.0, 25.0, 24.0],
25.27470016,
21.94499779,
21.73599815,
23.51249886,
),
(
[25.0, 23.0, 30.0, 30.0, 17.0, 25.0, 24.0],
30.51390076,
25.70400047,
25.45919991,
27.54000092,
),
(
[26.0, 23.0, 29.0, 15.0, 19.0, 22.0, 25.0],
28.62689972,
24.01350021,
23.78479958,
25.72875023,
),
(
[23.0, 24.0, 24.0, 23.0, 25.0, 24.0, 23.0],
25.46340179,
22.68000031,
22.46399879,
24.30000114,
),
(
[10.0, 100.0, 42.0, 69.0, 3.0, 88.0, 50.0],
101.82029724,
85.09198761,
84.28159332,
91.16999054,
),
];
#[allow(clippy::float_cmp)]
for &(numbers, s_overall, p_ss, p_ss_old, p_overall) in test_values {
assert_eq!(calculate_score_overall(&numbers), s_overall);
assert_eq!(calculate_player_skillset_rating(&numbers), p_ss);
assert_eq!(calculate_player_skillset_rating_pre_070(&numbers), p_ss_old);
assert_eq!(calculate_player_overall(&numbers), p_overall);
}
}
}