2023 - Day 04
This commit is contained in:
135
2023/src/bin/day04.rs
Normal file
135
2023/src/bin/day04.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
#![feature(test)]
|
||||
use anyhow::Result;
|
||||
use aoc::Solver;
|
||||
|
||||
// -- Runners --
|
||||
fn main() -> Result<()> {
|
||||
Day::solve()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_test1() -> Result<()> {
|
||||
Day::test(Day::part1, "test-1", 13)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_solution() -> Result<()> {
|
||||
Day::test(Day::part1, "input", 24706)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_test1() -> Result<()> {
|
||||
Day::test(Day::part2, "test-1", 30)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_solution() -> Result<()> {
|
||||
Day::test(Day::part2, "input", 13114317)
|
||||
}
|
||||
|
||||
// Benchmarks
|
||||
extern crate test;
|
||||
#[bench]
|
||||
#[ignore]
|
||||
fn part1_bench(b: &mut test::Bencher) {
|
||||
Day::benchmark(Day::part1, b)
|
||||
}
|
||||
#[bench]
|
||||
#[ignore]
|
||||
fn part2_bench(b: &mut test::Bencher) {
|
||||
Day::benchmark(Day::part2, b)
|
||||
}
|
||||
}
|
||||
|
||||
// -- Solution --
|
||||
pub struct Day;
|
||||
impl aoc::Solver for Day {
|
||||
type Output1 = usize;
|
||||
type Output2 = usize;
|
||||
|
||||
fn day() -> u8 {
|
||||
4
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> Self::Output1 {
|
||||
// Calculate the score for every game and sum it
|
||||
input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
// Get rid of the first part
|
||||
let (_, line) = line
|
||||
.split_once(": ")
|
||||
.expect("Input should be formatted properly");
|
||||
|
||||
// Seperate the winning numbers and numbers we have
|
||||
let (winning, numbers) = line
|
||||
.split_once(" | ")
|
||||
.expect("Input should be formatted properly");
|
||||
|
||||
// Parse the winning numbers
|
||||
let winning: Vec<_> = winning.split(' ').flat_map(str::parse::<usize>).collect();
|
||||
// Parse the numbers we have, check if they are a winning number and count the
|
||||
// amount of winning numbers we have
|
||||
let count = numbers
|
||||
.split(' ')
|
||||
.flat_map(str::parse::<usize>)
|
||||
.filter(|num| winning.contains(num))
|
||||
.count();
|
||||
|
||||
// Calculate the score
|
||||
if count > 0 {
|
||||
return 2_usize.pow(count as u32 - 1);
|
||||
}
|
||||
|
||||
0
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> Self::Output2 {
|
||||
// Calculate how many wins we have per game
|
||||
let wins: Vec<_> = input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
// Get rid of the first part
|
||||
let (_, line) = line
|
||||
.split_once(": ")
|
||||
.expect("Input should be formatted properly");
|
||||
|
||||
// Seperate the winning numbers and numbers we have
|
||||
let (winning, numbers) = line
|
||||
.split_once(" | ")
|
||||
.expect("Input should be formatted properly");
|
||||
|
||||
// Parse the winning numbers
|
||||
let winning: Vec<_> = winning.split(' ').flat_map(str::parse::<usize>).collect();
|
||||
// Parse the numbers we have, check if they are a winning number and count the
|
||||
// amount of winning numbers we have
|
||||
numbers
|
||||
.split(' ')
|
||||
.flat_map(str::parse::<usize>)
|
||||
.filter(|num| winning.contains(num))
|
||||
.count()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Start out with one copy of every card
|
||||
let mut copies = vec![1; wins.len()];
|
||||
|
||||
// Keep track of how many copies we get of every card
|
||||
for (i, win) in wins.iter().enumerate() {
|
||||
for j in (i + 1)..(i + win + 1) {
|
||||
// Add the current amount of copies to the card we win
|
||||
// e.g. we have 2 copies of the current card that has 3 wins, this means we add 2
|
||||
// to the next 3 cards
|
||||
copies[j] += copies[i]
|
||||
}
|
||||
}
|
||||
|
||||
copies.iter().sum()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user