use nom::{ bytes::complete::tag, character::complete::{line_ending, space1, u32 as nom_u32}, combinator::map, multi::separated_list1, sequence::tuple, IResult, }; use std::{collections::BTreeSet, fs}; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_4.txt")?; let parsed = Scratchcards::parser(&input).unwrap().1; dbg!(&parsed.points()); dbg!(&parsed.scratchcard_explosion_sum()); Ok(()) } #[derive(Debug)] struct Scratchcards(Vec); #[derive(Debug)] struct Scratchcard { winning: BTreeSet, owned: BTreeSet, } impl Scratchcards { fn parser(input: &str) -> IResult<&str, Self> { map( separated_list1(line_ending, Scratchcard::parser), Scratchcards, )(input) } fn points(&self) -> usize { self.0.iter().map(|card| card.points()).sum() } fn scratchcard_explosion_sum(&self) -> u64 { let mut scratchcard_pile = vec![1_u64.into(); self.0.len()]; for i in 0..scratchcard_pile.len() { let points = self.0[i].winning_numbers(); let new_scratchcards: u64 = scratchcard_pile[i]; for offset in 0..points { if let Some(pile) = scratchcard_pile.get_mut(i + 1 + offset) { *pile += new_scratchcards; } } } scratchcard_pile.into_iter().sum() } } impl Scratchcard { fn parser(input: &str) -> IResult<&str, Self> { map( tuple(( tag("Card"), space1, nom_u32, tag(":"), space1, separated_list1(space1, nom_u32), space1, tag("|"), space1, separated_list1(space1, nom_u32), )), |(_, _, _, _, _, winning, _, _, _, owned)| Scratchcard { winning: winning.into_iter().collect(), owned: owned.into_iter().collect(), }, )(input) } fn winning_numbers(&self) -> usize { self.winning.intersection(&self.owned).count() } fn points(&self) -> usize { let winning_numbers = self.winning_numbers(); if winning_numbers > 0 { 2_usize.pow(winning_numbers as u32 - 1) } else { 0 } } }