heh
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 282 |
1 files changed, 57 insertions, 225 deletions
diff --git a/src/main.rs b/src/main.rs index bc47c69..8969ecb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,258 +15,90 @@ pub use util::prelude::*; #[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', +enum Element { + Space = b'.', + Galaxy = b'#', #[allow(dead_code)] New = 10, } -#[derive(Copy, Clone, Debug)] -enum D { - N, - E, - S, - W, -} - -impl std::fmt::Debug for Pipe { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", *self as u8 as char) +impl Element { + fn galaxy(self) -> bool { + self == Self::Galaxy } -} -impl Pipe { - fn ch(self) -> char { - match self { - Self::New => panic!(), - 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) + fn space(self) -> bool { + self == Self::Space } } -impl std::fmt::Display for Pipe { +impl std::fmt::Debug for Element { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.ch()) + if *self as u8 == 10 { + return write!(f, "@"); + } + write!(f, "{}", *self as u8 as char) } } const S: u8 = 140; -const WI: u16 = S as u16 + 1; +const W: u16 = S as u16 + 1; struct Map<'a> { - map: &'a [Pipe], + map: &'a [Element], } impl<'a> std::ops::Index<u16> for Map<'a> { - type Output = Pipe; + type Output = Element; fn index(&self, index: u16) -> &'a Self::Output { unsafe { self.map.get_unchecked(index.nat()) } } } -impl std::fmt::Display for Map<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - pa(self.map); - for x in 0..S { - for y in 0..S { - write!(f, "{}", self.at(x, y))?; - } - writeln!(f)?; - } - - Ok(()) - } -} - impl Map<'_> { - fn at(&self, x: u8, y: u8) -> Pipe { - self[y.widen() * WI + x.widen()] - } - - fn start(&self, offset: u16) -> (Pipe, D) { - if self[offset - 1].e() && self[offset - WI] == Pipe::NW && self[offset + WI].n() { - return (Pipe::SW, D::S); - } - match [ - self[offset - 1].s() as u8, - self[offset + WI].w() as u8, - self[offset - WI].e() as u8, - self[offset + 1].n() as u8, - ] { - [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, offset: u16, d: D) -> u16 { - use D::*; - #[rustfmt::skip] - macro_rules! n { () => { offset - WI }; } - #[rustfmt::skip] - macro_rules! e { () => { offset + 1 }; } - #[rustfmt::skip] - macro_rules! s { () => { offset + WI }; } - #[rustfmt::skip] - macro_rules! w { () => { offset - 1 }; } - mat!(p { - Pipe::EW => mat!(d { - E => e!(), - W => w!(), - }), - Pipe::SW => mat!(d { - S => s!(), - W => w!(), - }), - Pipe::NS => mat!(d { - N => n!(), - S => s!(), - }), - Pipe::SE => mat!(d { - E => e!(), - S => s!(), - }), - Pipe::NE => mat!(d { - N => n!(), - E => e!(), - }), - Pipe::NW => mat!(d { - N => n!(), - W => w!(), - }), - }) - } - - fn turn(&self, p: Pipe, d: D) -> D { - use D::*; - mat!(p { - Pipe::EW => mat!(d { - E => E, // keep going east - W => W, // keep going west - }), - 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 - }), - Pipe::NS => mat!(d { - N => N, // keep going north - S => S, // keep going south - }), - Pipe::NE => mat!(d { - W => N, // start going north - S => E, // start going east - }), - }) - } - - fn p2(&self) -> usize { - let mut offset = self.search(); - let mut network = vec![None; WI as usize * WI as usize]; - let (mut at, mut dir) = self.start(offset); - network[offset.nat()] = Some(at); - loop { - offset = self.go(at, offset, dir); - at = self[offset]; - if at == Pipe::Start { - break; - } - network[offset.nat()] = Some(at); - dir = self.turn(at, dir); - } - - let mut inside = 0; - for row in unsafe { network.as_chunks_unchecked::<141>() } - .iter() - .skip(30) - .take(90) - { - let mut up = 0u8; - for &x in row.iter().take(110) { - match x { - Some(x) => { - if x.n() { - unsafe { up = up.unchecked_add(1) }; - } - } - None => { - if up % 2 != 0 { - inside += 1; - } + fn at(&self, x: u8, y: u8) -> Element { + self[y.widen() * W + x.widen()] + } + + fn solve(&self) -> usize { + let mut n = 0u8; + let emptyr = { + self.map + .chunks(W.nat()) + .map(|x| { + if x.iter().take(S.nat()).copied().all(Element::space) { + n += 1; } + n + }) + .Ν::<{ S as usize }>() + }; + let mut n = 0u8; + let emptyc = (0..S) + .map(move |x| (0..S).map(move |y| self.at(x, y))) + .map(|mut x| { + if x.all(Element::space) { + n += 1; } - } - } - inside - } - - fn search(&self) -> u16 { - self.map.iter().position(|&x| x == Pipe::Start).unwrap() as u16 - } - - fn p1(&self) -> usize { - let mut offset = self.search(); - let (mut at, mut dir) = self.start(offset); - let mut steps = 1; - loop { - offset = self.go(at, offset, dir); - at = self[offset]; - if at == Pipe::Start { - break; - } - dir = self.turn(at, dir); - steps += 1; - } - steps / 2 + n + }) + .Ν::<{ S as usize }>(); + + (0..S) + .flat_map(|y| (0..S).map(move |x| (x, y))) + .filter(|&(x, y)| self.at(x, y).galaxy()) + .tuple_combinations() + .map(|((x1, y1), (x2, y2))| { + let expand = 2; + // let expand = 1000000; + ((y1 as i16 - y2 as i16).abs() + (x1 as i16 - x2 as i16).abs()) as usize + + (expand - 1) + * (emptyr[y1.max(y2).nat()].nat() - emptyr[y1.min(y2).nat()].nat()) + + (expand - 1) + * (emptyc[x1.max(x2).nat()].nat() - emptyc[x1.min(x2).nat()].nat()) + }) + .sum() } } @@ -280,7 +112,7 @@ impl From<&[u8]> for Map<'_> { pub fn run(i: &str) -> impl Display { let map = Map::from(i.as_bytes()); - map.p2() + map.solve() } fn main() { |