AoC23/src/day04.rs

127 lines
3.4 KiB
Rust

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::<Vec<_>>();
let total_points = cards.iter().map(|c| c.points()).sum::<u32>();
dbg!(total_points);
let mut counts = cards.iter().map(|_| 1u32).collect::<Vec<_>>();
let mut to_process = cards.iter().map(|_| 1u32).collect::<Vec<_>>();
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::<u32>();
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::<u32>() == orig_total {
return orig_total;
} else {
return run_part2(cards, counts, to_process);
}
}
#[derive(Debug, Clone, PartialEq)]
struct Card {
id: u32,
win: Vec<u32>,
have: Vec<u32>,
}
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
)
}
}