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}