summaryrefslogtreecommitdiffstats
path: root/day01b/src/main.rs
blob: 1f932026382b724008e2ffb944fcf544d3b627e4 (plain)
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#![feature(binary_heap_into_iter_sorted)]

/// --- Part Two ---
///
/// By the time you calculate the answer to the Elves' question, they've already realized that the
/// Elf carrying the most Calories of food might eventually run out of snacks.
///
/// To avoid this unacceptable situation, the Elves would instead like to know the total Calories
/// carried by the top three Elves carrying the most Calories.  That way, even if one of those Elves
/// runs out of snacks, they still have two backups.
///
/// In the example above, the top three Elves are the fourth Elf (with 24000 Calories), then the
/// third Elf (with 11000 Calories), then the fifth Elf (with 10000 Calories).  The sum of the
/// Calories carried by these three elves is 45000.
///
/// Find the top three Elves carrying the most Calories.  How many Calories are those Elves carrying
/// in total?
use clap::Parser;
use itertools::Itertools;

use std::collections::BinaryHeap;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;

const FILEPATH: &'static str = "examples/input.txt";

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Cli {
    #[clap(short, long, default_value = FILEPATH)]
    file: PathBuf,
}

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
struct CalorieCount {
    elf: usize,
    calories: usize,
}

impl PartialOrd for CalorieCount {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for CalorieCount {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.calories.cmp(&other.calories)
    }
}

fn main() {
    let args = Cli::parse();

    let file = File::open(&args.file).unwrap();
    let reader = BufReader::new(file);

    let mut heap = BinaryHeap::new();
    let _ = reader
        .lines()
        .map(|l| l.unwrap())
        .peekable()
        .batching(|it| {
            if it.peek().is_none() {
                return None;
            }
            Some(
                it.take_while(|l| !l.is_empty())
                    .map(|w| w.parse::<usize>().unwrap())
                    .collect::<Vec<usize>>(),
            )
        })
        .zip(1..)
        .scan(&mut heap, |heap, (batch, elf)| {
            heap.push(CalorieCount {
                elf,
                calories: batch.iter().sum(),
            });
            match heap.peek() {
                None => None,
                Some(_) => Some(()),
            }
        })
        .last();

    // Find the top 3 elves carrying the most calories
    let res = heap
        .into_iter_sorted()
        .inspect(|x| println!("calories={:6} elf={}", x.calories, x.elf))
        .take(3)
        .fold(0usize, |acc, x| acc + x.calories);
    println!("The top 3 elves are carry {res} calories");
}