#![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 { 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::().unwrap()) .collect::>(), ) }) .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"); }