Compare commits
5 Commits
8cd421a8ef
...
fdbbd934a4
Author | SHA1 | Date |
---|---|---|
![]() |
fdbbd934a4 | |
![]() |
f87e5ea0af | |
![]() |
f9c32f0022 | |
![]() |
2cf47fd7d6 | |
![]() |
647e2fb356 |
|
@ -55,6 +55,7 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"nom",
|
"nom",
|
||||||
"num",
|
"num",
|
||||||
|
"num-modular",
|
||||||
"regex",
|
"regex",
|
||||||
"topological-sort",
|
"topological-sort",
|
||||||
]
|
]
|
||||||
|
@ -169,6 +170,12 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-modular"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-rational"
|
name = "num-rational"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
|
|
@ -9,5 +9,6 @@ aoc-runner-derive = "0.3.0"
|
||||||
hashbrown = "0.15.2"
|
hashbrown = "0.15.2"
|
||||||
nom = "7.1.3"
|
nom = "7.1.3"
|
||||||
num = "0.4.3"
|
num = "0.4.3"
|
||||||
|
num-modular = "0.6.1"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
topological-sort = "0.2.2"
|
topological-sort = "0.2.2"
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::character::complete::i64 as parse_u64;
|
||||||
|
use nom::multi::separated_list0;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Case {
|
||||||
|
button_a: (i64, i64),
|
||||||
|
button_b: (i64, i64),
|
||||||
|
prize: (i64, i64),
|
||||||
|
}
|
||||||
|
|
||||||
|
type Input = Vec<Case>;
|
||||||
|
|
||||||
|
#[aoc_generator(day13)]
|
||||||
|
fn parse(input: &str) -> Input {
|
||||||
|
separated_list0(tag("\n\n"), 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)?;
|
||||||
|
|
||||||
|
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) -> i64 {
|
||||||
|
input
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|case| {
|
||||||
|
let vec_a = case.button_a;
|
||||||
|
let vec_b = case.button_b;
|
||||||
|
let vec_p = case.prize;
|
||||||
|
|
||||||
|
if (vec_p.0 * vec_b.1 - vec_b.0 * vec_p.1) % (vec_a.0 * vec_b.1 - vec_b.0 * vec_a.1)
|
||||||
|
== 0
|
||||||
|
&& (vec_a.0 * vec_p.1 - vec_p.0 * vec_a.1) % (vec_a.0 * vec_b.1 - vec_b.0 * vec_a.1)
|
||||||
|
== 0
|
||||||
|
{
|
||||||
|
let a = (vec_p.0 * vec_b.1 - vec_b.0 * vec_p.1)
|
||||||
|
/ (vec_a.0 * vec_b.1 - vec_b.0 * vec_a.1);
|
||||||
|
let b = (vec_a.0 * vec_p.1 - vec_p.0 * vec_a.1)
|
||||||
|
/ (vec_a.0 * vec_b.1 - vec_b.0 * vec_a.1);
|
||||||
|
a * 3 + b
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day13, part2)]
|
||||||
|
fn part2(input: &Input) -> i64 {
|
||||||
|
input
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|case| {
|
||||||
|
let vec_a = case.button_a;
|
||||||
|
let vec_b = case.button_b;
|
||||||
|
let vec_p = case.prize;
|
||||||
|
let vec_p = (vec_p.0 + 10_000_000_000_000, vec_p.1 + 10_000_000_000_000);
|
||||||
|
|
||||||
|
if (vec_p.0 * vec_b.1 - vec_b.0 * vec_p.1) % (vec_a.0 * vec_b.1 - vec_b.0 * vec_a.1)
|
||||||
|
== 0
|
||||||
|
&& (vec_a.0 * vec_p.1 - vec_p.0 * vec_a.1) % (vec_a.0 * vec_b.1 - vec_b.0 * vec_a.1)
|
||||||
|
== 0
|
||||||
|
{
|
||||||
|
let a = (vec_p.0 * vec_b.1 - vec_b.0 * vec_p.1)
|
||||||
|
/ (vec_a.0 * vec_b.1 - vec_b.0 * vec_a.1);
|
||||||
|
let b = (vec_a.0 * vec_p.1 - vec_p.0 * vec_a.1)
|
||||||
|
/ (vec_a.0 * vec_b.1 - vec_b.0 * vec_a.1);
|
||||||
|
a * 3 + b
|
||||||
|
} 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
|
use nom::{
|
||||||
|
bytes::complete::tag,
|
||||||
|
character::complete::{i64 as parse_i64, newline, space1},
|
||||||
|
error::Error,
|
||||||
|
multi::separated_list0,
|
||||||
|
sequence::{preceded, separated_pair},
|
||||||
|
};
|
||||||
|
|
||||||
|
use num_modular::ModularPow;
|
||||||
|
|
||||||
|
type Input = Vec<((i64, i64), (i64, i64))>;
|
||||||
|
|
||||||
|
#[aoc_generator(day14)]
|
||||||
|
fn parse(input: &str) -> Input {
|
||||||
|
separated_list0(
|
||||||
|
newline::<&str, Error<&str>>,
|
||||||
|
separated_pair(
|
||||||
|
preceded(tag("p="), separated_pair(parse_i64, tag(","), parse_i64)),
|
||||||
|
space1,
|
||||||
|
preceded(tag("v="), separated_pair(parse_i64, tag(","), parse_i64)),
|
||||||
|
),
|
||||||
|
)(input)
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day14, part1)]
|
||||||
|
fn part1(input: &Input) -> i64 {
|
||||||
|
#[cfg(test)]
|
||||||
|
let (w, h) = (7, 11);
|
||||||
|
#[cfg(not(test))]
|
||||||
|
let (w, h) = (101, 103);
|
||||||
|
|
||||||
|
let mut quadrants = [0, 0, 0, 0];
|
||||||
|
|
||||||
|
input.iter().copied().for_each(|(p, v)| {
|
||||||
|
let (px, py) = (p.0, p.1);
|
||||||
|
let (vx, vy) = (v.0 + w, v.1 + h);
|
||||||
|
let (ex, ey) = ((px + vx * 100) % w, (py + vy * 100) % h);
|
||||||
|
if ex < w / 2 && ey < h / 2 {
|
||||||
|
quadrants[0] += 1;
|
||||||
|
} else if ex > (w - 1) / 2 && ey < h / 2 {
|
||||||
|
quadrants[1] += 1;
|
||||||
|
} else if ex < w / 2 && ey > (h - 1) / 2 {
|
||||||
|
quadrants[2] += 1;
|
||||||
|
} else if ex > (w - 1) / 2 && ey > (h - 1) / 2 {
|
||||||
|
quadrants[3] += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
quadrants.iter().product()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day14, part2)]
|
||||||
|
fn part2(input: &Input) -> i64 {
|
||||||
|
let (w, h) = (101, 103);
|
||||||
|
|
||||||
|
let mut offset_x = 0;
|
||||||
|
let mut min_var = f64::INFINITY;
|
||||||
|
for t in 0..w {
|
||||||
|
let values = input.iter().map(|((p, _), (v, _))| (p + t * (v + w)) % w);
|
||||||
|
let mean = values.clone().sum::<i64>() as f64 / input.len() as f64;
|
||||||
|
let variance = values
|
||||||
|
.map(|v| (v as f64 - mean) * (v as f64 - mean))
|
||||||
|
.sum::<f64>()
|
||||||
|
/ input.len() as f64;
|
||||||
|
if variance < min_var {
|
||||||
|
min_var = variance;
|
||||||
|
offset_x = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut offset_y = 0;
|
||||||
|
let mut min_var = f64::INFINITY;
|
||||||
|
for t in 0..h {
|
||||||
|
let values = input.iter().map(|((_, p), (_, v))| (p + t * (v + h)) % h);
|
||||||
|
let mean = values.clone().sum::<i64>() as f64 / input.len() as f64;
|
||||||
|
let variance = values
|
||||||
|
.map(|v| (v as f64 - mean) * (v as f64 - mean))
|
||||||
|
.sum::<f64>()
|
||||||
|
/ input.len() as f64;
|
||||||
|
if variance < min_var {
|
||||||
|
min_var = variance;
|
||||||
|
offset_y = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let invmod_x = (w as u64).powm((h - 2) as u64, &(h as u64)) as i64;
|
||||||
|
let invmod_y = (h as u64).powm((w - 2) as u64, &(w as u64)) as i64;
|
||||||
|
(offset_x * h * invmod_x + offset_y * w * invmod_y) % (w * h)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(
|
||||||
|
part1(&parse(
|
||||||
|
"p=0,4 v=3,-3
|
||||||
|
p=6,3 v=-1,-3
|
||||||
|
p=10,3 v=-1,2
|
||||||
|
p=2,0 v=2,-1
|
||||||
|
p=0,0 v=1,3
|
||||||
|
p=3,0 v=-2,-2
|
||||||
|
p=7,6 v=-1,-3
|
||||||
|
p=3,0 v=-1,-2
|
||||||
|
p=9,3 v=2,3
|
||||||
|
p=7,3 v=-1,2
|
||||||
|
p=2,4 v=2,-3
|
||||||
|
p=9,5 v=-3,-3"
|
||||||
|
)),
|
||||||
|
12
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(
|
||||||
|
part2(&parse(include_str!("../input/2024/day14.txt").trim_end())),
|
||||||
|
6398
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ mod day1;
|
||||||
mod day10;
|
mod day10;
|
||||||
mod day11;
|
mod day11;
|
||||||
mod day12;
|
mod day12;
|
||||||
|
mod day13;
|
||||||
|
mod day14;
|
||||||
mod day2;
|
mod day2;
|
||||||
mod day3;
|
mod day3;
|
||||||
mod day4;
|
mod day4;
|
||||||
|
|
Loading…
Reference in New Issue