roulette.rs

4.7 kB · rust · 157 lines

1use mrlylab::roulette::{nodes, spread, Nodes};2use mrlynum::spirograph::{pencils, track, Pencil};34const TOL: f64 = 4e-4;56const SAMPLES: usize = 4000;78const CARPET: [u8; 9] = [1, 1, 1, 1, 0, 1, 1, 1, 1];910const TWO: [u8; 9] = [1, 0, 0, 0, 0, 0, 0, 1, 0];1112// THE SEATS1314fn pin(target: f64) -> Vec<Pencil> {15    let reach = target * 1.5f64.hypot(0.5);16    pencils(&[1, 0, 0], 3, 1, "fill", reach, 0.0, 1).expect("the pin seats")17}1819fn tile(types: &[u8], target: f64) -> Vec<Pencil> {20    let reach = target * 1.5f64.hypot(1.5) / 2f64.sqrt();21    pencils(types, 3, 3, "fill", reach, 0.0, 1).expect("the tile seats")22}2324fn count(25    kind: &str,26    a: usize,27    b: usize,28    seats: &[Pencil],29    samples: usize,30) -> Result<Nodes, String> {31    let path = track(kind, a, b, 4, 1).expect("the track");32    let seats = spread(&path, seats, true);33    let edge = if kind == "in" {34        (1.0f64).min((a - b) as f64 / b as f64)35    } else {36        1.037    };38    for seat in &seats {39        let reach = seat.x.hypot(seat.y);40        if reach <= 0.0 || reach >= edge {41            return Err(format!(42                "{kind} {a}/{b} seats a pencil at {reach}, outside the law's 0 to {edge}"43            ));44        }45    }46    Ok(nodes(&path, &seats, samples, TOL).expect("the nodes"))47}4849// THE LAWS5051pub fn one_curve_of_a_circle_roulette() -> Result<(), String> {52    for (kind, a, b, target) in [53        ("in", 5, 2, 0.5),54        ("in", 7, 3, 0.9),55        ("in", 11, 4, 0.5),56        ("out", 5, 2, 0.9),57        ("out", 7, 3, 0.5),58    ] {59        let selved = count(kind, a, b, &pin(target), SAMPLES)?.selved();60        let want = a * (b - 1);61        if selved != want {62            return Err(format!(63                "{kind} {a}/{b} at a seat of {target} crosses itself {selved} times against {want}"64            ));65        }66    }67    Ok(())68}6970pub fn two_distinct_curves_of_one_wheel() -> Result<(), String> {71    let count = count("in", 7, 4, &tile(&TWO, 0.6), 6000)?;72    if (count.selved(), count.paired()) != (42, 56) {73        return Err(format!(74            "the two curves of 7/4 cross {} times against 56 and themselves {} against 42",75            count.paired(),76            count.selved()77        ));78    }79    Ok(())80}8182pub fn a_whole_design_carries_one_node() -> Result<(), String> {83    let count = count("in", 7, 3, &tile(&CARPET, 0.4), SAMPLES)?;84    let (a, b, k) = (7, 3, 8);85    let want = (k * a * (b - 1), a * b * k * (k - 1));86    if (count.selved(), count.paired()) != want {87        return Err(format!(88            "the carpet on 7/3 carries {} and {} against {} and {}",89            count.selved(),90            count.paired(),91            want.0,92            want.193        ));94    }95    Ok(())96}9798pub fn a_roulette_cuts_the_plane_into() -> Result<(), String> {99    let cells: [(usize, usize, Vec<Pencil>, usize); 5] = [100        (3, 1, pin(0.5), 2),101        (5, 2, pin(0.5), 7),102        (7, 3, pin(0.5), 16),103        (3, 1, tile(&TWO, 0.5), 8),104        (5, 2, tile(&TWO, 0.5), 32),105    ];106    for (a, b, seats, want) in cells {107        let count = count("in", a, b, &seats, SAMPLES)?;108        let faces = count.branches - count.points + 2;109        if faces != want || count.crowded > 0 {110            return Err(format!(111                "in {a}/{b} cuts the plane into {faces} regions against {want}, {} nodes crowded",112                count.crowded113            ));114        }115    }116    Ok(())117}118119// THE ENDS120121pub fn the_loop_threshold_is_not_where() -> Result<(), String> {122    let path = track("in", 7, 6, 4, 1).expect("the track");123    let selved = nodes(&path, &pin(0.9), 6000, TOL)124        .expect("the nodes")125        .selved();126    if selved != 7 {127        return Err(format!(128            "7/6 at a seat of 0.9 crosses itself {selved} times against 7, the law saying 35"129        ));130    }131    let path = track("in", 7, 4, 4, 1).expect("the track");132    let count = nodes(&path, &spread(&path, &tile(&TWO, 0.9), true), 6000, TOL).expect("the nodes");133    if (count.paired(), count.selves.clone()) != (42, vec![21, 21]) {134        return Err(format!(135            "7/4 at seats of 0.9 and 0.636 crosses {} times against 42, the law saying 56, with selves {:?}",136            count.paired(),137            count.selves138        ));139    }140    Ok(())141}142143pub fn the_self_law_ends_at_the() -> Result<(), String> {144    let path = track("in", 6, 5, 4, 1).expect("the track");145    let edge = 1.0 / 5.0;146    for (level, want) in [(0.9, 24), (1.02, 18), (1.3, 6)] {147        let selved = nodes(&path, &pin(level * edge), 6000, TOL)148            .expect("the nodes")149            .selved();150        if selved != want {151            return Err(format!(152                "6/5 at a level of {level} crosses itself {selved} times against {want}"153            ));154        }155    }156    Ok(())157}