research-dimers.rs

3.5 kB · rust · 119 lines

1use figures::{ink, save, Board};2use mrlyrs::core::error::Result;3use mrlyrs::core::Rng;4use mrlyrs::math::bang::factory;5use mrlyrs::math::bang::Code;67const LEVEL: usize = 3;8const SIDE: usize = 27;9const CELLS: usize = 512;10const SEED: u64 = 3;11const FLIPS: usize = 400_000;12const NONE: usize = usize::MAX;1314fn neighbours(filled: &[bool], cell: usize) -> Vec<usize> {15    let (r, c) = (cell / SIDE, cell % SIDE);16    let mut out = Vec::with_capacity(4);17    if r > 0 {18        out.push(cell - SIDE);19    }20    if c + 1 < SIDE {21        out.push(cell + 1);22    }23    if r + 1 < SIDE {24        out.push(cell + SIDE);25    }26    if c > 0 {27        out.push(cell - 1);28    }29    out.retain(|&n| filled[n]);30    out31}3233fn augment(links: &[Vec<usize>], mate: &mut [usize], seen: &mut [bool], black: usize) -> bool {34    for &white in &links[black] {35        if std::mem::replace(&mut seen[white], true) {36            continue;37        }38        if mate[white] == NONE || augment(links, mate, seen, mate[white]) {39            mate[white] = black;40            mate[black] = white;41            return true;42        }43    }44    false45}4647fn flip(filled: &[bool], mate: &mut [usize], r: usize, c: usize) {48    let a = r * SIDE + c;49    let (b, d, e) = (a + 1, a + SIDE, a + SIDE + 1);50    if ![a, b, d, e].iter().all(|&x| filled[x]) {51        return;52    }53    if mate[a] == b && mate[d] == e {54        (mate[a], mate[d], mate[b], mate[e]) = (d, a, e, b);55    } else if mate[a] == d && mate[b] == e {56        (mate[a], mate[b], mate[d], mate[e]) = (b, a, e, d);57    }58}5960fn main() -> Result<()> {61    let design = factory::create(Code::from(495u128), 3, 2, 3, LEVEL)?;62    assert_eq!(design.shape, vec![SIDE, SIDE]);63    let filled: Vec<bool> = (0..SIDE * SIDE).map(|f| design.at(f) == 1).collect();64    assert_eq!(filled.iter().filter(|&&on| on).count(), CELLS);65    let links: Vec<Vec<usize>> = (0..SIDE * SIDE).map(|i| neighbours(&filled, i)).collect();66    let blacks: Vec<usize> = (0..SIDE * SIDE)67        .filter(|&i| filled[i] && (i / SIDE + i % SIDE).is_multiple_of(2))68        .collect();69    assert_eq!(2 * blacks.len(), CELLS);7071    let mut mate = vec![NONE; SIDE * SIDE];72    for &black in &blacks {73        let mut seen = vec![false; SIDE * SIDE];74        assert!(augment(&links, &mut mate, &mut seen, black));75    }76    let mut rng = Rng::new(SEED);77    for _ in 0..FLIPS {78        flip(&filled, &mut mate, rng.below(SIDE - 1), rng.below(SIDE - 1));79    }80    for cell in 0..SIDE * SIDE {81        if filled[cell] {82            assert!(links[cell].contains(&mate[cell]));83            assert_eq!(mate[mate[cell]], cell);84        } else {85            assert_eq!(mate[cell], NONE);86        }87    }8889    let mut board = Board::square();90    let frame = board.frame(0.08);91    let unit = frame.w / SIDE as f64;92    let pad = unit * 0.11;93    let thick = unit - 2.0 * pad;94    let mut dominoes = 0;95    for &black in &blacks {96        let white = mate[black];97        let (lo, hi) = (black.min(white), black.max(white));98        let flat = hi == lo + 1;99        let (r, c) = (lo / SIDE, lo % SIDE);100        let (x, y) = (frame.x + c as f64 * unit, frame.y + r as f64 * unit);101        let (w, h, color) = if flat {102            (2.0 * unit, unit, ink::blue())103        } else {104            (unit, 2.0 * unit, ink::orange())105        };106        board.round_rect(107            x + pad,108            y + pad,109            w - 2.0 * pad,110            h - 2.0 * pad,111            thick * 0.3,112            color,113        );114        dominoes += 1;115    }116    assert_eq!(2 * dominoes, CELLS);117    save("research-dimers", &board)?;118    Ok(())119}