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}