Implement RNR rating adjustment

This commit is contained in:
Kiana Sheibani 2023-10-04 17:58:54 -04:00
parent 1b603bf727
commit 2e3bd017f3
Signed by: toki
GPG key ID: 6CB106C25E86A9F7
5 changed files with 240 additions and 75 deletions

View file

@ -8,31 +8,31 @@ use sqlite::*;
// Score calculation
/// Calculate the collective expected score for each team.
fn expected_scores(ratings: &Teams<&mut f64>) -> Vec<f64> {
let qs: Vec<f64> = ratings
.into_iter()
.map(|es| 10_f64.powf(es.iter().map(|x| **x).sum::<f64>() / es.len() as f64 / 400.0))
.collect();
let sumq: f64 = qs.iter().sum();
qs.into_iter().map(|q| q / sumq).collect()
}
// /// Calculate the collective expected score for each team.
// fn expected_scores(ratings: &Teams<&mut f64>) -> Vec<f64> {
// let qs: Vec<f64> = ratings
// .into_iter()
// .map(|es| 10_f64.powf(es.iter().map(|x| **x).sum::<f64>() / es.len() as f64 / 400.0))
// .collect();
// let sumq: f64 = qs.iter().sum();
// qs.into_iter().map(|q| q / sumq).collect()
// }
/// Adjust the ratings of each player based on who won.
fn adjust_ratings(ratings: Teams<&mut f64>, winner: usize) {
let exp_scores = expected_scores(&ratings);
// /// Adjust the ratings of each player based on who won.
// fn adjust_ratings(ratings: Teams<&mut f64>, winner: usize) {
// let exp_scores = expected_scores(&ratings);
ratings
.into_iter()
.zip(exp_scores.into_iter())
.enumerate()
.for_each(|(i, (es, exp_sc))| {
let len = es.len() as f64;
let score = f64::from(winner == i);
es.into_iter()
.for_each(|e| *e += 40.0 * (score - exp_sc) / len);
})
}
// ratings
// .into_iter()
// .zip(exp_scores.into_iter())
// .enumerate()
// .for_each(|(i, (es, exp_sc))| {
// let len = es.len() as f64;
// let score = f64::from(winner == i);
// es.into_iter()
// .for_each(|e| *e += 40.0 * (score - exp_sc) / len);
// })
// }
// Extract set data
@ -135,14 +135,41 @@ fn update_from_set(connection: &Connection, dataset: &str, results: SetData) ->
let players_data = results.teams;
add_players(connection, dataset, &players_data)?;
let mut elos = get_ratings(connection, dataset, &players_data)?;
adjust_ratings(
elos.iter_mut()
.map(|v| v.iter_mut().map(|x| &mut x.1).collect())
.collect(),
results.winner,
);
update_ratings(connection, dataset, elos)
// Singles matches are currently not supported
if players_data.len() != 2 || players_data[0].len() != 1 || players_data[1].len() != 1 {
return Ok(());
}
let mut it = players_data.into_iter();
let player1 = it.next().unwrap()[0].id;
let player2 = it.next().unwrap()[0].id;
let advantage = get_advantage(connection, dataset, player1, player2)
.or_else(|_| hypothetical_advantage(connection, dataset, player1, player2))?;
let adjust = 40.0 * (1.0 - 1.0 / (1.0 + 10_f64.powf(advantage / 400.0)));
if results.winner == 0 {
adjust_advantages(connection, dataset, player1, 0.5 * adjust)?;
adjust_advantages(connection, dataset, player2, -0.5 * adjust)?;
adjust_advantage(
connection,
dataset,
player1,
player2,
-2.0 * (1.0 - 0.5) * adjust,
)?;
} else {
adjust_advantages(connection, dataset, player1, -0.5 * adjust)?;
adjust_advantages(connection, dataset, player2, 0.5 * adjust)?;
adjust_advantage(
connection,
dataset,
player1,
player2,
2.0 * (1.0 - 0.5) * adjust,
)?;
}
Ok(())
}
pub fn sync_dataset(