diff --git a/src/days/day13.rs b/src/days/day13.rs new file mode 100644 index 0000000..209aff3 --- /dev/null +++ b/src/days/day13.rs @@ -0,0 +1,130 @@ +use std::{cmp::Ordering, fmt::Debug}; + +use aoc_runner_derive::{aoc, aoc_generator}; +use itertools::{EitherOrBoth, Itertools}; + +#[derive(Clone, PartialEq, Eq)] +enum Data { + Integer(u32), + List(Vec), +} + +impl Debug for Data { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Integer(i) => write!(f, "{i}"), + Self::List(l) => f.debug_list().entries(l).finish(), + } + } +} + +impl PartialOrd for Data { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Data { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Data::Integer(a), Data::Integer(b)) => a.cmp(b), + (a @ Data::Integer(_), b @ Data::List(_)) => b.cmp(a).reverse(), + (a @ Data::List(_), Data::Integer(b)) => { + a.cmp(&Data::List(Vec::from([Data::Integer(*b)]))) + } + (Data::List(a), Data::List(b)) => a + .iter() + .zip_longest(b) + .find_map(|els| match els { + EitherOrBoth::Both(a, b) => { + let res = a.cmp(b); + (!res.is_eq()).then_some(res) + } + EitherOrBoth::Left(_) => Some(Ordering::Greater), + EitherOrBoth::Right(_) => Some(Ordering::Less), + }) + .unwrap_or(Ordering::Equal), + } + } +} + +impl Data { + fn parse(s: &str) -> Option<(Self, &str)> { + if let Some(mut rest) = s.strip_prefix('[') { + let mut vec = Vec::new(); + + loop { + if let Some(rest) = rest.strip_prefix(']') { + return Some((Self::List(vec), rest)); + } + + let (val, rest2) = Self::parse(rest)?; + vec.push(val); + + if let Some(rest) = rest2.strip_prefix(']') { + return Some((Self::List(vec), rest)); + } + + let rest2 = rest2.strip_prefix(',')?; + rest = rest2; + } + } else if s.chars().next()?.is_alphanumeric() { + let (num_part, rest) = s + .char_indices() + .find_map(|(i, c)| (!c.is_numeric()).then_some(s.split_at(i))) + .unwrap_or((s, "")); + + Some((Self::Integer(num_part.parse().ok()?), rest)) + } else { + return None; + } + } +} + +#[aoc_generator(day13)] +fn generator(input: &str) -> Vec<(Data, Data)> { + input + .lines() + .chunks(3) + .into_iter() + .map(|mut v| { + ( + Data::parse(v.next().unwrap()).unwrap().0, + Data::parse(v.next().unwrap()).unwrap().0, + ) + }) + .collect() +} + +#[aoc(day13, part1)] +fn part1(input: &[(Data, Data)]) -> usize { + input + .iter() + .positions(|(a, b)| a < b) + .map(|v| v + 1) // adjust for one-indexing + .sum() +} + +#[aoc(day13, part2)] +fn part2(input: &[(Data, Data)]) -> usize { + let mut vec = input + .iter() + .flat_map(|(a, b)| [a.clone(), b.clone()]) + .map(|v| (v, false)) + .chain([ + (Data::parse("[[2]]").unwrap().0, true), + (Data::parse("[[6]]").unwrap().0, true), + ]) + .collect::>(); + + vec.sort_by(|a, b| a.0.cmp(&b.0)); + + let (i, j) = vec + .iter() + .enumerate() + .filter_map(|(i, (_, is_divider))| is_divider.then_some(i + 1)) + .next_tuple() + .unwrap(); + + i * j +} diff --git a/src/lib.rs b/src/lib.rs index 25e5eb4..9153be2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ mod days { mod day10; mod day11; mod day12; + mod day13; } aoc_lib! { year = 2022 }