advent_of_code_2024/src/day13.rs

96 lines
2.2 KiB
Rust

use itertools::Itertools;
use pest::{
iterators::{Pair, Pairs},
Parser,
};
const OFFSETS: (u64, u64) = (10000000000000, 10000000000000);
pub fn day13() {
let cost: f64 = parse_machines(&crate::input(13))
.iter()
.filter_map(|machine| {
let (c, d) = machine.prize;
let (a, b) = &machine.buttons;
let bn = (d - c * a.y / a.x) / (b.y - b.x * a.y / a.x);
let an = (c - bn * b.x) / a.x;
// Both solutions must be whole numbers
let winnable = [an, bn]
.iter()
.all(|&n| n >= -0.01 && (n.round() - n).abs() <= 0.01);
if winnable {
Some(an.round() * a.cost + bn.round() * b.cost)
} else {
None
}
})
.sum();
println!("Minimum Cost: {:?}", cost);
}
struct Machine {
buttons: (Button, Button),
prize: (f64, f64),
}
struct Button {
cost: f64,
x: f64,
y: f64,
}
#[derive(pest_derive::Parser)]
#[grammar = "grammars/day13.pest"]
struct MachinesParser {}
fn parse_machines(input: &str) -> Vec<Machine> {
MachinesParser::parse(Rule::machines, input)
.unwrap()
.nth(0)
.unwrap()
.into_inner()
.map(Pair::<'_, Rule>::into_inner)
.map(Machine::parse)
.collect()
}
impl Machine {
fn parse(input: Pairs<'_, Rule>) -> Self {
let (a, b, prize) = input.map(|p| p.into_inner()).collect_tuple().unwrap();
let buttons = [a, b]
.into_iter()
.map(Button::parse)
.collect_tuple()
.unwrap();
let prize = prize
.map(|n| n.as_str().parse::<u64>().unwrap())
.collect_tuple()
.map(|(x, y)| ((x + OFFSETS.0) as f64, (y + OFFSETS.1) as f64))
.unwrap();
Self { buttons, prize }
}
}
impl Button {
fn parse(input: Pairs<'_, Rule>) -> Self {
let (t, x, y) = input.collect_tuple().unwrap();
let cost = match t.as_str() {
"A" => 3.,
"B" => 1.,
_ => unreachable!(),
};
Self {
x: x.as_str().parse::<f64>().unwrap(),
y: y.as_str().parse::<f64>().unwrap(),
cost,
}
}
}