Dag 13 af, was makkelijk als je het gewoon direct uitrekende
This commit is contained in:
163
advent_of_code/2024/13/src/main.rs
Normal file
163
advent_of_code/2024/13/src/main.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
use nom::{
|
||||
bytes::complete::tag,
|
||||
character::complete::{i64, multispace1},
|
||||
multi::many1,
|
||||
sequence::{delimited, separated_pair, tuple},
|
||||
IResult,
|
||||
};
|
||||
|
||||
fn parse(input: &str) -> IResult<&str, Vec<((i64, i64), (i64, i64), (i64, i64))>> {
|
||||
let (_input, result) = many1(tuple((
|
||||
delimited(
|
||||
tag("Button A: X+"),
|
||||
separated_pair(i64, tag(", Y+"), i64),
|
||||
multispace1,
|
||||
),
|
||||
delimited(
|
||||
tag("Button B: X+"),
|
||||
separated_pair(i64, tag(", Y+"), i64),
|
||||
multispace1,
|
||||
),
|
||||
delimited(
|
||||
tag("Prize: X="),
|
||||
separated_pair(i64, tag(", Y="), i64),
|
||||
multispace1,
|
||||
),
|
||||
)))(input)?;
|
||||
|
||||
Ok((input, result))
|
||||
}
|
||||
|
||||
// For a / b
|
||||
fn divisible(a: f64, b: f64, epsilon: f64) -> bool {
|
||||
let div = a / b;
|
||||
|
||||
(div - div.round()).abs() < epsilon
|
||||
}
|
||||
|
||||
fn equal(a: f64, b: f64, epsilon: f64) -> bool {
|
||||
(a - b).abs() < epsilon
|
||||
}
|
||||
|
||||
fn linear_solve_1(a: (i64, i64), b: (i64, i64), prize: (i64, i64)) -> Option<i64> {
|
||||
const EPS: f64 = 0.000001;
|
||||
|
||||
let (fa1, fb1) = (a.0 as f64, a.1 as f64);
|
||||
let (fa2, fb2) = (b.0 as f64, b.1 as f64);
|
||||
let (p1, p2) = (prize.0 as f64, prize.1 as f64);
|
||||
|
||||
let y_denominator = fb2 - fb1 * fa2 / fa1;
|
||||
if equal(y_denominator, 0.0, EPS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let y_nominator = p2 - fb1 * p1 / fa1;
|
||||
if !divisible(y_nominator, y_denominator, EPS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let x_nominator = p1 - fa2 * (p2 - fb1 * p1 / fa1) / (fb2 - fb1 * fa2 / fa1);
|
||||
if !divisible(x_nominator, fa1, EPS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let y = (y_nominator / y_denominator).round() as i64;
|
||||
let x = (x_nominator / fa1).round() as i64;
|
||||
|
||||
if x < 0 || y < 0 || x > 100 || y > 100 {
|
||||
return None;
|
||||
} else {
|
||||
return Some(x * 3 + y);
|
||||
}
|
||||
}
|
||||
|
||||
fn linear_solve_2(a: (i64, i64), b: (i64, i64), prize: (i64, i64)) -> Option<i64> {
|
||||
const EPS: f64 = 0.001;
|
||||
const BONUS: i64 = 10000000000000;
|
||||
|
||||
let (fa1, fb1) = (a.0 as f64, a.1 as f64);
|
||||
let (fa2, fb2) = (b.0 as f64, b.1 as f64);
|
||||
let (p1, p2) = ((prize.0 + BONUS) as f64, (prize.1 + BONUS) as f64);
|
||||
|
||||
let y_denominator = fb2 - fb1 * fa2 / fa1;
|
||||
if equal(y_denominator, 0.0, EPS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let y_nominator = p2 - fb1 * p1 / fa1;
|
||||
if !divisible(y_nominator, y_denominator, EPS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let x_nominator = p1 - fa2 * (p2 - fb1 * p1 / fa1) / (fb2 - fb1 * fa2 / fa1);
|
||||
if !divisible(x_nominator, fa1, EPS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let y = (y_nominator / y_denominator).round() as i64;
|
||||
let x = (x_nominator / fa1).round() as i64;
|
||||
|
||||
if x < 0 || y < 0 {
|
||||
return None;
|
||||
} else {
|
||||
return Some(x * 3 + y);
|
||||
}
|
||||
}
|
||||
|
||||
fn solve_1(input: &str) -> i64 {
|
||||
let (_, result) = parse(input).unwrap();
|
||||
|
||||
result
|
||||
.into_iter()
|
||||
.filter_map(|(a, b, prize)| linear_solve_1(a, b, prize))
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn solve_2(input: &str) -> i64 {
|
||||
let (_, result) = parse(input).unwrap();
|
||||
|
||||
result
|
||||
.into_iter()
|
||||
.filter_map(|(a, b, prize)| linear_solve_2(a, b, prize))
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, this is Patrick!");
|
||||
|
||||
let input = include_str!("../input.txt");
|
||||
|
||||
let result_1 = solve_1(input);
|
||||
println!("The fewest tokens spent to get all prizes is {}", result_1);
|
||||
|
||||
let result_2 = solve_2(input);
|
||||
println!(
|
||||
"With the huge positions, the fewest tokens to get all prizes is now {}",
|
||||
result_2
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_1() {
|
||||
let test_input = include_str!("../test.txt");
|
||||
assert_eq!(solve_1(test_input), 480);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2() {
|
||||
let test_input = include_str!("../test.txt");
|
||||
let ts = parse(test_input).unwrap().1;
|
||||
|
||||
for (i, t) in ts.into_iter().enumerate() {
|
||||
if i % 2 == 0 {
|
||||
assert!(linear_solve_2(t.0, t.1, t.2).is_none());
|
||||
} else {
|
||||
assert!(linear_solve_2(t.0, t.1, t.2).is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user