#![forbid(elided_lifetimes_in_paths, unsafe_code)] use aoc23::read; use chumsky::{prelude::*, text::int}; use std::collections::{BTreeMap, HashSet}; struct Card { winning_nums: HashSet, nums: HashSet } impl Card { fn parser() -> impl Parser> { let nums = just(" ") .repeated() .ignore_then(int(10)) .separated_by(just(" ")) .map(|nums| { nums.into_iter() .map(|num: String| num.parse().unwrap()) .collect::>() }); just("Card") .ignore_then(just(" ").repeated()) .ignore_then(int(10)) .then_ignore(just(": ")) .then(nums) .then_ignore(just(" | ")) .then(nums) .map(|((id, winning_nums), nums): ((String, _), _)| { (id.parse().unwrap(), Self { winning_nums, nums }) }) } } 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 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!("{}", copies.values().sum::()); Ok(()) }