1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//! # Reindeer Olympics
//!
//! In order to make things easier we create a function to calculate the distance travelled by a
//! reindeer at any arbitrary time.
use crate::util::iter::*;
use crate::util::parse::*;

type Reindeer = [u32; 3];

pub fn parse(input: &str) -> Vec<Reindeer> {
    input.iter_unsigned().chunk::<3>().collect()
}

pub fn part1(input: &[Reindeer]) -> u32 {
    part1_testable(input, 2503)
}

pub fn part2(input: &[Reindeer]) -> u32 {
    part2_testable(input, 2503)
}

pub fn part1_testable(input: &[Reindeer], time: u32) -> u32 {
    input.iter().map(|&r| distance(r, time)).max().unwrap()
}

pub fn part2_testable(input: &[Reindeer], time: u32) -> u32 {
    let mut score = vec![0; input.len()];
    let mut distances = vec![0; input.len()];

    for minute in 1..time {
        let mut lead = 0;

        for (index, &reindeer) in input.iter().enumerate() {
            let next = distance(reindeer, minute);
            distances[index] = next;
            lead = lead.max(next);
        }

        for (index, &distance) in distances.iter().enumerate() {
            if distance == lead {
                score[index] += 1;
            }
        }
    }

    *score.iter().max().unwrap()
}

fn distance([speed, fly, rest]: Reindeer, time: u32) -> u32 {
    let total = fly + rest;
    let complete = time / total;
    let partial = (time % total).min(fly);

    speed * (fly * complete + partial)
}