1
0
Fork 0
advent-of-code/2023/src/bin/04.rs

109 lines
2.7 KiB
Rust

advent_of_code::solution!(4);
use std::collections::HashSet;
struct Card {
id: usize,
winning: HashSet<u32>,
present: HashSet<u32>,
}
impl Card {
fn matching_numbers(&self) -> Vec<&u32> {
self.winning
.intersection(&self.present)
.collect::<Vec<&u32>>()
}
}
fn parse(input: &str) -> Vec<Card> {
input
.lines()
.filter_map(|line| {
if !line.is_empty() {
let cparts: Vec<&str> = line.split(": ").collect();
let id = cparts[0]
.split(" ")
.collect::<Vec<&str>>()
.last()?
.trim_start()
.parse::<usize>()
.unwrap();
let cnums: Vec<&str> = cparts[1].split(" | ").collect();
let winning: HashSet<u32> = cnums[0]
.replace(" ", " ")
.trim_start()
.split(" ")
.map(|n| n.parse::<u32>().unwrap())
.collect();
let present: HashSet<u32> = cnums[1]
.replace(" ", " ")
.trim_start()
.split(" ")
.map(|n| n.parse::<u32>().unwrap())
.collect();
Some(Card {
id,
winning,
present,
})
} else {
None
}
})
.collect()
}
pub fn part_one(input: &str) -> Option<u32> {
let mut sum = 0;
let base: i32 = 2;
for c in parse(input).iter() {
let m = c.matching_numbers();
if m.is_empty() {
continue;
}
let p = base.pow(m.len() as u32 - 1);
if m.len() > 0 {
sum += p;
}
}
Some(sum.try_into().unwrap())
}
pub fn part_two(input_str: &str) -> Option<u32> {
let mut cards: [u32; 202] = [1; 202];
let input = parse(input_str);
for i in input.len()..cards.len() {
cards[i] = 0;
}
for c in input.iter() {
let m = c.matching_numbers();
let cur = c.id - 1;
for i in 1..=m.len() {
let dest = cur + i;
if dest >= input.len() {
continue;
}
cards[dest] += cards[cur];
}
}
Some(cards.iter().sum())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(13));
}
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(30));
}
}