use nom::{ branch::alt, character::complete::{char, line_ending, space1, u32}, combinator::{map, value}, multi::{many1, separated_list1}, sequence::separated_pair, IResult, }; use std::fs; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_12.txt")?; let parsed = SpringField::parser(&input).unwrap().1; dbg!(&parsed.possibilities_sum()); Ok(()) } #[derive(Debug)] struct SpringField(Vec); #[derive(Debug)] struct SpringRow { springs: Vec>, check: Vec, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Spring { Good, Bad, } impl SpringField { fn parser(input: &str) -> IResult<&str, Self> { map(separated_list1(line_ending, SpringRow::parser), SpringField)(input) } fn possibilities_sum(&self) -> usize { self.0.iter().map(|r| r.possibilities_count()).sum() } } impl SpringRow { fn parser(input: &str) -> IResult<&str, Self> { map( separated_pair( many1(Spring::parser), space1, separated_list1(char(','), u32), ), |(springs, check)| SpringRow { springs, check }, )(input) } fn fill_in_springs(&self, bits: usize) -> Vec { let mut current_bit_index = 0; self.springs .iter() .map(|maybe_spring| { maybe_spring.unwrap_or_else(|| { let current_bit = bits & (1 << current_bit_index) != 0; current_bit_index += 1; if current_bit { Spring::Bad } else { Spring::Good } }) }) .collect() } fn generate_check(springs: Vec) -> Vec { let mut check = Vec::new(); let mut current_count = 0; let mut in_bad_lands = false; for spring in springs { match spring { Spring::Good => { if in_bad_lands { check.push(current_count); current_count = 0; } in_bad_lands = false; } Spring::Bad => { current_count += 1; in_bad_lands = true; } } } if in_bad_lands { check.push(current_count); } check } fn possibilities_count(&self) -> usize { let unknown_count = self.springs.iter().filter(|s| s.is_none()).count(); assert_ne!(unknown_count, 0); let max_possibilities = 2_usize.pow(unknown_count.try_into().unwrap()); let mut possibilities = 0; for i in 0..max_possibilities { let springs_guess = self.fill_in_springs(i); let generated_check = SpringRow::generate_check(springs_guess); if self.check == generated_check { possibilities += 1; } } possibilities } } impl Spring { fn parser(input: &str) -> IResult<&str, Option> { alt(( value(Some(Spring::Good), char('.')), value(Some(Spring::Bad), char('#')), value(None, char('?')), ))(input) } }