diff --git a/src/day4.rs b/src/day4.rs index eebbaf6..64c767b 100644 --- a/src/day4.rs +++ b/src/day4.rs @@ -1,12 +1,12 @@ use chumsky::{ error::Simple, - primitive::{choice, just}, + primitive::just, text::{self, TextParser}, Parser, }; use eyre::{eyre, Context}; use std::{ - collections::HashSet, + collections::{HashMap, HashSet}, io::{BufRead, BufReader, Read}, str::FromStr, }; @@ -24,6 +24,33 @@ pub fn part1(input: impl Read) -> eyre::Result { Ok(sum) } +pub fn part2(input: impl Read) -> eyre::Result { + let buf_reader = BufReader::new(input); + let mut counts: HashMap<_, usize> = HashMap::new(); + for (num, line) in buf_reader.lines().enumerate() { + let line = line.wrap_err_with(|| format!("could not read line {num}"))?; + let card: Card = line + .parse() + .wrap_err_with(|| format!("could not parse card at line {num}"))?; + // the count of copies won by past cards + let count = counts.entry(card.id).or_default(); + *count += 1; // count the original card + let count = *count; // drop the borrow + let matches = card.matches(); + for id in card.id + 1..=card.id + matches { + *counts.entry(id).or_default() += count; + } + // println!( + // "card: {} has {}, matched {} -- set is {:?}", + // card.id, + // count, + // card.matches(), + // counts + // ); + } + Ok(counts.into_values().sum()) +} + #[derive(Default, Debug)] struct Card { id: usize, @@ -33,13 +60,16 @@ struct Card { impl Card { fn points(&self) -> usize { - let matches = self.winning.intersection(&self.scratched).count(); + let matches = self.matches(); if matches == 0 { 0 } else { 2_usize.pow((matches - 1) as u32) } } + fn matches(&self) -> usize { + self.winning.intersection(&self.scratched).count() + } } impl FromStr for Card { diff --git a/tests/day4.rs b/tests/day4.rs index a72d245..1083178 100644 --- a/tests/day4.rs +++ b/tests/day4.rs @@ -11,6 +11,7 @@ const SAMPLE: &str = indoc! { r#" Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 1 "# }; +const INPUT_PATH: &str = "day4/input.txt"; #[test] fn part1_sample() { @@ -20,7 +21,20 @@ fn part1_sample() { #[test] fn part1_input() { - let input = common::read("day4/input.txt").unwrap(); + let input = common::read(INPUT_PATH).unwrap(); let result = day4::part1(input).unwrap(); assert_eq!(result, 25004); } + +#[test] +fn part2_sample() { + let result = day4::part2(SAMPLE.as_bytes()).unwrap(); + assert_eq!(result, 30); +} + +#[test] +fn part2_input() { + let input = common::read(INPUT_PATH).unwrap(); + let result = day4::part2(input).unwrap(); + assert_eq!(result, 14427616); +}