day-12.rs (2660B)
1 fn main() {
2 let input = vec![
3 vec![14, 15, -2],
4 vec![17, -3, 4],
5 vec![6, 12, -13],
6 vec![-2, 10, -8],
7 ];
8
9 println!("Rust:");
10 println!("Part 1: {}", part_1(&input));
11 println!("Part 2: {}", part_2(&input));
12 }
13
14 fn evolve(coord: &mut Vec<isize>, velocity: &mut Vec<isize>) {
15 let num_stars = coord.len();
16 for i in 0..num_stars {
17 for j in (i + 1)..num_stars {
18 let dv = (coord[j] - coord[i]).signum();
19 velocity[i] += dv;
20 velocity[j] -= dv;
21 }
22 }
23 coord
24 .iter_mut()
25 .zip(velocity.iter())
26 .for_each(|(c, v)| *c += v);
27 }
28
29 fn calc_energy(coord: &Vec<Vec<isize>>, velocity: &Vec<Vec<isize>>) -> isize {
30 // Calculate energy.
31 let pot = (0..coord[0].len())
32 .map(|i| (0..coord.len()).fold(0, |acc, dim| acc + coord[dim][i].abs()))
33 .collect::<Vec<_>>();
34 let kin = (0..velocity[0].len())
35 .map(|i| (0..coord.len()).fold(0, |acc, dim| acc + velocity[dim][i].abs()))
36 .collect::<Vec<_>>();
37 pot.iter()
38 .zip(kin.iter())
39 .fold(0, |acc, (p, k)| acc + p * k)
40 }
41
42 fn calc_period(mut coord: Vec<isize>) -> u128 {
43 let mut velocity = vec![0; coord.len()];
44 let mut i = 0;
45 let mut abs_speed_sum = 1;
46 while abs_speed_sum != 0 {
47 evolve(&mut coord, &mut velocity);
48 // Cycle reaches half point when all speed reaches 0.
49 abs_speed_sum = velocity.iter().fold(0, |acc, v| acc + v.abs());
50 i += 1;
51 }
52 i * 2
53 }
54
55 fn gcd(mut x: u128, mut y: u128) -> u128 {
56 while x > 0 && y > 0 {
57 x %= y;
58 if x != 0 {
59 y %= x;
60 }
61 }
62 x + y
63 }
64
65 fn lcm(x: u128, y: u128) -> u128 {
66 let factor = gcd(x, y);
67 x * y / factor
68 }
69
70 fn part_1(input: &Vec<Vec<isize>>) -> isize {
71 // Treat each direction independently.
72 let num_dim = input[0].len();
73 let num_star = input.len();
74 let mut coord = (0..num_dim)
75 .map(|dim| input.iter().map(|c| c[dim]).collect())
76 .collect::<Vec<Vec<isize>>>();
77 let mut velocity = vec![vec![0; num_star]; num_dim];
78 for _ in 0..1000 {
79 (0..num_dim)
80 .for_each(|dim| evolve(coord.get_mut(dim).unwrap(), velocity.get_mut(dim).unwrap()));
81 }
82 calc_energy(&coord, &velocity)
83 }
84
85 fn part_2(input: &Vec<Vec<isize>>) -> u128 {
86 // Each direction should be independent and have their own cycles.
87 // So get the period in each direction and find least common multiplier.
88 let num_dim = input[0].len();
89 (0..num_dim)
90 .map(|dim| calc_period(input.iter().map(|c| c[dim]).collect()))
91 .fold(1, |acc, cycle| lcm(acc, cycle))
92 }