use aoc2023_niels_overkamp::common::{self, AOCResult}; use nom::character::complete::multispace1; use nom::sequence::{preceded, terminated, tuple}; use nom::bytes::complete::tag; use nom::character::complete::u32 as u32_parser; use nom::error::convert_error; use nom::multi::separated_list0; use nom::combinator::all_consuming; use nom::Finish; use std::collections::HashSet; const DAY: &str = "day4"; fn main() -> Result<(), Box> { common::run(DAY, &run) } pub fn run(input: &Vec) -> AOCResult { let id_parser = preceded(tuple((tag("Card"), multispace1)), terminated(u32_parser, tuple((tag(":"), multispace1)))); let numbers_parser_gen = || separated_list0(multispace1, u32_parser); let mut card_parser = all_consuming(tuple(( id_parser, terminated( numbers_parser_gen(), tuple((tag(" |"), multispace1))), numbers_parser_gen()))); let mut copy_counter = vec![]; let mut sum = 0; for line in input.iter() { let (_, (id, win_numbers, my_numbers)) = card_parser(line.as_str()) .finish() .map_err(|e| convert_error(line.as_str(), e))?; let win_numbers = HashSet::<_>::from_iter(win_numbers.into_iter()); let my_numbers = HashSet::<_>::from_iter(my_numbers.into_iter()); let id = id as usize; let win_count = win_numbers.intersection(&my_numbers).count(); copy_counter.resize(copy_counter.len().max(id+win_count), 1); let copy_count = copy_counter[id - 1]; if win_count > 0 { sum += 1 << (win_count - 1); for id in id..id+win_count { copy_counter[id] += copy_count; } } } Ok([Some(sum.to_string()), Some(copy_counter.into_iter().sum::().to_string())]) } #[test] pub fn test_day4() { assert!(common::run_test(DAY, &run)) }