heh
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 247 |
1 files changed, 229 insertions, 18 deletions
diff --git a/src/main.rs b/src/main.rs index d878a4e..586ad1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![allow(confusable_idents, uncommon_codepoints, mixed_script_confusables)] #![feature( array_windows, + slice_take, test, slice_as_chunks, array_chunks, @@ -9,30 +10,240 @@ )] extern crate test; mod util; - pub use util::prelude::*; -/// generated by passing 1, 0{20} and 0, 1, 0{19}, etc to the original -const INTERPOLATION_P1: [i32; 21] = [ - 1, -21, 210, -1330, 5985, -20349, 54264, -116280, 203490, -293930, 352716, -352716, 293930, - -203490, 116280, -54264, 20349, -5985, 1330, -210, 21, -]; -/// just the reversed version of [`INTERPOLATION_P1`] -const INTERPOLATION_P2: [i32; 21] = [ - 21, -210, 1330, -5985, 20349, -54264, 116280, -203490, 293930, -352716, 352716, -293930, - 203490, -116280, 54264, -20349, 5985, -1330, 210, -21, 1, -]; +#[repr(u8)] +#[derive(Copy, Clone, PartialEq, Eq)] +enum Pipe { + /// │ + NS = b'|', + /// ─ + EW = b'-', + /// ╰ + NE = b'L', + /// ╯ + NW = b'J', + /// ╮ + SW = b'7', + /// ╭ + SE = b'F', + #[allow(dead_code)] // transmute() go brr + Ground = b'.', + Start = b'S', +} + +#[derive(Copy, Clone, Debug)] +enum D { + N, + E, + S, + W, +} + +impl Pipe { + fn ch(self) -> char { + match self { + Pipe::NS => '│', + Pipe::EW => '─', + Pipe::NE => '╰', + Pipe::NW => '╯', + Pipe::SW => '╮', + Pipe::SE => '╭', + Pipe::Ground => '.', + Pipe::Start => 'S', + } + } + + fn n(self) -> bool { + matches!(self, Pipe::NS | Pipe::NE | Pipe::NW) + } + + fn e(self) -> bool { + matches!(self, Pipe::EW | Pipe::NE | Pipe::SE) + } + + fn s(self) -> bool { + matches!(self, Pipe::SW | Pipe::NS | Pipe::SE) + } + + fn w(self) -> bool { + matches!(self, Pipe::EW | Pipe::NW | Pipe::SW) + } +} + +impl std::fmt::Display for Pipe { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.ch()) + } +} + +struct Map<const S: usize> { + map: [[Pipe; S]; S], +} + +impl<const N: usize> std::fmt::Display for Map<N> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for x in self.map { + for y in x { + write!(f, "{y}")?; + } + writeln!(f)?; + } + Ok(()) + } +} + +impl<const S: usize> Map<S> { + fn at(&self, x: u8, y: u8) -> Pipe { + self.map[y.nat()][x.nat()] + } + + fn start(&self, x: u8, y: u8) -> (Pipe, D) { + let surround = [ + self.at(x - 1, y).s() as u8, + self.at(x, y + 1).w() as u8, + self.at(x, y - 1).e() as u8, + self.at(x + 1, y).n() as u8, + ]; + match surround { + [1, 1, 0, 0] => (Pipe::NE, D::E), + [1, 0, 1, 0] => (Pipe::NS, D::S), + [1, 0, 0, 1] => (Pipe::NW, D::W), + [0, 1, 1, 0] => (Pipe::SE, D::S), + [0, 1, 0, 1] => (Pipe::EW, D::W), + [0, 0, 1, 1] => (Pipe::SW, D::S), + _ => dang!(), + } + } + + fn go(&self, p: Pipe, x: &mut u8, y: &mut u8, d: D) { + use D::*; + #[rustfmt::skip] + macro_rules! n { () => { *y -= 1 }; } + #[rustfmt::skip] + macro_rules! e { () => { *x += 1 }; } + #[rustfmt::skip] + macro_rules! s { () => { *y += 1 }; } + #[rustfmt::skip] + macro_rules! w { () => { *x -= 1 }; } + mat!(p { + Pipe::NS => mat!(d { + N => n!(), + S => s!(), + }), + Pipe::EW => mat!(d { + E => e!(), + W => w!(), + }), + Pipe::NE => mat!(d { + N => n!(), + E => e!(), + }), + Pipe::NW => mat!(d { + N => n!(), + W => w!(), + }), + Pipe::SW => mat!(d { + S => s!(), + W => w!(), + }), + Pipe::SE => mat!(d { + E => e!(), + S => s!(), + }), + }) + } + + fn turn(&self, p: Pipe, d: &mut D) { + use D::*; + #[rustfmt::skip] + macro_rules! n { () => { *d = N }; } + #[rustfmt::skip] + macro_rules! e { () => { *d = E }; } + #[rustfmt::skip] + macro_rules! s { () => { *d = S }; } + #[rustfmt::skip] + macro_rules! w { () => { *d = W }; } + mat!(p { + Pipe::NS => mat!(d { + N => n!(), // keep going north + S => s!(), // keep going south + }), + Pipe::EW => mat!(d { + E => e!(), // keep going east + W => w!(), // keep going west + }), + Pipe::NE => mat!(d { + W => n!(), // start going north + S => e!(), // start going east + }), + Pipe::NW => mat!(d { + E => n!(), // start going north + S => w!(), // start going west + }), + Pipe::SW => mat!(d { + E => s!(), // start going south + N => w!(), // start going west + }), + Pipe::SE => mat!(d { + N => e!(), // start going east + W => s!(), // start going south + }), + }) + } + + fn run(&self) -> usize { + let mut x = 0; + let mut y = 0; + for (r, j) in self.map.iter().zip(0..) { + for (&c, i) in r.iter().zip(0..) { + if c == Pipe::Start { + x = i; + y = j; + break; + } + } + } + + let (mut at, mut dir) = self.start(x, y); + let mut steps = 1; + loop { + self.go(at, &mut x, &mut y, dir); + at = self.at(x, y); + if at == Pipe::Start { + break; + } + self.turn(at, &mut dir); + steps += 1; + } + steps / 2 + } +} -pub fn solve(a: impl Iterator<Item = i32>, interp: [i32; 21]) -> i32 { - a.zip(interp.into_iter()) - .map(|(a, b)| a as i64 * b as i64) - .sum::<i64>() as i32 +impl<const S: usize> From<&[u8]> for Map<S> { + fn from(mut i: &[u8]) -> Self { + Self { + map: (0..S) + .map(|n| { + let inner = i + .take(..S) + .α() + .iter() + .map(|&b| unsafe { std::mem::transmute(b) }) + .Ν(); + if n != S - 1 { + i.skip(1); + } + inner + }) + .Ν(), + } + } } pub fn run(i: &str) -> impl Display { - i.行() - .map(|x| solve(&mut x.κ(), INTERPOLATION_P2)) - .sum::<i32>() + let map = Map::<140>::from(i.as_bytes()); + map.run() } fn main() { |