From 0ab91c4a2a802db982a3a5d8fbf0eb523d8845e8 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sat, 16 Dec 2023 20:30:23 +0200 Subject: [PATCH] part 2 --- 2023/Cargo.lock | 45 +++--- 2023/day-12/Cargo.toml | 2 + 2023/day-12/src/part2.rs | 288 ++++++++++----------------------------- 3 files changed, 95 insertions(+), 240 deletions(-) diff --git a/2023/Cargo.lock b/2023/Cargo.lock index a74abdd..0831e0b 100644 --- a/2023/Cargo.lock +++ b/2023/Cargo.lock @@ -97,9 +97,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -108,22 +108,21 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] @@ -203,6 +202,8 @@ name = "day-12" version = "0.1.0" dependencies = [ "color-eyre", + "itertools", + "nom", ] [[package]] @@ -213,9 +214,9 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "eyre" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" dependencies = [ "indenter", "once_cell", @@ -262,9 +263,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "memchr" @@ -330,9 +331,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "owo-colors" @@ -390,12 +391,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "sharded-slab" version = "0.1.7" @@ -407,9 +402,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -418,18 +413,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", diff --git a/2023/day-12/Cargo.toml b/2023/day-12/Cargo.toml index 7658550..1eb3508 100644 --- a/2023/day-12/Cargo.toml +++ b/2023/day-12/Cargo.toml @@ -7,3 +7,5 @@ edition = "2021" [dependencies] color-eyre.workspace = true +itertools.workspace = true +nom.workspace = true diff --git a/2023/day-12/src/part2.rs b/2023/day-12/src/part2.rs index 81bb634..28fa155 100644 --- a/2023/day-12/src/part2.rs +++ b/2023/day-12/src/part2.rs @@ -1,125 +1,89 @@ -use std::str::FromStr; - use color_eyre::Result; +use itertools::{repeat_n, Itertools}; +use nom::{ + bytes::complete::{is_a, tag}, + character::complete::{self, space1}, + multi::separated_list1, + sequence::separated_pair, + IResult, +}; -#[derive(Debug, Clone, Copy, PartialEq)] -enum SpringStatus { - Operational, - Unknown, - Damaged, +#[derive(Debug)] +struct Puzzle { + spaces_to_fill: usize, + line: String, + batches: Vec, } -#[derive(Debug, Clone, PartialEq, Default)] -struct Spring { - status: Vec, - condition: Vec, -} - -impl Spring { - fn arragement_amount(&self) -> usize { - let mut combinations = vec![vec![]]; - for status in &self.status { - let mut new_combinations = Vec::new(); - for combination in &combinations { - match status { - SpringStatus::Operational => { - let mut new_combination = combination.clone(); - new_combination.push(*status); - new_combinations.push(new_combination); - } - SpringStatus::Unknown => { - let mut new_combination = combination.clone(); - new_combination.push(SpringStatus::Operational); - new_combinations.push(new_combination); - let mut new_combination = combination.clone(); - new_combination.push(SpringStatus::Damaged); - new_combinations.push(new_combination); - } - SpringStatus::Damaged => { - let mut new_combination = combination.clone(); - new_combination.push(*status); - new_combinations.push(new_combination); - } - } - } - combinations = new_combinations; - } - - let combinations = combinations - .iter() - .map(|combination| { - let mut combination_status: Vec = Vec::new(); - let mut count = 0; - combination.iter().for_each(|status| { - match status { - SpringStatus::Operational => { - if count > 0 { - combination_status.push(count); - } - count = 0; - } - SpringStatus::Damaged => count += 1, - SpringStatus::Unknown => unimplemented!("Should not happen"), - }; - }); - if count > 0 { - combination_status.push(count); - } - combination_status - }) - .filter(|status| status == &self.condition); - - combinations.count() +impl Puzzle { + fn generate_permutations(&self) -> impl Iterator { + repeat_n([".", "#"].into_iter(), self.spaces_to_fill) + .multi_cartesian_product() + .map(|x| x.join("")) } -} -impl FromStr for Spring { - type Err = color_eyre::Report; - fn from_str(s: &str) -> std::prelude::v1::Result { - let line = s.split_whitespace().collect::>(); - let status = line - .first() - .unwrap() + fn check_option(&self, option: &str) -> bool { + let mut option_iter = option.chars(); + let filled_option = self + .line .chars() .map(|ch| match ch { - '?' => SpringStatus::Unknown, - '.' => SpringStatus::Operational, - '#' => SpringStatus::Damaged, - _ => unreachable!(), + '?' => option_iter + .next() + .expect("Should have a len similar to needed gaps"), + value => value, }) - .collect::>(); - let condition = line - .last() - .unwrap() - .split(',') - .map(|s| s.parse::().unwrap()) - .collect::>(); - - let mut new_status = status.clone(); - let mut new_condition = condition.clone(); - - for _ in 0..4 { - new_status.push(SpringStatus::Unknown); - new_status.extend(status.clone().iter()); - new_condition.extend(condition.clone().iter()); - } - - dbg!(&new_status, &new_condition); - - Ok(Self { - status: new_status, - condition: new_condition, - }) + .collect::(); + let counts = filled_option + .chars() + .group_by(|ch| ch == &'#') + .into_iter() + .filter_map(|(is_hashes, group)| is_hashes.then_some(group.into_iter().count())) + .collect_vec(); + &self.batches[..] == &counts[..] } + + fn possible_solution_count(&self) -> usize { + let count = self + .generate_permutations() + .filter(|option| self.check_option(option)) + .count(); + count + } +} + +fn parse_line(input: &str) -> IResult<&str, Puzzle> { + let (input, (line, batches)) = separated_pair( + is_a("?.#"), + space1, + separated_list1(tag(","), complete::u32), + )(input)?; + let expanded_line = std::iter::repeat(line).take(5).join("?"); + let spaces_to_fill = expanded_line.chars().filter(|ch| ch != &'?').count(); + Ok(( + input, + Puzzle { + spaces_to_fill, + line: expanded_line, + batches: std::iter::repeat(batches) + .take(5) + .flatten() + .map(|x| x as usize) + .collect(), + }, + )) } pub fn process(input: &str) -> Result { - let springs = input.lines().map(|line| { - Spring::from_str(line) - .unwrap_or_default() - .arragement_amount() - }); - Ok(springs.sum()) + let puzzles = input + .lines() + .map(parse_line) + .collect::, nom::Err>>>() + .expect("Parsisng to succeed"); + let sum = puzzles + .iter() + .map(|(_, puzzle)| puzzle.possible_solution_count()); + Ok(sum.sum()) } #[cfg(test)] @@ -137,110 +101,4 @@ mod tests { assert_eq!(525152, process(input)?); Ok(()) } - - #[test] - fn test_from_str() -> Result<()> { - let input = "???.### 1,1,3"; - let spring = Spring::from_str(input)?; - assert_eq!( - vec![ - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Operational, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Operational, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Operational, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Operational, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Unknown, - SpringStatus::Operational, - SpringStatus::Damaged, - SpringStatus::Damaged, - SpringStatus::Damaged, - ], - spring.status - ); - assert_eq!( - vec![1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3], - spring.condition - ); - Ok(()) - } - - #[test] - fn test_line_1() -> Result<()> { - assert_eq!(1, Spring::from_str("???.### 1,1,3")?.arragement_amount()); - Ok(()) - } - - #[test] - fn test_line_2() -> Result<()> { - assert_eq!( - 16384, - Spring::from_str(".??..??...?##. 1,1,3")?.arragement_amount() - ); - Ok(()) - } - - #[test] - fn test_line_3() -> Result<()> { - assert_eq!( - 1, - Spring::from_str("?#?#?#?#?#?#?#? 1,3,1,6")?.arragement_amount() - ); - Ok(()) - } - - #[test] - fn test_line_4() -> Result<()> { - assert_eq!( - 16, - Spring::from_str("????.#...#... 4,1,1")?.arragement_amount() - ); - Ok(()) - } - - #[test] - fn test_line_5() -> Result<()> { - assert_eq!( - 2500, - Spring::from_str("????.######..#####. 1,6,5")?.arragement_amount() - ); - Ok(()) - } - - #[test] - fn test_line_6() -> Result<()> { - assert_eq!( - 506250, - Spring::from_str("?###???????? 3,2,1")?.arragement_amount() - ); - Ok(()) - } }