veilus-human-input 0.1.0

Human-like mouse paths, wheel scrolling and typing rhythm for browser automation: pure functions, parameters supplied by the caller.
Documentation
use rand::Rng;

/// One draw from a log-normal distribution with the given median and sigma
/// (of the underlying normal). Box-Muller, to avoid a distribution crate.
pub(crate) fn log_normal(median: f64, sigma: f64, rng: &mut impl Rng) -> f64 {
    let (u1, u2): (f64, f64) = (rng.gen_range(f64::EPSILON..1.0), rng.gen());
    let z = (-2.0 * u1.ln()).sqrt() * (std::f64::consts::TAU * u2).cos();
    median * (sigma * z).exp()
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand::rngs::StdRng;
    use rand::SeedableRng;

    #[test]
    fn log_normal_median_matches_parameter() {
        let mut rng = StdRng::seed_from_u64(1);
        let mut v: Vec<f64> = (0..4001)
            .map(|_| log_normal(200.0, 0.5, &mut rng))
            .collect();
        v.sort_by(f64::total_cmp);
        let median = v[2000];
        assert!((185.0..=215.0).contains(&median), "{median}");
        assert!(v.iter().all(|&x| x > 0.0));
    }
}