Dag 13 af, was makkelijk als je het gewoon direct uitrekende

This commit is contained in:
2024-12-17 16:52:09 +01:00
parent 1cf9bbcaca
commit 4ab100300d
4 changed files with 1464 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
[package]
name = "main"
version = "0.1.0"
edition = "2021"
[dependencies]
nom = "7.1.3"

File diff suppressed because it is too large Load Diff

View 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());
}
}
}
}

View File

@@ -0,0 +1,15 @@
Button A: X+94, Y+34
Button B: X+22, Y+67
Prize: X=8400, Y=5400
Button A: X+26, Y+66
Button B: X+67, Y+21
Prize: X=12748, Y=12176
Button A: X+17, Y+86
Button B: X+84, Y+37
Prize: X=7870, Y=6450
Button A: X+69, Y+23
Button B: X+27, Y+71
Prize: X=18641, Y=10279