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");
}
|