research-windows.rs
4.7 kB · rust · 167 lines
1use figures::{ink, save, Board, Color};2use mrlyrs::core::error::Result;3use mrlyrs::math::bang::factory;4use mrlyrs::math::bang::Code;5use std::collections::BTreeSet;67const LEVEL: usize = 3;8const SIDE: usize = 27;9const SCAN: usize = 5;10const COUNTS: [usize; 4] = [2, 10, 40, 74];11const RING: usize = 11;12const CELL: usize = 22;13const HAIR: usize = 2;14const GUTTER: usize = 15;1516type Window = Vec<u8>;1718fn render(level: usize) -> Result<(usize, Vec<u8>)> {19 let design = factory::create(Code::from(495u128), 3, 2, 3, level)?;20 let side = 3usize.pow(level as u32);21 assert_eq!(design.shape, vec![side, side]);22 assert_eq!(design.sum(), 8u64.pow(level as u32));23 let parity = factory::create(Code::from(7u128), 3, 2, 2, level)?;24 assert_eq!(design.bytes()?, parity.bytes()?);25 Ok((side, design.bytes()?.to_vec()))26}2728fn windows(side: usize, cells: &[u8], k: usize) -> BTreeSet<Window> {29 let mut out = BTreeSet::new();30 for r in 0..=side - k {31 for c in 0..=side - k {32 out.insert(33 (0..k * k)34 .map(|i| cells[(r + i / k) * side + c + i % k])35 .collect(),36 );37 }38 }39 out40}4142fn turn(w: &[u8]) -> Window {43 (0..9).map(|i| w[(2 - i % 3) * 3 + i / 3]).collect()44}4546fn orbit(w: &[u8]) -> Vec<Window> {47 let mut out = vec![w.to_vec()];48 loop {49 let next = turn(&out[out.len() - 1]);50 if next == out[0] {51 return out;52 }53 out.push(next);54 }55}5657fn ones(w: &[u8]) -> usize {58 w.iter().filter(|&&v| v == 1).count()59}6061fn low(w: &[u8]) -> usize {62 (0..9).filter(|&i| w[i] == 1).map(|i| i / 3).sum()63}6465fn ring(three: &BTreeSet<Window>) -> Vec<(usize, usize, Window)> {66 let mut seen = BTreeSet::new();67 let mut reps = Vec::new();68 let mut fixed = Vec::new();69 for w in three {70 if seen.contains(w) {71 continue;72 }73 let orb = orbit(w);74 seen.extend(orb.iter().cloned());75 if orb.len() == 4 {76 reps.push(orb.into_iter().max_by_key(|o| (low(o), o.clone())).unwrap());77 } else {78 fixed.extend(orb);79 }80 }81 reps.sort_by_key(|w| (ones(w), w.clone()));82 assert_eq!(reps.len(), RING - 2);83 assert_eq!(fixed.len(), 4);84 let pick = |n: usize, head: u8| -> Window {85 let found: Vec<&Window> = fixed86 .iter()87 .filter(|w| ones(w) == n && w[0] == head)88 .collect();89 assert_eq!(found.len(), 1);90 found[0].clone()91 };92 let last = RING - 1;93 let mut slots = vec![94 (0, 0, pick(7, 1)),95 (0, last, pick(7, 0)),96 (last, last, pick(8, 1)),97 (last, 0, pick(0, 0)),98 ];99 assert_eq!(turn(&slots[0].2), slots[1].2);100 for (i, rep) in reps.iter().enumerate() {101 let a = turn(rep);102 let b = turn(&a);103 let c = turn(&b);104 slots.push((0, i + 1, rep.clone()));105 slots.push((i + 1, last, a));106 slots.push((last, last - 1 - i, b));107 slots.push((last - 1 - i, 0, c));108 }109 let drawn: BTreeSet<Window> = slots.iter().map(|s| s.2.clone()).collect();110 assert_eq!(&drawn, three);111 assert_eq!(slots.len(), 4 * RING - 4);112 slots113}114115fn cells(116 board: &mut Board,117 x: usize,118 y: usize,119 side: usize,120 w: &[u8],121 on: Color,122 off: Option<Color>,123) {124 for (i, &v) in w.iter().enumerate() {125 let color = if v == 1 { Some(on) } else { off };126 if let Some(color) = color {127 let (cx, cy) = (x + (i % side) * CELL, y + (i / side) * CELL);128 let size = (CELL - HAIR) as f64;129 board.rect(cx as f64, cy as f64, size, size, color);130 }131 }132}133134fn main() -> Result<()> {135 let (side, scan) = render(SCAN)?;136 let (before, coarse) = render(SCAN - 1)?;137 for (k, count) in COUNTS.iter().enumerate() {138 let found = windows(side, &scan, k + 1);139 assert_eq!(found.len(), *count);140 assert_eq!(found, windows(before, &coarse, k + 1));141 }142 let three = windows(side, &scan, 3);143 let slots = ring(&three);144 let (ground, carpet) = render(LEVEL)?;145 assert_eq!(ground, SIDE);146147 let mut board = Board::square();148 let tile = 3 * CELL - HAIR;149 let span = RING * tile + (RING - 1) * GUTTER;150 let origin = (board.width - span) / 2;151 let inner = (board.width - (SIDE * CELL - HAIR)) / 2;152 cells(153 &mut board,154 inner,155 inner,156 SIDE,157 &carpet,158 ink::fade(ink::dim(), 0.75),159 None,160 );161 for (r, c, w) in &slots {162 let (x, y) = (origin + c * (tile + GUTTER), origin + r * (tile + GUTTER));163 cells(&mut board, x, y, 3, w, ink::blue(), Some(ink::line()));164 }165 save("research-windows", &board)?;166 Ok(())167}