1use utils::geometry::Vec2;
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day13 {
7 machines: Vec<Machine>,
8}
9
10#[derive(Copy, Clone, Debug)]
11struct Machine {
12 button_a: Vec2<u64>,
13 button_b: Vec2<u64>,
14 prize: Vec2<u64>,
15}
16
17impl Day13 {
18 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
19 Ok(Self {
20 machines: parser::u64()
21 .with_prefix("Button A: X+")
22 .then(parser::u64().with_prefix(", Y+"))
23 .then(parser::u64().with_prefix(parser::eol().then("Button B: X+")))
24 .then(parser::u64().with_prefix(", Y+"))
25 .then(parser::u64().with_prefix(parser::eol().then("Prize: X=")))
26 .then(parser::u64().with_prefix(", Y="))
27 .with_suffix(parser::eol())
28 .map_res(|(ax, ay, bx, by, px, py)| {
29 let m = Machine {
30 button_a: Vec2::new(ax, ay),
31 button_b: Vec2::new(bx, by),
32 prize: Vec2::new(px, py),
33 };
34
35 if det(m.button_a, m.button_b) == 0 {
38 Err("expected buttons to be linearly independent")
39 } else {
40 Ok(m)
41 }
42 })
43 .parse_lines(input)?,
44 })
45 }
46
47 #[must_use]
48 pub fn part1(&self) -> u64 {
49 self.machines
50 .iter()
51 .map(|m| m.required_tokens().unwrap_or(0))
52 .sum()
53 }
54
55 #[must_use]
56 pub fn part2(&self) -> u64 {
57 self.machines
58 .iter()
59 .map(|&(mut m)| {
60 m.prize += Vec2::new(10000000000000, 10000000000000);
61 m.required_tokens().unwrap_or(0)
62 })
63 .sum()
64 }
65}
66
67impl Machine {
68 fn required_tokens(&self) -> Option<u64> {
69 self.solve().map(|(a, b)| a * 3 + b)
70 }
71
72 fn solve(&self) -> Option<(u64, u64)> {
73 let det_denominator = det(self.button_a, self.button_b);
75 if det_denominator == 0 {
76 return None;
77 }
78
79 let det_a = det(self.prize, self.button_b);
80 let det_b = det(self.button_a, self.prize);
81 if det_a % det_denominator != 0 || det_b % det_denominator != 0 {
82 return None;
83 }
84
85 if let Ok(count_a) = (det_a / det_denominator).try_into()
86 && let Ok(count_b) = (det_b / det_denominator).try_into()
87 {
88 return Some((count_a, count_b));
89 }
90
91 None
92 }
93}
94
95fn det(a: Vec2<u64>, b: Vec2<u64>) -> i64 {
96 (a.x as i64) * (b.y as i64) - (b.x as i64) * (a.y as i64)
97}
98
99examples!(Day13 -> (u64, u64) [
100 {file: "day13_example0.txt", part1: 480},
101]);