From a1f44e58866d5b09570703da67c9111dec6fe1b1 Mon Sep 17 00:00:00 2001 From: Keenan Tims Date: Tue, 5 Dec 2023 19:47:45 -0800 Subject: [PATCH] day4: problem 2 solution --- 4/src/main.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 3 deletions(-) diff --git a/4/src/main.rs b/4/src/main.rs index 95a0f03..5af7175 100644 --- a/4/src/main.rs +++ b/4/src/main.rs @@ -77,6 +77,13 @@ impl Card { 0 } } + // Return the number of copies won + fn win_copies(&self) -> usize { + self.winning_numbers + .iter() + .filter(|win| self.our_numbers.contains(win)) + .count() + } } impl From<&str> for Card { @@ -127,11 +134,87 @@ fn problem1(input: InputIter) -> u64 { .map(|line| Card::from(line.unwrap().as_str())) .collect(); - cards.iter().map(|x| x.score()).sum() } // PROBLEM 2 solution -fn problem2(input: InputIter) -> u64 { - 0 + +// --- Part Two --- + +// Just as you're about to report your findings to the Elf, one of you realizes that the +// rules have actually been printed on the back of every card this whole time. + +// There's no such thing as "points". Instead, scratchcards only cause you to win more +// scratchcards equal to the number of winning numbers you have. + +// Specifically, you win copies of the scratchcards below the winning card equal to the +// number of matches. So, if card 10 were to have 5 matching numbers, you would win one +// copy each of cards 11, 12, 13, 14, and 15. + +// Copies of scratchcards are scored like normal scratchcards and have the same card +// number as the card they copied. So, if you win a copy of card 10 and it has 5 +// matching numbers, it would then win a copy of the same cards that the original card +// 10 won: cards 11, 12, 13, 14, and 15. This process repeats until none of the copies +// cause you to win any more cards. (Cards will never make you copy a card past the end +// of the table.) + +// This time, the above example goes differently: + +// 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 + +// Card 1 has four matching numbers, so you win one copy each of the next four +// cards: cards 2, 3, 4, and 5. Your original card 2 has two matching numbers, so +// you win one copy each of cards 3 and 4. Your copy of card 2 also wins one copy +// each of cards 3 and 4. Your four instances of card 3 (one original and three +// copies) have two matching numbers, so you win four copies each of cards 4 and 5. +// Your eight instances of card 4 (one original and seven copies) have one matching +// number, so you win eight copies of card 5. Your fourteen instances of card 5 (one +// original and thirteen copies) have no matching numbers and win no more cards. +// Your one instance of card 6 (one original) has no matching numbers and wins no +// more cards. + +// Once all of the originals and copies have been processed, you end up with 1 instance +// of card 1, 2 instances of card 2, 4 instances of card 3, 8 instances of card 4, 14 +// instances of card 5, and 1 instance of card 6. In total, this example pile of +// scratchcards causes you to ultimately have 30 scratchcards! + +// Process all of the original and copied scratchcards until no more scratchcards are +// won. Including the original set of scratchcards, how many total scratchcards do you +// end up with? + +fn problem2_award_copies<'a>(orig_cards: &'a Vec, card: &Card) -> Vec<&'a Card> { + let win_copies = card.win_copies(); + let mut new_cards = Vec::new(); + if win_copies != 0 { + for ofs in 0..win_copies { + // card.id is 1-indexed, so would need to be card.id-1, but offset needs to + // start at 1, which offsets this + new_cards.push(&orig_cards[card.id + ofs]); + } + } + + new_cards +} + +fn problem2(input: InputIter) -> u64 { + let orig_cards: Vec = input + .map(|line| Card::from(line.unwrap().as_str())) + .collect(); + + let mut new_cards = Vec::new(); + let mut won_cards = Vec::new(); + + for card in &orig_cards { + new_cards.append(&mut problem2_award_copies(&orig_cards, card)) + } + + while let Some(card) = new_cards.pop() { + won_cards.push(card); + new_cards.append(&mut problem2_award_copies(&orig_cards, card)) + } + + (won_cards.len() + orig_cards.len()) as u64 }