spirograph.rs

5.3 kB · rust · 173 lines

1use mrlycore::json::parse;2use mrlydemo::spirograph::*;3use mrlydemo::two::two_grid;45fn carpet() -> Vec<u8> {6    let grid = two_grid("495", 3, 1, 0, 3).unwrap();7    assert_eq!((grid.width, grid.height), (3, 3));8    assert_eq!(grid.types.iter().map(|&b| b as usize).sum::<usize>(), 8);9    assert_eq!(grid.types[4], 0);10    grid.types11}1213fn read(pens: &str, track: &str, ring: usize, wheel: usize, laps: usize) -> mrlycore::Json {14    parse(15        &spirograph_read(16            &carpet(),17            3,18            3,19            pens,20            track,21            ring,22            wheel,23            4,24            laps,25            0.9,26            0.0,27            1,28        )29        .unwrap(),30    )31    .unwrap()32}3334#[test]35fn the_carpet_seats_eight_pencils_and_the_law_counts_the_curves() {36    let four = read("fill", "in", 7, 4, 1);37    assert_eq!(four["pencils"], 8);38    assert_eq!(four["fills"], 8);39    assert_eq!(four["distinct"], 2);40    assert_eq!(read("fill", "in", 7, 2, 1)["distinct"], 4);41    assert_eq!(read("fill", "in", 7, 3, 1)["distinct"], 8);42    assert_eq!(read("fill", "line", 7, 3, 2)["distinct"], 2);43    assert_eq!(read("void", "in", 7, 3, 1)["pencils"], 1);44    assert_eq!(read("corners", "in", 7, 3, 1)["corners"], 16);45}4647#[test]48fn the_ring_over_the_wheel_closes_the_circle() {49    let seven = read("fill", "in", 7, 3, 1);50    assert_eq!(51        format!(52            "{} {} {} {}",53            seven["a"], seven["b"], seven["orbits"], seven["fold"]54        ),55        "7 3 3 7"56    );57    assert_eq!(58        format!("{:.6}", seven["turns"].as_f64().unwrap()),59        "4.000000"60    );61    let trace = spirograph(&carpet(), 3, 3, "fill", "in", 7, 3, 4, 1, 0.9, 0.0, 1, 720).unwrap();62    assert_eq!(trace.len(), 8 * 720 * 2);63    assert!((trace[0] - trace[1438]).abs() < 1e-4 && (trace[1] - trace[1439]).abs() < 1e-4);64    let start = spirograph_pose("in", 7, 3, 4, 1, 0.0).unwrap();65    let end = spirograph_pose("in", 7, 3, 4, 1, 1.0).unwrap();66    assert_eq!(67        format!("{:.6} {:.6} {:.6}", start[0], start[1], start[2]),68        "4.000000 0.000000 0.000000"69    );70    assert_eq!(71        format!("{:.6} {:.6}", end[0], end[2] / std::f64::consts::PI),72        "4.000000 -8.000000"73    );74}7576#[test]77fn the_nodes_come_back_only_inside_the_seat_window() {78    assert_eq!(read("fill", "in", 7, 3, 1)["nodes"], 1288);79    assert_eq!(read("fill", "in", 7, 4, 1)["nodes"], 98);80    assert_eq!(read("fill", "out", 5, 8, 1)["nodes"], 150);81    assert!(read("fill", "in", 7, 6, 1)["nodes"].is_null());82    assert!(read("fill", "line", 7, 3, 2)["nodes"].is_null());83    assert!(read("void", "in", 7, 3, 1)["nodes"].is_null());84    let past =85        parse(&spirograph_read(&carpet(), 3, 3, "fill", "in", 7, 4, 4, 1, 1.35, 0.0, 1).unwrap())86            .unwrap();87    assert_eq!(past["distinct"], 2);88    assert!(past["nodes"].is_null());89    let far =90        parse(&spirograph_read(&carpet(), 3, 3, "corners", "in", 7, 3, 4, 1, 1.2, 0.0, 1).unwrap())91            .unwrap();92    assert_eq!(far["corners"], 16);93    assert!(far["nodes"].is_null());94}9596#[test]97fn a_wheel_that_does_not_fit_is_refused() {98    assert!(spirograph_read(&carpet(), 3, 3, "fill", "in", 3, 3, 4, 1, 0.9, 0.0, 1).is_err());99    assert!(spirograph_read(&carpet(), 3, 3, "fill", "polyin", 4, 3, 3, 1, 0.9, 0.0, 1).is_err());100    assert!(spirograph_read(&carpet(), 3, 3, "edges", "in", 7, 3, 4, 1, 0.9, 0.0, 1).is_err());101}102103#[test]104fn the_cover_walls_the_carpet_and_the_winding_checks_it() {105    let side = 256;106    let cover =107        spirograph_cover(&carpet(), 3, 3, "fill", "in", 7, 3, 4, 1, 0.9, 0.0, 1, side).unwrap();108    assert_eq!(cover.side as usize, side);109    assert_eq!(cover.mask.len(), side * side);110    assert_eq!(111        format!(112            "{:.6} {:.6} {:.6} {:.6} {:.6}",113            cover.covered, cover.hole, cover.wall, cover.winding, cover.areas114        ),115        "0.814487 0.140825 0.269255 9.104609 9.103448"116    );117    let disc = &cover.disc;118    assert_eq!(119        format!("{:.6} {:.6} {:.6}", disc[0], disc[2], disc[3]),120        "0.000000 5.800000 2.200000"121    );122    let inside = cover.mask.iter().filter(|&&code| code > 0).count();123    let shape = cover.mask.iter().filter(|&&code| code == 3).count();124    assert_eq!(format!("{:.6}", shape as f64 / inside as f64), "0.814487");125    let d = 0.9 / (1.5_f64).hypot(0.5);126    for (kind, rho, want) in [127        ("in", 2.0, "0.014922 0.500622 0.508005 0.507814"),128        ("out", 4.0, "0.016671 0.819733 0.828554 0.828445"),129    ] {130        let one = spirograph_cover(131            &[1, 0, 0],132            3,133            1,134            "fill",135            kind,136            3,137            1,138            4,139            1,140            0.9,141            0.0,142            1,143            side,144        )145        .unwrap();146        let sign = if kind == "in" { -1.0 } else { 1.0 };147        let form = rho * (rho + sign * d * d) / (rho + d).powi(2);148        assert!((one.areas - form).abs() < 1e-12);149        assert_eq!(150            format!(151                "{:.6} {:.6} {:.6} {:.6}",152                one.covered, one.hole, one.winding, form153            ),154            want155        );156    }157    assert!(spirograph_cover(158        &carpet(),159        3,160        3,161        "fill",162        "line",163        7,164        3,165        4,166        2,167        0.9,168        0.0,169        1,170        side171    )172    .is_err());173}