1use crate::util::math::*;
18use crate::util::parse::*;
19use std::array::from_fn;
20
21type Axis = [i32; 8];
22type Input = [Axis; 3];
23
24pub fn parse(input: &str) -> Input {
26 let n: Vec<_> = input.iter_signed().collect();
27 [
28 [n[0], n[3], n[6], n[9], 0, 0, 0, 0],
29 [n[1], n[4], n[7], n[10], 0, 0, 0, 0],
30 [n[2], n[5], n[8], n[11], 0, 0, 0, 0],
31 ]
32}
33
34pub fn part1(input: &Input) -> i32 {
35 let [mut x, mut y, mut z] = *input;
36
37 for _ in 0..1000 {
38 x = step(x);
39 y = step(y);
40 z = step(z);
41 }
42
43 let [p0, p1, p2, p3, v0, v1, v2, v3] = from_fn(|i| x[i].abs() + y[i].abs() + z[i].abs());
44 p0 * v0 + p1 * v1 + p2 * v2 + p3 * v3
45}
46
47pub fn part2(input: &Input) -> usize {
48 let [mut x, mut y, mut z] = *input;
49 let [mut a, mut b, mut c] = [0, 0, 0];
50 let mut count = 0;
51
52 while a * b * c == 0 {
53 count += 1;
54
55 if a == 0 {
56 x = step(x);
57 if stopped(x) {
58 a = count;
59 }
60 }
61
62 if b == 0 {
63 y = step(y);
64 if stopped(y) {
65 b = count;
66 }
67 }
68
69 if c == 0 {
70 z = step(z);
71 if stopped(z) {
72 c = count;
73 }
74 }
75 }
76
77 2 * a.lcm(b.lcm(c))
79}
80
81fn step(axis: Axis) -> Axis {
82 let [p0, p1, p2, p3, v0, v1, v2, v3] = axis;
84
85 let a = (p1 - p0).signum();
86 let b = (p2 - p0).signum();
87 let c = (p3 - p0).signum();
88 let d = (p2 - p1).signum();
89 let e = (p3 - p1).signum();
90 let f = (p3 - p2).signum();
91
92 let n0 = v0 + a + b + c;
93 let n1 = v1 - a + d + e;
94 let n2 = v2 - b - d + f;
95 let n3 = v3 - c - e - f;
96
97 [p0 + n0, p1 + n1, p2 + n2, p3 + n3, n0, n1, n2, n3]
98}
99
100fn stopped(axis: Axis) -> bool {
101 axis[4] == 0 && axis[5] == 0 && axis[6] == 0 && axis[7] == 0
102}