advent-of-code

Perserverance, or the lack thereof

git clone git://git.shimmy1996.com/advent-of-code.git

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 }