diff options
author | Toby Vincent <tobyv@tobyvin.dev> | 2023-12-12 18:39:18 -0600 |
---|---|---|
committer | Toby Vincent <tobyv@tobyvin.dev> | 2023-12-12 18:39:18 -0600 |
commit | 83ecd48629924bec2852e07c87825ce70c3db5bf (patch) | |
tree | c74b2ea9d6f1042bbc611938b0e9ae9bb93ceea7 /src/day_12.rs | |
parent | c791edce9a365beeeb3288b3060c37ae48a1a4e2 (diff) |
feat(wip): impl day 12, part 1 (brute forced)
Diffstat (limited to 'src/day_12.rs')
-rw-r--r-- | src/day_12.rs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/day_12.rs b/src/day_12.rs new file mode 100644 index 0000000..6b755c9 --- /dev/null +++ b/src/day_12.rs @@ -0,0 +1,143 @@ +use crate::{Problem, Solution}; + +pub struct Day12; + +impl Problem for Day12 { + const DAY: u8 = 12; + + const INPUT: &'static str = include_str!("../input/day_12.txt"); +} + +impl Solution for Day12 { + type Answer1 = usize; + + type Answer2 = usize; + + fn part_1(input: &str) -> anyhow::Result<Self::Answer1> { + let rows = input + .lines() + .map(std::str::FromStr::from_str) + .try_collect::<Vec<Row>>()?; + + Ok(rows + .into_iter() + .map(|row| { + row.permutations() + .into_iter() + .filter(|p| row.check_group(p)) + .count() + }) + .sum()) + } + + fn part_2(input: &str) -> anyhow::Result<Self::Answer2> { + todo!() + } +} + +#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct Row { + states: Vec<State>, + groups: Vec<usize>, +} + +impl Row { + fn unknowns(&self) -> usize { + self.states.iter().filter(|&&s| s == State::Unknown).count() + } + + fn permutations(&self) -> Vec<Vec<State>> { + (0..self.unknowns()) + .fold(vec![vec![]], |acc, _| { + acc.into_iter() + .flat_map(|mut p1| { + let mut p2 = p1.to_vec(); + p2.push(State::Bad); + p1.push(State::Good); + [p1, p2] + }) + .collect() + }) + .into_iter() + .map(|s| { + let mut iter = s.into_iter(); + let mut row = self.states.to_vec(); + for s in row.iter_mut() { + if let State::Unknown = s { + *s = iter.next().unwrap() + }; + } + row + }) + .collect() + } + + fn check_group(&self, states: &[State]) -> bool { + let mut counts = self.groups.iter(); + + states.group_by(|a, b| a == b).all(|group| { + group.iter().all(|s| *s == State::Good) + || counts.next().is_some_and(|n| *n == group.len()) + }) && counts.next().is_none() + } +} + +impl std::str::FromStr for Row { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let (states, groups) = s.split_once(' ').unwrap(); + + let states = states + .chars() + .map(TryFrom::try_from) + .try_collect::<Vec<State>>()?; + + let groups = groups + .split(',') + .map(std::str::FromStr::from_str) + .try_collect::<Vec<usize>>()?; + + Ok(Self { states, groups }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum State { + Good, + Bad, + Unknown, +} + +impl TryFrom<char> for State { + type Error = anyhow::Error; + + fn try_from(value: char) -> Result<Self, Self::Error> { + use State::*; + match value { + '.' => Ok(Good), + '#' => Ok(Bad), + '?' => Ok(Unknown), + c => Err(anyhow::format_err!("Unknown spring condition: {c}")), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const INPUT: &str = indoc::indoc! {" + ???.### 1,1,3 + .??..??...?##. 1,1,3 + ?#?#?#?#?#?#?#? 1,3,1,6 + ????.#...#... 4,1,1 + ????.######..#####. 1,6,5 + ?###???????? 3,2,1 + "}; + + #[test] + fn test_part_1() -> anyhow::Result<()> { + Ok(assert_eq!(21, Day12::part_1(INPUT)?)) + } +} |