use rayon::iter::{IntoParallelIterator, ParallelIterator};
use crate::{datatypes::Teams, reporting::Report};
mod matching;
mod rng;
mod swiss_system;
use matching::Matchups;
pub use swiss_system::SwissSystem;
#[derive(Debug, Clone)]
pub struct Simulation {
pub teams: Teams,
pub sigma: f32,
pub iterations: u64,
}
impl Simulation {
#[must_use]
pub const fn new(teams: Teams, sigma: f32, iterations: u64) -> Self {
Self {
teams,
sigma,
iterations,
}
}
#[must_use]
pub fn dummy(iterations: u64) -> Self {
Self {
teams: Teams::dummy(),
sigma: 800.0,
iterations,
}
}
pub fn bench_test<R: Report>(&self, mut report: R) -> R {
let mut ss = SwissSystem::new(self.teams.ratings, self.sigma);
let mut rng = rng::deterministic();
for _ in 0..self.iterations {
ss.reset();
ss.simulate_tournament(&mut rng);
report.update(&ss);
}
report
}
pub fn run<R: Report>(&self, fresh_report: R) -> R {
let fresh_ss = SwissSystem::new(self.teams.ratings, self.sigma);
(0..self.iterations)
.into_par_iter()
.map_init(
|| (fresh_ss, rng::random()),
|(ss, rng), _| {
ss.reset();
ss.simulate_tournament(rng);
let mut report = fresh_report;
report.update(ss);
report
},
)
.sum()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::reporting::BasicReport;
#[test]
fn sanity_test() {
let iterations = 1000;
let report = Simulation::dummy(iterations).bench_test(BasicReport::default());
assert_eq!(
(0..16)
.map(|index| report.stats[index].three_zero)
.sum::<u64>(),
iterations * 2
);
assert_eq!(
(0..16)
.map(|index| report.stats[index].advancing)
.sum::<u64>(),
iterations * 6
);
assert_eq!(
(0..16)
.map(|index| report.stats[index].zero_three)
.sum::<u64>(),
iterations * 2
);
assert!(report.stats[0].three_zero > report.stats[15].three_zero);
assert!(report.stats[0].zero_three < report.stats[15].zero_three);
}
}