diff --git a/2018/src/bin/day4.rs b/2018/src/bin/day4.rs index bf7492f..e864319 100644 --- a/2018/src/bin/day4.rs +++ b/2018/src/bin/day4.rs @@ -3,10 +3,10 @@ extern crate lazy_static; extern crate chrono; extern crate regex; -use chrono::{DateTime, TimeZone, Utc, Duration, Timelike}; +use chrono::{DateTime, Duration, TimeZone, Timelike, Utc}; use regex::Regex; -use std::fs; use std::collections::HashMap; +use std::fs; #[derive(Debug)] enum Action { @@ -21,6 +21,14 @@ struct Entry { action: Action, } +impl Entry { + fn new(time: DateTime, action: Action) -> Self { + Self { time, action } + } +} + +// If anyone is reading this, it's not great Rust code... + fn main() { let input = fs::read_to_string("input/day4.txt").expect("input"); @@ -33,25 +41,66 @@ fn main() { entries.sort_unstable_by(|a, b| a.time.cmp(&b.time)); entries }; + let entries_by_guard = entries_by_guard(&entries); - part1(&entries); + part1(&entries_by_guard); + part2(&entries_by_guard); } -fn part1(entries: &[Entry]) { - // First group entries by guard - let entries_by_guard = entries_by_guard(entries); - - // Next find the one that was asleep the most +fn part1(entries_by_guard: &HashMap>) { + // Find the one that was asleep the most let guards_by_time_asleep = calculate_time_asleep(&entries_by_guard); - let asleep_the_most = guards_by_time_asleep.iter().max_by(|(_guard_id, time_asleep), (_other_guard_id, other_time_asleep)| time_asleep.cmp(other_time_asleep)); - println!("{:?}", asleep_the_most); + let asleep_the_most = guards_by_time_asleep.iter().max_by( + |(_guard_id, time_asleep), (_other_guard_id, other_time_asleep)| { + time_asleep.cmp(other_time_asleep) + }, + ); // Now find the minute that guard is asleep the most let sleepiest_guard = asleep_the_most.unwrap().0; let sleep_by_minute = sleep_by_minute(&entries_by_guard[sleepiest_guard]); - let sleepiest_minute = sleep_by_minute.iter().max_by(|(_minute, count), (_other_minute, other_count)| count.cmp(other_count)).unwrap(); + let sleepiest_minute = sleep_by_minute + .iter() + .max_by(|(_minute, count), (_other_minute, other_count)| count.cmp(other_count)) + .unwrap(); - println!("Day 1: {}", sleepiest_minute.0 * sleepiest_guard); + println!("Part 1: {}", sleepiest_minute.0 * sleepiest_guard); +} + +fn part2(entries_by_guard: &HashMap>) { + let results: HashMap<_, _> = entries_by_guard + .keys() + .filter_map(|guard_id| { + let sleep_by_minute = sleep_by_minute(&entries_by_guard[&guard_id]); + + if sleep_by_minute.is_empty() { + None + } else { + Some((guard_id, sleep_by_minute)) + } + }) + .collect(); + + // Now find the answer + if let Some((guard_id, minute_counts)) = + results + .iter() + .max_by(|(_, minute_counts), (_, other_minute_counts)| { + max_minute(&minute_counts) + .1 + .cmp(&max_minute(&other_minute_counts).1) + }) + { + let minute = max_minute(minute_counts).0; + println!( + "Part 2: guard {} * minute {} = {}", + *guard_id, + minute, + *guard_id * minute + ); + } else { + println!("Part 2: No result found"); + } } fn entries_by_guard(entries: &[Entry]) -> HashMap> { @@ -59,19 +108,25 @@ fn entries_by_guard(entries: &[Entry]) -> HashMap> { let mut current_guard = None; for entry in entries { - println!("{:?}", entry); - match entry.action { Action::BeginShift(guard_id) => { - let guard_entry = entries_by_guard.entry(guard_id).or_insert_with(|| Vec::new()); + let guard_entry = entries_by_guard + .entry(guard_id) + .or_insert_with(|| Vec::new()); guard_entry.push(entry); current_guard = Some(guard_id); } Action::FallAsleep => { - entries_by_guard.get_mut(¤t_guard.unwrap()).unwrap().push(entry); + entries_by_guard + .get_mut(¤t_guard.unwrap()) + .unwrap() + .push(entry); } Action::WakeUp => { - entries_by_guard.get_mut(¤t_guard.unwrap()).unwrap().push(entry); + entries_by_guard + .get_mut(¤t_guard.unwrap()) + .unwrap() + .push(entry); } } } @@ -87,10 +142,12 @@ fn calculate_time_asleep(entries_by_guard: &HashMap>) -> HashMa for entry in entries { match entry.action { - Action::BeginShift(guard_id) => {} + Action::BeginShift(_guard_id) => {} Action::FallAsleep => fell_asleep = Some(entry.time), Action::WakeUp => { - let total_time_asleep = time_asleep.entry(guard_id).or_insert_with(|| Duration::zero()); + let total_time_asleep = time_asleep + .entry(guard_id) + .or_insert_with(|| Duration::zero()); *total_time_asleep = *total_time_asleep + (entry.time - fell_asleep.unwrap()); } } @@ -106,7 +163,7 @@ fn sleep_by_minute(entries: &[&Entry]) -> HashMap { for entry in entries { match entry.action { - Action::BeginShift(guard_id) => {} + Action::BeginShift(_guard_id) => {} Action::FallAsleep => fell_asleep = Some(entry.time), Action::WakeUp => { for minute in fell_asleep.unwrap().minute()..entry.time.minute() { @@ -141,8 +198,10 @@ fn parse_entry(line: &str) -> Option { } } -impl Entry { - fn new(time: DateTime, action: Action) -> Self { - Self { time, action } - } +fn max_minute(hash: &HashMap) -> (u32, u32) { + hash + .iter() + .max_by(|(_, count), (_, other_count)| count.cmp(other_count)) + .map(|(&minute, &count)| (minute, count)) + .unwrap() }