diff options
author | Toby Vincent <tobyv@tobyvin.dev> | 2023-12-04 19:06:10 -0600 |
---|---|---|
committer | Toby Vincent <tobyv@tobyvin.dev> | 2023-12-04 19:06:10 -0600 |
commit | 608aaf9a5cf769ced7e02a4ce2cc27beba6dcbba (patch) | |
tree | e84018ecea67a473c4785b41dbf79de821984384 /src | |
parent | 78dcf2ef7b9678ecd5bff597bd627dd8697dbee1 (diff) |
feat: impl day 4
Diffstat (limited to 'src')
-rw-r--r-- | src/day_04.rs | 110 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/main.rs | 3 |
3 files changed, 114 insertions, 2 deletions
diff --git a/src/day_04.rs b/src/day_04.rs new file mode 100644 index 0000000..77559e2 --- /dev/null +++ b/src/day_04.rs @@ -0,0 +1,110 @@ +use crate::{Problem, Solution}; + +pub struct Day04; + +impl Problem for Day04 { + const DAY: u8 = 4; + + const INPUT: &'static str = include_str!("../input/day_04.txt"); +} + +impl Solution for Day04 { + type Answer1 = usize; + + type Answer2 = usize; + + fn part_1(input: &str) -> anyhow::Result<Self::Answer1> { + let scores = input + .trim() + .split('\n') + .map(parse_score) + .collect::<Result<Vec<_>, _>>()?; + + Ok(scores + .into_iter() + .filter(|n| n > &0) + .map(|n| 2usize.pow(n as u32 - 1)) + .sum()) + } + + fn part_2(input: &str) -> anyhow::Result<Self::Answer2> { + let scores = input + .trim() + .split('\n') + .map(parse_score) + .collect::<Result<Vec<_>, _>>()?; + + let cards = &mut vec![0usize; scores.len()]; + + for card in 0..scores.len() { + add_copy(cards, &scores, card) + } + + Ok(cards.iter().sum()) + } +} + +fn add_copy(cards: &mut Vec<usize>, scores: &[usize], card: usize) { + cards[card] += 1; + + for card in card + 1..cards.len().min(card + scores[card] + 1) { + add_copy(cards, scores, card); + } +} + +fn parse_score(s: &str) -> anyhow::Result<usize> { + let (winning, numbers) = s + .trim() + .split_once(':') + .ok_or(anyhow::format_err!("Invalid card format: {s}"))? + .1 + .trim() + .split_once('|') + .ok_or(anyhow::format_err!("Invalid card format: {s}"))?; + + let winning_set = winning + .split_whitespace() + .map(std::str::FromStr::from_str) + .collect::<Result<Vec<usize>, _>>()?; + + Ok(numbers + .split_whitespace() + .map(std::str::FromStr::from_str) + .collect::<Result<Vec<usize>, _>>()? + .into_iter() + .filter(|n| winning_set.contains(n)) + .count()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_1() -> anyhow::Result<()> { + const INPUT: &str = indoc::indoc! {" + Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 + Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 + Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 + Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 + 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 11 + "}; + + Ok(assert_eq!(13, Day04::part_1(INPUT)?)) + } + + #[test] + fn test_part_2() -> anyhow::Result<()> { + const INPUT: &str = indoc::indoc! {" + Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 + Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 + Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 + Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 + 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 11 + "}; + + Ok(assert_eq!(30, Day04::part_2(INPUT)?)) + } +} @@ -1,8 +1,9 @@ #![feature(iterator_try_collect)] - + pub mod day_01; pub mod day_02; pub mod day_03; +pub mod day_04; pub trait Problem { const DAY: u8; diff --git a/src/main.rs b/src/main.rs index 7ac9cfa..3f47fac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,10 @@ -use aoc_2023::{day_01::Day01, day_02::Day02, day_03::Day03, Solution}; +use aoc_2023::{day_01::Day01, day_02::Day02, day_03::Day03, day_04::Day04, Solution}; fn main() -> anyhow::Result<()> { Day01::solve()?; Day02::solve()?; Day03::solve()?; + Day04::solve()?; Ok(()) } |