use std::io; use std::io::BufRead; use std::collections::HashMap; use std::cmp::max; use regex::Regex; use lazy_static::lazy_static; #[derive(PartialEq, Eq, PartialOrd, Ord)] enum Action { Begin(i32), Sleep, Wake } #[derive(PartialEq, Eq, PartialOrd, Ord)] struct Record { year: i32, month: i32, day: i32, hour: i32, minute: i32, action: Action } struct Guard { id: i32, sleep_times: Vec<(i32, i32)>, // inclusive-exclusive asleep: [i32; 60] } fn parse_action(line: &str) -> Action { if line.chars().next() == Some('G') { let idx = 7 + line[7..].find(' ').unwrap(); Action::Begin(line[7 .. idx].parse().unwrap()) } else if line.chars().next() == Some('f') { Action::Sleep } else { Action::Wake } } fn parse_line(line: &str) -> Record { lazy_static! { static ref RE: Regex = Regex::new(r"^\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (.*)$").unwrap(); } let caps = RE.captures(line).unwrap(); Record { year: caps.get(1).unwrap().as_str().parse().unwrap(), month: caps.get(2).unwrap().as_str().parse().unwrap(), day: caps.get(3).unwrap().as_str().parse().unwrap(), hour: caps.get(4).unwrap().as_str().parse().unwrap(), minute: caps.get(5).unwrap().as_str().parse().unwrap(), action: parse_action(caps.get(6).unwrap().as_str()) } } fn argmax(v: &[T]) -> Option { if v.len() == 0 { None } else { let mut maxat = 0; for i in 1..v.len() { if v[i] > v[maxat] { maxat = i; } } Some(maxat) } } pub fn main(reader: T) -> io::Result<(String, String)> { let mut records: Vec = reader.lines().map(|l| parse_line(&l.unwrap())).collect(); records.sort_unstable(); let mut guards = HashMap::new(); { let mut current_id = 0; let mut sleep_start = 0; for record in records.iter() { match record.action { Action::Begin(id) => { if let None = guards.get(&id) { guards.insert(id, Guard {id: id, sleep_times: Vec::new(), asleep: [0; 60]}); } current_id = id; }, Action::Sleep => sleep_start = record.minute, Action::Wake => guards.get_mut(¤t_id).unwrap() .sleep_times.push((sleep_start, record.minute)) } } } let mut max_sleep = -1; let mut max_sleep_at = -1; let mut max_times = -1; let mut max_times_at = -1; for mut guard in guards.values_mut() { let mut sleep = 0; let mut times = 0; for (from, to) in guard.sleep_times.iter() { for i in *from..*to { guard.asleep[i as usize] += 1; times = max(times, guard.asleep[i as usize]); } sleep += to - from; } if sleep > max_sleep { max_sleep = sleep; max_sleep_at = guard.id; } if times > max_times { max_times = times; max_times_at = guard.id; } } let sleepy_guard = guards.get(&max_sleep_at).unwrap(); let max_minute = argmax(&sleepy_guard.asleep).unwrap() as i32; let part1 = max_minute * sleepy_guard.id; let consistent_guard = guards.get(&max_times_at).unwrap(); let max_minute = argmax(&consistent_guard.asleep).unwrap() as i32; let part2 = max_minute * consistent_guard.id; Ok((part1.to_string(), part2.to_string())) }