feat: day 13
This commit is contained in:
parent
0dc10ff73c
commit
75d1327446
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -33,6 +33,7 @@ dependencies = [
|
|||
"color-eyre",
|
||||
"rayon",
|
||||
"regex",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tracing-test",
|
||||
|
@ -353,6 +354,26 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
|
|
|
@ -17,6 +17,7 @@ full = [
|
|||
"day10",
|
||||
"day11",
|
||||
"day12",
|
||||
"day13",
|
||||
]
|
||||
default = ["full"]
|
||||
day1 = []
|
||||
|
@ -31,6 +32,7 @@ day9 = []
|
|||
day10 = []
|
||||
day11 = []
|
||||
day12 = []
|
||||
day13 = []
|
||||
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -39,6 +41,7 @@ day12 = []
|
|||
color-eyre = "0.6.3"
|
||||
rayon = "1.10.0"
|
||||
regex = "1.11.1"
|
||||
thiserror = "2.0.6"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = "0.3.19"
|
||||
tracing-test = "0.2.5"
|
||||
|
|
15
inputs/day13/example.txt
Normal file
15
inputs/day13/example.txt
Normal 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
|
186
src/day13.rs
Normal file
186
src/day13.rs
Normal file
|
@ -0,0 +1,186 @@
|
|||
#![allow(
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::too_many_lines,
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::cast_precision_loss,
|
||||
clippy::float_cmp
|
||||
)]
|
||||
use std::str::FromStr;
|
||||
|
||||
use color_eyre::eyre::{self, OptionExt};
|
||||
|
||||
struct Elem {
|
||||
x: usize,
|
||||
y: usize,
|
||||
}
|
||||
struct Machine {
|
||||
button_a: Elem,
|
||||
button_b: Elem,
|
||||
prize: Elem,
|
||||
}
|
||||
|
||||
fn parse_button(s: &str) -> Result<Elem, eyre::Error> {
|
||||
let positions = s.split_once(", ").ok_or_eyre("Button A line malformed")?;
|
||||
Ok(Elem {
|
||||
x: positions
|
||||
.0
|
||||
.split_once('+')
|
||||
.ok_or_eyre("seems to be malformed")?
|
||||
.1
|
||||
.parse::<usize>()?,
|
||||
y: positions
|
||||
.1
|
||||
.split_once('+')
|
||||
.ok_or_eyre("seems to be malformed")?
|
||||
.1
|
||||
.parse::<usize>()?,
|
||||
})
|
||||
}
|
||||
|
||||
impl FromStr for Machine {
|
||||
type Err = eyre::Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let lines = s.lines().collect::<Vec<_>>();
|
||||
let button_a = parse_button(lines.first().ok_or_eyre("Could not find button a line")?)?;
|
||||
let button_b = parse_button(lines.get(1).ok_or_eyre("could not find button b line")?)?;
|
||||
let prize_line = lines.get(2).ok_or_eyre("Could not find prize line")?;
|
||||
let prizes = prize_line
|
||||
.split_once(", ")
|
||||
.ok_or_eyre("Could not parse prize line")?;
|
||||
let prize = Elem {
|
||||
x: prizes
|
||||
.0
|
||||
.split_once('=')
|
||||
.ok_or_eyre("Could not parse prize")?
|
||||
.1
|
||||
.parse::<usize>()?,
|
||||
y: prizes
|
||||
.1
|
||||
.split_once('=')
|
||||
.ok_or_eyre("Could not parse prize")?
|
||||
.1
|
||||
.parse::<usize>()?,
|
||||
};
|
||||
Ok(Machine {
|
||||
button_a,
|
||||
button_b,
|
||||
prize,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
pub fn play(&self) -> Option<usize> {
|
||||
let machine = self;
|
||||
let determinant = machine.button_a.x as f64 * machine.button_b.y as f64
|
||||
- machine.button_a.y as f64 * machine.button_b.x as f64;
|
||||
let a = ((-(machine.button_b.x as f64)) * (machine.prize.y as f64)
|
||||
+ machine.button_b.y as f64 * machine.prize.x as f64)
|
||||
/ determinant;
|
||||
let b = (machine.button_a.x as f64 * machine.prize.y as f64
|
||||
- machine.button_a.y as f64 * machine.prize.x as f64)
|
||||
/ determinant;
|
||||
if a.floor() == a && b.floor() == b && a >= 0.0 && b >= 0.0 {
|
||||
if a > 100.0 || b > 100.0 {
|
||||
None
|
||||
} else {
|
||||
Some(a.round() as usize * 3 + b as usize)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn play_without_limits(&self) -> Option<usize> {
|
||||
let machine = self;
|
||||
let determinant = machine.button_a.x as f64 * machine.button_b.y as f64
|
||||
- machine.button_a.y as f64 * machine.button_b.x as f64;
|
||||
let a = ((-(machine.button_b.x as f64)) * (machine.prize.y as f64)
|
||||
+ machine.button_b.y as f64 * machine.prize.x as f64)
|
||||
/ determinant;
|
||||
let b = (machine.button_a.x as f64 * machine.prize.y as f64
|
||||
- machine.button_a.y as f64 * machine.prize.x as f64)
|
||||
/ determinant;
|
||||
if a.floor() == a && b.floor() == b && a >= 0.0 && b >= 0.0 {
|
||||
Some(a.round() as usize * 3 + b as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pt1(input: &str) -> usize {
|
||||
input
|
||||
.split("\n\n")
|
||||
.flat_map(Machine::from_str)
|
||||
.filter_map(|m| m.play())
|
||||
.sum()
|
||||
}
|
||||
pub fn pt2(input: &str) -> usize {
|
||||
input
|
||||
.split("\n\n")
|
||||
.flat_map(Machine::from_str)
|
||||
.map(|mut m| {
|
||||
m.prize.x += 10_000_000_000_000;
|
||||
m.prize.y += 10_000_000_000_000;
|
||||
m
|
||||
})
|
||||
.filter_map(|m| m.play_without_limits())
|
||||
.sum()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tracing_test::traced_test;
|
||||
|
||||
use super::{pt1, pt2, Machine};
|
||||
use std::fs::read_to_string;
|
||||
|
||||
#[traced_test]
|
||||
#[test]
|
||||
pub fn test_pt1() {
|
||||
let input =
|
||||
read_to_string("./inputs/day13/example.txt").expect("Missing example.txt for day13");
|
||||
assert_eq!(pt1(&input), 480)
|
||||
}
|
||||
#[traced_test]
|
||||
#[test]
|
||||
pub fn test_machine_execution1() {
|
||||
let m = Machine {
|
||||
button_a: crate::day13::Elem { x: 94, y: 34 },
|
||||
button_b: crate::day13::Elem { x: 22, y: 67 },
|
||||
prize: crate::day13::Elem { x: 8400, y: 5400 },
|
||||
};
|
||||
assert_eq!(m.play(), Some(280))
|
||||
}
|
||||
#[traced_test]
|
||||
#[test]
|
||||
pub fn test_machine_execution2() {
|
||||
let m = Machine {
|
||||
button_a: crate::day13::Elem { x: 26, y: 66 },
|
||||
button_b: crate::day13::Elem { x: 67, y: 21 },
|
||||
prize: crate::day13::Elem { x: 12748, y: 12176 },
|
||||
};
|
||||
assert_eq!(m.play(), None)
|
||||
}
|
||||
#[traced_test]
|
||||
#[test]
|
||||
pub fn test_machine_execution3() {
|
||||
let m = Machine {
|
||||
button_a: crate::day13::Elem { x: 17, y: 86 },
|
||||
button_b: crate::day13::Elem { x: 84, y: 37 },
|
||||
prize: crate::day13::Elem { x: 7870, y: 6450 },
|
||||
};
|
||||
assert_eq!(m.play(), Some(200))
|
||||
}
|
||||
#[traced_test]
|
||||
#[test]
|
||||
pub fn test_machine_execution4() {
|
||||
let m = Machine {
|
||||
button_a: crate::day13::Elem { x: 69, y: 23 },
|
||||
button_b: crate::day13::Elem { x: 27, y: 71 },
|
||||
prize: crate::day13::Elem { x: 18641, y: 10279 },
|
||||
};
|
||||
assert_eq!(m.play(), None)
|
||||
}
|
||||
}
|
|
@ -27,6 +27,8 @@ mod day10;
|
|||
mod day11;
|
||||
#[cfg(feature = "day12")]
|
||||
mod day12;
|
||||
#[cfg(feature = "day13")]
|
||||
mod day13;
|
||||
|
||||
fn main() -> eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
@ -57,6 +59,8 @@ fn main() -> eyre::Result<()> {
|
|||
solve_day(11, day11::pt1, day11::pt2);
|
||||
#[cfg(feature = "day12")]
|
||||
solve_day(12, day12::pt1, day12::pt2);
|
||||
#[cfg(feature = "day13")]
|
||||
solve_day(13, day13::pt1, day13::pt2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue