aoc/year2021/
day07.rs

1//! # The Treachery of Whales
2//!
3//! Part 1 is a disguised definition of the mathematical [median](https://en.wikipedia.org/wiki/Median).
4//! We can calculate the result immediately using the standard algorithm.
5//!
6//! Part 2 is found by using the [mean](https://en.wikipedia.org/wiki/Mean).
7//! However since this could a floating point value and we are using integers we need to check
8//! 3 values total, the rounded result and one value on either side to ensure the correct answer.
9use crate::util::parse::*;
10
11pub fn parse(input: &str) -> Vec<i32> {
12    input.iter_signed().collect()
13}
14
15pub fn part1(input: &[i32]) -> i32 {
16    let median = median(input);
17    input.iter().map(|n| (n - median).abs()).sum()
18}
19
20pub fn part2(input: &[i32]) -> i32 {
21    let mean = mean(input);
22    let triangle = |x: i32, mean: i32| {
23        let n = (x - mean).abs();
24        (n * (n + 1)) / 2
25    };
26
27    let first: i32 = input.iter().map(|&x| triangle(x, mean)).sum();
28    let second: i32 = input.iter().map(|&x| triangle(x, mean + 1)).sum();
29    let third: i32 = input.iter().map(|&x| triangle(x, mean - 1)).sum();
30    first.min(second).min(third)
31}
32
33fn median(input: &[i32]) -> i32 {
34    let mut crabs = input.to_vec();
35    crabs.sort_unstable();
36
37    let half = input.len() / 2;
38    let odd = crabs.len() % 2 == 1;
39
40    if odd { crabs[half] } else { (crabs[half - 1] + crabs[half]) / 2 }
41}
42
43fn mean(input: &[i32]) -> i32 {
44    let sum: i32 = input.iter().sum();
45    sum / (input.len() as i32)
46}