Perserverance, or the lack thereof

`git clone git://git.shimmy1996.com/advent-of-code.git`
```commit 701edf2e478876c8d6ce1a777ebdc1ffe2b63383
Author: Shimmy Xu <shimmy.xu@shimmy1996.com>
Date:   Fri, 13 Dec 2019 01:18:39 -0500

Add Rust solution for day 12

Diffstat:
```
```1 file changed, 92 insertions(+), 0 deletions(-)
diff --git a/day-12/day-12.rs b/day-12/day-12.rs
@@ -0,0 +1,92 @@
+fn main() {
+    let input = vec![
+        vec![14, 15, -2],
+        vec![17, -3, 4],
+        vec![6, 12, -13],
+        vec![-2, 10, -8],
+    ];
+
+    println!("Rust:");
+    println!("Part 1: {}", part_1(&input));
+    println!("Part 2: {}", part_2(&input));
+}
+
+fn evolve(coord: &mut Vec<isize>, velocity: &mut Vec<isize>) {
+    let num_stars = coord.len();
+    for i in 0..num_stars {
+        for j in (i + 1)..num_stars {
+            let dv = (coord[j] - coord[i]).signum();
+            velocity[i] += dv;
+            velocity[j] -= dv;
+        }
+    }
+    coord
+        .iter_mut()
+        .zip(velocity.iter())
+        .for_each(|(c, v)| *c += v);
+}
+
+fn calc_energy(coord: &Vec<Vec<isize>>, velocity: &Vec<Vec<isize>>) -> isize {
+    // Calculate energy.
+    let pot = (0..coord[0].len())
+        .map(|i| (0..coord.len()).fold(0, |acc, dim| acc + coord[dim][i].abs()))
+        .collect::<Vec<_>>();
+    let kin = (0..velocity[0].len())
+        .map(|i| (0..coord.len()).fold(0, |acc, dim| acc + velocity[dim][i].abs()))
+        .collect::<Vec<_>>();
+    pot.iter()
+        .zip(kin.iter())
+        .fold(0, |acc, (p, k)| acc + p * k)
+}
+
+fn calc_period(mut coord: Vec<isize>) -> u128 {
+    let mut velocity = vec![0; coord.len()];
+    let mut i = 0;
+    let mut abs_speed_sum = 1;
+    while abs_speed_sum != 0 {
+        evolve(&mut coord, &mut velocity);
+        // Cycle reaches half point when all speed reaches 0.
+        abs_speed_sum = velocity.iter().fold(0, |acc, v| acc + v.abs());
+        i += 1;
+    }
+    i * 2
+}
+
+fn gcd(mut x: u128, mut y: u128) -> u128 {
+    while x > 0 && y > 0 {
+        x %= y;
+        if x != 0 {
+            y %= x;
+        }
+    }
+    x + y
+}
+
+fn lcm(x: u128, y: u128) -> u128 {
+    let factor = gcd(x, y);
+    x * y / factor
+}
+
+fn part_1(input: &Vec<Vec<isize>>) -> isize {
+    // Treat each direction independently.
+    let num_dim = input[0].len();
+    let num_star = input.len();
+    let mut coord = (0..num_dim)
+        .map(|dim| input.iter().map(|c| c[dim]).collect())
+        .collect::<Vec<Vec<isize>>>();
+    let mut velocity = vec![vec![0; num_star]; num_dim];
+    for _ in 0..1000 {
+        (0..num_dim)
+            .for_each(|dim| evolve(coord.get_mut(dim).unwrap(), velocity.get_mut(dim).unwrap()));
+    }
+    calc_energy(&coord, &velocity)
+}
+
+fn part_2(input: &Vec<Vec<isize>>) -> u128 {
+    // Each direction should be independent and have their own cycles.
+    // So get the period in each direction and find least common multiplier.
+    let num_dim = input[0].len();
+    (0..num_dim)
+        .map(|dim| calc_period(input.iter().map(|c| c[dim]).collect()))
+        .fold(1, |acc, cycle| lcm(acc, cycle))
+}
```