From c112bdb4fecec673bffb961f61c17a1470962e3f Mon Sep 17 00:00:00 2001 From: Anthony Oteri Date: Thu, 14 Dec 2023 08:50:38 -0500 Subject: [PATCH] Day 13 - Part 2 (Not Correct) Could not get correct result even though all tests seem to pass Signed-off-by: Anthony Oteri --- day-13/src/part2.rs | 196 +++++++++++++++++++++++++++++++++++++++-- day-13/test-input3.txt | 31 +++++++ 2 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 day-13/test-input3.txt diff --git a/day-13/src/part2.rs b/day-13/src/part2.rs index 1ff3976..d8d721c 100644 --- a/day-13/src/part2.rs +++ b/day-13/src/part2.rs @@ -1,18 +1,204 @@ use crate::error::AocError; +use itertools::Itertools as _; +use nom::character::complete::line_ending; +use nom::{ + bytes::complete::is_a, character::complete::newline, multi::separated_list1, sequence::pair, + IResult, +}; +use tracing::instrument; -#[tracing::instrument] +#[instrument(skip(input))] +fn block(input: &str) -> IResult<&str, Vec<&str>> { + separated_list1(line_ending, is_a(".#"))(input) +} + +#[instrument(skip(input))] +fn parse(input: &str) -> IResult<&str, Vec<(Vec, Vec)>> { + let (input, blocks) = separated_list1(pair(newline, newline), block)(input)?; + + let blocks = blocks + .into_iter() + .map(|block| { + let rows: Vec = block.iter().map(|&s| s.to_string()).collect_vec(); + let cols: Vec = (0..block[0].len()) + .map(|i| { + rows.iter() + .map(|row| row.chars().nth(i).unwrap().to_string()) + .collect::() + }) + .collect_vec(); + + (rows, cols) + }) + .collect_vec(); + + Ok((input, blocks)) +} + +#[instrument] +fn partition(input: Vec) -> (Vec, Vec) { + for i in 0..input.len() - 1 { + if input[i] == input[i + 1] { + let a = input[..=i].to_vec(); + let b = input[i + 1..].to_vec(); + if is_mirror(&a, &b) { + return (a, b); + } + } + } + (input, vec![]) +} + +#[instrument] +fn is_mirror(a: &[T], b: &[T]) -> bool { + if a.is_empty() || b.is_empty() { + return false; + } + + let a: Vec = a.iter().rev().cloned().collect(); + let b: Vec = b.to_vec(); + if a.len() >= b.len() { + return a.starts_with(&b); + } else { + return b.starts_with(&a); + } +} + +#[instrument] +fn smaller_len(a: &Vec, b: &Vec) -> usize { + a.len().min(b.len()) +} + +#[instrument] +fn get_permutations(block: &(Vec, Vec)) -> Vec<(Vec, Vec)> { + let rows = block.0.clone(); + let cols = block.1.clone(); + + let mut permutations = vec![]; + + for i in 0..rows.len() { + for j in 0..cols.len() { + let mut rows = rows.clone(); + let mut cols = cols.clone(); + + if let Some(c) = rows[i].chars().nth(j) { + let c = match c { + '#' => ".", + '.' => "#", + _ => panic!("unexpected character"), + }; + + rows[i].replace_range(j..=j, &c); + } + if let Some(c) = cols[j].chars().nth(i) { + let c = match c { + '#' => ".", + '.' => "#", + _ => panic!("unexpected character"), + }; + + cols[j].replace_range(i..=i, &c); + } + permutations.push((rows, cols)); + } + } + permutations +} + +#[instrument] +fn get_reflection(block: &(Vec, Vec)) -> Option { + let rows = block.0.clone(); + let cols = block.1.clone(); + + let (row_lhs, row_rhs) = partition(rows); + let (col_lhs, col_rhs) = partition(cols); + + if is_mirror(&row_lhs, &row_rhs) { + return Some(100 * row_lhs.len()); + } + if is_mirror(&col_lhs, &col_rhs) { + return Some(col_lhs.len()); + } + + None +} + +#[tracing::instrument(skip(input))] pub fn process(input: &str) -> miette::Result { - Ok(0) + let (input, parsed) = parse(input).unwrap(); + + debug_assert!(input.is_empty()); + + Ok(parsed + .iter() + .flat_map(|b| { + let old_score = get_reflection(b).unwrap_or(0); + let scores = get_permutations(b) + .iter() + .filter_map(get_reflection) + .filter(|&s| s != old_score) + .collect_vec(); + + let new_score = *scores.iter().max().unwrap_or(&0); + dbg!(&old_score, &new_score); + + if new_score != 0 { + Some(new_score) + } else { + Some(old_score) + } + }) + .inspect(|s| { + dbg!(s); + () + }) + .sum::() as u64) } #[cfg(test)] mod tests { use super::*; + use rstest::rstest; + #[test_log::test] - fn test_process() -> miette::Result<()> { - let input = include_str!("../test-input.txt"); - assert_eq!(0, process(input)?); + fn test_permutations() { + let input = ( + vec!["..".to_string(), "..".to_string()], + vec!["..".to_string(), "..".to_string()], + ); + + let output = vec![ + ( + vec!["#.".to_string(), "..".to_string()], + vec!["#.".to_string(), "..".to_string()], + ), + ( + vec![".#".to_string(), "..".to_string()], + vec!["..".to_string(), "#.".to_string()], + ), + ( + vec!["..".to_string(), "#.".to_string()], + vec![".#".to_string(), "..".to_string()], + ), + ( + vec!["..".to_string(), ".#".to_string()], + vec!["..".to_string(), ".#".to_string()], + ), + ]; + + assert_eq!(get_permutations(&input), output); + } + + #[test_log::test(rstest)] + #[case("test-input.txt", 400)] + #[case("test-input3.txt", 1400)] + fn test_process(#[case] filename: &str, #[case] output: u64) -> miette::Result<()> { + let input = + String::from_utf8_lossy(&std::fs::read(std::path::Path::new(filename)).unwrap()) + .parse::() + .unwrap(); + assert_eq!(output, process(&input)?); Ok(()) } } diff --git a/day-13/test-input3.txt b/day-13/test-input3.txt new file mode 100644 index 0000000..6a3fe33 --- /dev/null +++ b/day-13/test-input3.txt @@ -0,0 +1,31 @@ +#.##..##. +..#.##.#. +##......# +##......# +..#.##.#. +..##..##. +#.#.##.#. + +#...##..# +#....#..# +..##..### +#####.##. +#####.##. +..##..### +#....#..# + +.#.##.#.# +.##..##.. +.#.##.#.. +#......## +#......## +.#.##.#.. +.##..##.# + +#..#....# +###..##.. +.##.##### +.##.##### +###..##.. +#..#....# +#..##...# \ No newline at end of file