use std::{collections::HashMap, str::FromStr}; use regex::Regex; pub fn run() { let input = include_str!("../input/day4.txt"); // let input = r#"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"#; let cards = input .lines() .filter(|s| !s.is_empty()) .map(|s| Card::parse(s.trim())) .collect::>(); let total_points = cards.iter().map(|c| c.points()).sum::(); dbg!(total_points); let mut counts = cards.iter().map(|_| 1u32).collect::>(); let mut to_process = cards.iter().map(|_| 1u32).collect::>(); let total_cards = run_part2(&cards, &mut counts, &mut to_process); dbg!(total_cards); } fn run_part2(cards: &[Card], counts: &mut [u32], to_process: &mut [u32]) -> u32 { let orig_total = counts.iter().sum::(); for c in cards { let card_index = c.id as usize - 1; let card_count = to_process[card_index]; to_process[card_index] = 0; let winning_numbers = c.winning_numbers(); for i in 1..(winning_numbers + 1) { let duped_index = card_index + i; if duped_index >= cards.len() { break; } // println!("adding {} to card {}", card_count, duped_index + 1); counts[duped_index] += card_count; to_process[duped_index] += card_count; } } // dbg!(counts); // return 0; if counts.iter().sum::() == orig_total { return orig_total; } else { return run_part2(cards, counts, to_process); } } #[derive(Debug, Clone, PartialEq)] struct Card { id: u32, win: Vec, have: Vec, } impl Card { fn parse(value: &str) -> Self { let (card, rest) = value.split_once(":").unwrap(); let id: u32 = card.split(" ").last().unwrap().parse().unwrap(); let (win, have) = rest.split_once("|").unwrap(); let mut win_vec = vec![]; let mut have_vec = vec![]; for s in win.split(" ") { if s.is_empty() { continue; } win_vec.push(s.parse().unwrap()); } for s in have.split(" ") { if s.is_empty() { continue; } have_vec.push(s.parse().unwrap()); } Self { id, win: win_vec, have: have_vec, } } fn winning_numbers(&self) -> usize { self.win.iter().filter(|w| self.have.contains(w)).count() } fn points(&self) -> u32 { let count = self.winning_numbers(); if count == 0 { 0 } else { 2u32.pow(count as u32 - 1) as u32 } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_card_from_str() { assert_eq!( Card::parse("Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53"), Card { id: 1, win: vec![41, 48, 83, 86, 17], have: vec![83, 86, 6, 31, 17, 9, 48, 53], } ) } #[test] fn test_points() { assert_eq!( Card::parse("Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53").points(), 8 ) } }