wiki-subshift-of-finite-type.rs
2.6 kB · rust · 84 lines
1use figures::{ink, save, Board, Color};2use mrlyrs::core::error::Result;3use std::f64::consts::{FRAC_PI_2, TAU};45const DEPTH: usize = 8;67fn allowed(word: u32, length: usize) -> bool {8 let bits = word & ((1u32 << length) - 1);9 bits & (bits >> 1) == 010}1112fn sector(13 board: &mut Board,14 center: (f64, f64),15 radii: (f64, f64),16 turns: (f64, f64),17 gap: f64,18 color: Color,19) {20 let (inner, outer) = radii;21 let at = |r: f64, turn: f64| {22 let angle = TAU * turn - FRAC_PI_2;23 (center.0 + r * angle.cos(), center.1 + r * angle.sin())24 };25 let side = |r: f64| {26 let trim = gap / (2.0 * r * TAU);27 (turns.0 + trim, turns.1 - trim)28 };29 let steps =30 |r: f64, span: (f64, f64)| ((span.1 - span.0) * TAU * r / 3.0).ceil().max(1.0) as usize;31 let (far, near) = (side(outer), side(inner));32 let mut pts = Vec::new();33 let n = steps(outer, far);34 for i in 0..=n {35 pts.push(at(outer, far.0 + (far.1 - far.0) * i as f64 / n as f64));36 }37 let n = steps(inner, near);38 for i in (0..=n).rev() {39 pts.push(at(inner, near.0 + (near.1 - near.0) * i as f64 / n as f64));40 }41 board.polygon(&pts, color);42}4344fn main() -> Result<()> {45 let counts: Vec<usize> = (1..=DEPTH)46 .map(|length| (0..1u32 << length).filter(|&w| allowed(w, length)).count())47 .collect();48 assert_eq!(counts, vec![2, 3, 5, 8, 13, 21, 34, 55]);4950 let mut board = Board::square();51 let frame = board.frame(0.08);52 let center = frame.center();53 let reach = frame.w.min(frame.h) / 2.0;54 let hole = reach * 0.16;55 let step = (reach - hole) / DEPTH as f64;56 let rim = 4.0;57 let gap = 4.0;5859 board.disc(center.0, center.1, hole * 0.42, ink::dim());60 for length in 1..=DEPTH {61 let inner = hole + step * (length - 1) as f64 + rim / 2.0;62 let outer = inner + step - rim;63 let slot = 1.0 / (1u32 << length) as f64;64 for word in 0..1u32 << length {65 let parent = word >> 1;66 if length > 1 && !allowed(parent, length - 1) {67 continue;68 }69 let color = if allowed(word, length) {70 if word & 1 == 1 {71 ink::yellow()72 } else {73 ink::blue()74 }75 } else {76 ink::fade(ink::line(), 0.7)77 };78 let turns = (word as f64 * slot, (word + 1) as f64 * slot);79 sector(&mut board, center, (inner, outer), turns, gap, color);80 }81 }82 save("wiki-subshift-of-finite-type", &board)?;83 Ok(())84}