diff --git a/2023/day-13/src/part2.rs b/2023/day-13/src/part2.rs index 91ef1a3..d632126 100644 --- a/2023/day-13/src/part2.rs +++ b/2023/day-13/src/part2.rs @@ -1,19 +1,150 @@ +use std::iter::from_fn; + use color_eyre::Result; +use itertools::Itertools; + +#[derive(Debug, PartialEq, Eq)] +enum Fold { + Horizontal(usize), + Vertical(usize), +} + +fn detect_fold(input: &str) -> Option { + detect_vertical_fold(input).or(detect_horizontal_fold(input)) +} + +fn detect_vertical_fold(input: &str) -> Option { + let mut columns_iter_collection = input.lines().map(|line| line.chars()).collect::>(); + let columns = from_fn(move || { + let mut items = Vec::new(); + for iter in &mut columns_iter_collection { + match iter.next() { + Some(item) => items.push(item), + None => return None, + } + } + Some(items) + }) + .collect::>(); + let result = columns + .iter() + .enumerate() + .tuple_windows() + .filter(|((_, line_a), (_, line_b))| { + line_a == line_b + || line_a + .iter() + .zip(line_b.iter()) + .filter(|(a, b)| a != b) + .count() + <= 1 + }) + .find_map(|((index_a, _), (index_b, _))| { + let lines_a = (&columns[0..=index_a]).iter().rev(); + let lines_b = (&columns[index_b..]).iter(); + (lines_a + .flatten() + .zip(lines_b.flatten()) + .filter(|(a, b)| a != b) + .count() + == 1) + .then_some(index_a + 1) + }); + result.map(|num| Fold::Vertical(num)) +} + +fn detect_horizontal_fold(input: &str) -> Option { + let lines = input.lines().collect::>(); + let result = input + .lines() + .enumerate() + .tuple_windows() + .filter(|((_, line_a), (_, line_b))| { + line_a == line_b + || line_a + .chars() + .zip(line_b.chars()) + .filter(|(a, b)| a != b) + .count() + <= 1 + }) + .find_map(|((index_a, _), (index_b, _))| { + let lines_a = (&lines[0..=index_a]).iter().map(|line| line.chars()).rev(); + let lines_b = (&lines[index_b..]).iter().map(|line| line.chars()); + (lines_a + .flatten() + .zip(lines_b.flatten()) + .filter(|(a, b)| a != b) + .count() + == 1) + .then_some(index_a + 1) + }); + result.map(|num| Fold::Horizontal(num)) +} pub fn process(input: &str) -> Result { - todo!("day xx - part 2"); - Ok(0) + let (horizontal, vertical) = + input + .split("\n\n") + .flat_map(detect_fold) + .fold((0, 0), |mut acc, item| match item { + Fold::Horizontal(num) => { + acc.0 += 100 * num; + acc + } + Fold::Vertical(num) => { + acc.1 += num; + acc + } + }); + Ok(horizontal + vertical) } #[cfg(test)] mod tests { + use super::*; #[test] fn test_process() -> Result<()> { - let input = ""; - todo!("haven't built test yet"); - assert_eq!(0, process(input)?); + let input = "#.##..##. +..#.##.#. +##......# +##......# +..#.##.#. +..##..##. +#.#.##.#. + +#...##..# +#....#..# +..##..### +#####.##. +#####.##. +..##..### +#....#..#"; + assert_eq!(400, process(input)?); + Ok(()) + } + + #[test] + fn test_horizontal() -> Result<()> { + let input = "#...##..# +#....#..# +..##..### +#####.##. +#####.##. +..##..### +#....#..#"; + assert_eq!(Some(Fold::Horizontal(1)), detect_fold(input)); + + let input = "#.##..##. +..#.##.#. +##......# +##......# +..#.##.#. +..##..##. +#.#.##.#."; + assert_eq!(Some(Fold::Horizontal(3)), detect_fold(input)); Ok(()) } }