diff --git a/src/bin/day4.rs b/src/bin/day4.rs index 23f52eb..d034cc7 100644 --- a/src/bin/day4.rs +++ b/src/bin/day4.rs @@ -2,16 +2,15 @@ use aoc23::read; use chumsky::{prelude::*, text::int}; -use std::collections::HashSet; +use std::collections::{BTreeMap, HashSet}; struct Card { - id: usize, winning_nums: HashSet, nums: HashSet } impl Card { - fn parser() -> impl Parser> { + fn parser() -> impl Parser> { let nums = just(" ") .repeated() .ignore_then(int(10)) @@ -29,36 +28,62 @@ impl Card { .then(nums) .then_ignore(just(" | ")) .then(nums) - .map(|((id, winning_nums), nums): ((String, _), _)| Self { - id: id.parse().unwrap(), - winning_nums, - nums + .map(|((id, winning_nums), nums): ((String, _), _)| { + (id.parse().unwrap(), Self { winning_nums, nums }) }) } } -fn parser() -> impl Parser, Error = Simple> { +fn parser() -> impl Parser, Error = Simple> { Card::parser() .then_ignore(just("\n")) .repeated() + .map(|cards| cards.into_iter().collect()) .then_ignore(end()) } fn main() -> anyhow::Result<()> { let cards = read("inputs/day4.txt", parser())?; - let mut points = 0; - for card in &cards { - let matches = card - .nums - .iter() - .filter(|num| card.winning_nums.contains(num)) - .count(); - if matches > 0 { - points += 1 << (matches - 1); + let matches = cards + .iter() + .map(|(id, card)| { + ( + *id, + card.nums + .iter() + .filter(|num| card.winning_nums.contains(num)) + .count() + ) + }) + .collect::>(); + + // part 1 + println!( + "{}", + matches + .values() + .map(|count| match count { + 0 => 0, + _ => 1 << (count - 1) + }) + .sum::() + ); + + // part 2 + let mut copies = cards + .keys() + .map(|key| (*key, 1)) + .collect::>(); + for id in cards.keys() { + let num_copies = copies[id]; + for next in id + 1 ..= id + matches[id] { + if let Some(next_copies) = copies.get_mut(&next) { + *next_copies += num_copies; + } } } - println!("{points}"); + println!("{}", copies.values().sum::()); Ok(()) }