day13
This commit is contained in:
parent
8cd421a8ef
commit
647e2fb356
|
@ -0,0 +1,254 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::character::complete::{multispace0, u64 as parse_u64};
|
||||||
|
use nom::multi::many0;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Case {
|
||||||
|
button_a: (u64, u64),
|
||||||
|
button_b: (u64, u64),
|
||||||
|
prize: (u64, u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
type Input = Vec<Case>;
|
||||||
|
|
||||||
|
#[aoc_generator(day13)]
|
||||||
|
fn parse(input: &str) -> Input {
|
||||||
|
many0(parse_case)(input).unwrap().1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_case(input: &str) -> IResult<&str, Case> {
|
||||||
|
let (input, _) = tag("Button A: X+")(input)?;
|
||||||
|
let (input, button_a_x) = parse_u64(input)?;
|
||||||
|
let (input, _) = tag(", Y+")(input)?;
|
||||||
|
let (input, button_a_y) = parse_u64(input)?;
|
||||||
|
let (input, _) = tag("\nButton B: X+")(input)?;
|
||||||
|
let (input, button_b_x) = parse_u64(input)?;
|
||||||
|
let (input, _) = tag(", Y+")(input)?;
|
||||||
|
let (input, button_b_y) = parse_u64(input)?;
|
||||||
|
let (input, _) = tag("\nPrize: X=")(input)?;
|
||||||
|
let (input, prize_x) = parse_u64(input)?;
|
||||||
|
let (input, _) = tag(", Y=")(input)?;
|
||||||
|
let (input, prize_y) = parse_u64(input)?;
|
||||||
|
let (input, _) = multispace0(input)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
input,
|
||||||
|
Case {
|
||||||
|
button_a: (button_a_x, button_a_y),
|
||||||
|
button_b: (button_b_x, button_b_y),
|
||||||
|
prize: (prize_x, prize_y),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day13, part1)]
|
||||||
|
fn part1(input: &Input) -> u64 {
|
||||||
|
input
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|case| {
|
||||||
|
let (vec_low, vec_high, cost_low, cost_high) = match (case.button_a.1 * case.button_b.0)
|
||||||
|
.cmp(&(case.button_a.0 * case.button_b.1))
|
||||||
|
{
|
||||||
|
Ordering::Greater => (case.button_b, case.button_a, 1, 3),
|
||||||
|
Ordering::Less => (case.button_a, case.button_b, 3, 1),
|
||||||
|
Ordering::Equal => panic!("Parallel"),
|
||||||
|
};
|
||||||
|
let vec_prize = case.prize;
|
||||||
|
|
||||||
|
let vec_low_norm = (
|
||||||
|
vec_low.0 as f64 / ((vec_low.0 * vec_low.0 + vec_low.1 * vec_low.1) as f64).sqrt(),
|
||||||
|
vec_low.1 as f64 / ((vec_low.0 * vec_low.0 + vec_low.1 * vec_low.1) as f64).sqrt(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let vec_prize_proj = (
|
||||||
|
vec_low_norm.0
|
||||||
|
* (vec_prize.0 as f64 * vec_low_norm.0 + vec_prize.1 as f64 * vec_low_norm.1),
|
||||||
|
vec_low_norm.1
|
||||||
|
* (vec_prize.0 as f64 * vec_low_norm.0 + vec_prize.1 as f64 * vec_low_norm.1),
|
||||||
|
);
|
||||||
|
|
||||||
|
let vec_prize_perp = (
|
||||||
|
vec_prize.0 as f64 - vec_prize_proj.0,
|
||||||
|
vec_prize.1 as f64 - vec_prize_proj.1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let len_prize_perp =
|
||||||
|
(vec_prize_perp.0 * vec_prize_perp.0 + vec_prize_perp.1 * vec_prize_perp.1).sqrt();
|
||||||
|
|
||||||
|
let vec_high_proj = (
|
||||||
|
vec_low_norm.0
|
||||||
|
* (vec_high.0 as f64 * vec_low_norm.0 + vec_high.1 as f64 * vec_low_norm.1),
|
||||||
|
vec_low_norm.1
|
||||||
|
* (vec_high.0 as f64 * vec_low_norm.0 + vec_high.1 as f64 * vec_low_norm.1),
|
||||||
|
);
|
||||||
|
|
||||||
|
let vec_high_perp = (
|
||||||
|
vec_high.0 as f64 - vec_high_proj.0,
|
||||||
|
vec_high.1 as f64 - vec_high_proj.1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let len_high_perp =
|
||||||
|
(vec_high_perp.0 * vec_high_perp.0 + vec_high_perp.1 * vec_high_perp.1).sqrt();
|
||||||
|
|
||||||
|
let n_high = len_prize_perp / len_high_perp;
|
||||||
|
|
||||||
|
let vec_low_goal = (
|
||||||
|
vec_prize.0 as f64 - n_high * vec_high.0 as f64,
|
||||||
|
vec_prize.1 as f64 - n_high * vec_high.1 as f64,
|
||||||
|
);
|
||||||
|
|
||||||
|
let len_low = ((vec_low.0 * vec_low.0 + vec_low.1 * vec_low.1) as f64).sqrt();
|
||||||
|
|
||||||
|
let len_low_goal =
|
||||||
|
(vec_low_goal.0 * vec_low_goal.0 + vec_low_goal.1 * vec_low_goal.1).sqrt();
|
||||||
|
|
||||||
|
let n_low = len_low_goal / len_low;
|
||||||
|
|
||||||
|
let n_high = n_high.round() as u64;
|
||||||
|
let n_low = n_low.round() as u64;
|
||||||
|
|
||||||
|
if n_high * vec_high.0 + n_low * vec_low.0 == vec_prize.0
|
||||||
|
&& n_high * vec_high.1 + n_low * vec_low.1 == vec_prize.1
|
||||||
|
{
|
||||||
|
n_high * cost_high + n_low * cost_low
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day13, part2)]
|
||||||
|
fn part2(input: &Input) -> u64 {
|
||||||
|
input
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|case| {
|
||||||
|
let (vec_low, vec_high, cost_low, cost_high) = match (case.button_a.1 * case.button_b.0)
|
||||||
|
.cmp(&(case.button_a.0 * case.button_b.1))
|
||||||
|
{
|
||||||
|
Ordering::Greater => (case.button_b, case.button_a, 1, 3),
|
||||||
|
Ordering::Less => (case.button_a, case.button_b, 3, 1),
|
||||||
|
Ordering::Equal => panic!("Parallel"),
|
||||||
|
};
|
||||||
|
let vec_prize = (
|
||||||
|
case.prize.0 + 10_000_000_000_000,
|
||||||
|
case.prize.1 + 10_000_000_000_000,
|
||||||
|
);
|
||||||
|
|
||||||
|
let vec_low_norm = (
|
||||||
|
vec_low.0 as f64 / ((vec_low.0 * vec_low.0 + vec_low.1 * vec_low.1) as f64).sqrt(),
|
||||||
|
vec_low.1 as f64 / ((vec_low.0 * vec_low.0 + vec_low.1 * vec_low.1) as f64).sqrt(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let vec_prize_proj = (
|
||||||
|
vec_low_norm.0
|
||||||
|
* (vec_prize.0 as f64 * vec_low_norm.0 + vec_prize.1 as f64 * vec_low_norm.1),
|
||||||
|
vec_low_norm.1
|
||||||
|
* (vec_prize.0 as f64 * vec_low_norm.0 + vec_prize.1 as f64 * vec_low_norm.1),
|
||||||
|
);
|
||||||
|
|
||||||
|
let vec_prize_perp = (
|
||||||
|
vec_prize.0 as f64 - vec_prize_proj.0,
|
||||||
|
vec_prize.1 as f64 - vec_prize_proj.1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let len_prize_perp =
|
||||||
|
(vec_prize_perp.0 * vec_prize_perp.0 + vec_prize_perp.1 * vec_prize_perp.1).sqrt();
|
||||||
|
|
||||||
|
let vec_high_proj = (
|
||||||
|
vec_low_norm.0
|
||||||
|
* (vec_high.0 as f64 * vec_low_norm.0 + vec_high.1 as f64 * vec_low_norm.1),
|
||||||
|
vec_low_norm.1
|
||||||
|
* (vec_high.0 as f64 * vec_low_norm.0 + vec_high.1 as f64 * vec_low_norm.1),
|
||||||
|
);
|
||||||
|
|
||||||
|
let vec_high_perp = (
|
||||||
|
vec_high.0 as f64 - vec_high_proj.0,
|
||||||
|
vec_high.1 as f64 - vec_high_proj.1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let len_high_perp =
|
||||||
|
(vec_high_perp.0 * vec_high_perp.0 + vec_high_perp.1 * vec_high_perp.1).sqrt();
|
||||||
|
|
||||||
|
let n_high = len_prize_perp / len_high_perp;
|
||||||
|
|
||||||
|
let vec_low_goal = (
|
||||||
|
vec_prize.0 as f64 - n_high * vec_high.0 as f64,
|
||||||
|
vec_prize.1 as f64 - n_high * vec_high.1 as f64,
|
||||||
|
);
|
||||||
|
|
||||||
|
let len_low = ((vec_low.0 * vec_low.0 + vec_low.1 * vec_low.1) as f64).sqrt();
|
||||||
|
|
||||||
|
let len_low_goal =
|
||||||
|
(vec_low_goal.0 * vec_low_goal.0 + vec_low_goal.1 * vec_low_goal.1).sqrt();
|
||||||
|
|
||||||
|
let n_low = len_low_goal / len_low;
|
||||||
|
|
||||||
|
let n_high = n_high.round() as u64;
|
||||||
|
let n_low = n_low.round() as u64;
|
||||||
|
|
||||||
|
if n_high * vec_high.0 + n_low * vec_low.0 == vec_prize.0
|
||||||
|
&& n_high * vec_high.1 + n_low * vec_low.1 == vec_prize.1
|
||||||
|
{
|
||||||
|
n_high * cost_high + n_low * cost_low
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(
|
||||||
|
part1(&parse(
|
||||||
|
"Button A: X+94, Y+34
|
||||||
|
Button B: X+22, Y+67
|
||||||
|
Prize: X=8400, Y=5400"
|
||||||
|
)),
|
||||||
|
280
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
part1(&parse(
|
||||||
|
"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"
|
||||||
|
)),
|
||||||
|
480
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
part1(&parse(include_str!("../input/2024/day13.txt").trim_end())),
|
||||||
|
28753
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(
|
||||||
|
part2(&parse(include_str!("../input/2024/day13.txt").trim_end())),
|
||||||
|
102718967795500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ mod day1;
|
||||||
mod day10;
|
mod day10;
|
||||||
mod day11;
|
mod day11;
|
||||||
mod day12;
|
mod day12;
|
||||||
|
mod day13;
|
||||||
mod day2;
|
mod day2;
|
||||||
mod day3;
|
mod day3;
|
||||||
mod day4;
|
mod day4;
|
||||||
|
|
Loading…
Reference in New Issue