2018/04
This commit is contained in:
176
2018/04/src/main.rs
Normal file
176
2018/04/src/main.rs
Normal file
@@ -0,0 +1,176 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
use chrono::prelude::*;
|
||||
use regex::{Captures, Regex};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Entry {
|
||||
date: DateTime<Utc>,
|
||||
event: Event,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Event {
|
||||
BeginShift { guard_id: u16 },
|
||||
FallsAsleep,
|
||||
WakesUp,
|
||||
}
|
||||
|
||||
enum State {
|
||||
Default,
|
||||
Guard(u16),
|
||||
FallsAsleep(u16, DateTime<Utc>),
|
||||
}
|
||||
|
||||
fn date_from_captures(caps: &Captures<'_>) -> DateTime<Utc> {
|
||||
let year = caps
|
||||
.get(1)
|
||||
.expect("faild to find year")
|
||||
.as_str()
|
||||
.parse::<i32>()
|
||||
.expect("faild to parse year");
|
||||
|
||||
let month = caps
|
||||
.get(2)
|
||||
.expect("faild to find month")
|
||||
.as_str()
|
||||
.parse::<u32>()
|
||||
.expect("faild to parse month");
|
||||
|
||||
let day = caps
|
||||
.get(3)
|
||||
.expect("failed to find day")
|
||||
.as_str()
|
||||
.parse::<u32>()
|
||||
.expect("faild to parse day");
|
||||
|
||||
let hour = caps
|
||||
.get(4)
|
||||
.expect("faild to find hour")
|
||||
.as_str()
|
||||
.parse::<u32>()
|
||||
.expect("faild to parse hour");
|
||||
|
||||
let minute = caps
|
||||
.get(5)
|
||||
.expect("failed to find minute")
|
||||
.as_str()
|
||||
.parse::<u32>()
|
||||
.expect("faild to parse minute");
|
||||
|
||||
Utc.ymd(year, month, day).and_hms(hour, minute, 0)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let re_begin_shift =
|
||||
Regex::new(r"\[(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})\] Guard #(\d+) begins shift")
|
||||
.expect("failed to build regex");
|
||||
|
||||
let re_falls_asleep = Regex::new(r"\[(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})\] falls asleep")
|
||||
.expect("failed to build regex");
|
||||
|
||||
let re_wakes_up = Regex::new(r"\[(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})\] wakes up")
|
||||
.expect("failed to build regex");
|
||||
|
||||
let mut entries = io::stdin()
|
||||
.lock()
|
||||
.lines()
|
||||
.filter_map(Result::ok)
|
||||
.map(|line| {
|
||||
if let Some(caps) = re_begin_shift.captures(&line) {
|
||||
Entry {
|
||||
date: date_from_captures(&caps),
|
||||
event: Event::BeginShift {
|
||||
guard_id: caps
|
||||
.get(6)
|
||||
.expect("failed to find y")
|
||||
.as_str()
|
||||
.parse::<u16>()
|
||||
.expect("faild to parse y"),
|
||||
},
|
||||
}
|
||||
} else if let Some(caps) = re_falls_asleep.captures(&line) {
|
||||
Entry {
|
||||
date: date_from_captures(&caps),
|
||||
event: Event::FallsAsleep,
|
||||
}
|
||||
} else if let Some(caps) = re_wakes_up.captures(&line) {
|
||||
Entry {
|
||||
date: date_from_captures(&caps),
|
||||
event: Event::WakesUp,
|
||||
}
|
||||
} else {
|
||||
panic!("failed to parse line: {}", line);
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
entries.sort_by_key(|entry| entry.date);
|
||||
|
||||
let entries = entries;
|
||||
|
||||
let mut minute_asleep = HashMap::new();
|
||||
let mut minutes_asleep = HashMap::new();
|
||||
|
||||
let mut state = State::Default;
|
||||
|
||||
for entry in &entries {
|
||||
match (state, &entry.event) {
|
||||
// Default.
|
||||
(State::Default, Event::BeginShift { guard_id }) => {
|
||||
state = State::Guard(*guard_id);
|
||||
}
|
||||
(State::Default, _) => panic!("oh no"),
|
||||
|
||||
// Guard.
|
||||
(State::Guard(_), Event::BeginShift { guard_id }) => state = State::Guard(*guard_id),
|
||||
(State::Guard(guard_id), Event::FallsAsleep) => {
|
||||
state = State::FallsAsleep(guard_id, entry.date);
|
||||
}
|
||||
(State::Guard(_), _) => panic!("oh no"),
|
||||
|
||||
// FallsAsleep.
|
||||
(State::FallsAsleep(guard_id, date), Event::WakesUp) => {
|
||||
state = State::Guard(guard_id);
|
||||
|
||||
for m in date.minute()..entry.date.minute() {
|
||||
minute_asleep
|
||||
.entry((guard_id, m))
|
||||
.and_modify(|x| *x += 1)
|
||||
.or_insert(1);
|
||||
}
|
||||
|
||||
let duration = entry.date - date;
|
||||
|
||||
minutes_asleep
|
||||
.entry(guard_id)
|
||||
.and_modify(|x| *x += duration.num_seconds())
|
||||
.or_insert(0);
|
||||
}
|
||||
(State::FallsAsleep(_, _), _) => panic!("oh no"),
|
||||
}
|
||||
}
|
||||
|
||||
let (guard_id, minutes) = minutes_asleep
|
||||
.iter()
|
||||
.max_by_key(|(_, asleep)| *asleep)
|
||||
.expect("failed to find guard");
|
||||
|
||||
let (minute, _) = minute_asleep
|
||||
.iter()
|
||||
.filter(|((guard, _), _)| guard == guard_id)
|
||||
.map(|((_, minute), total)| (minute, total))
|
||||
.max_by_key(|(minute, total)| *total)
|
||||
.expect("failed to find minute");
|
||||
|
||||
println!("part.one={}", *guard_id as u32 * *minute);
|
||||
|
||||
let (guard_id, minute, _) = minute_asleep
|
||||
.iter()
|
||||
.map(|((guard, minute), total)| (guard, minute, total))
|
||||
.max_by_key(|(guard, minute, total)| *total)
|
||||
.expect("failed to find guard and minute");
|
||||
|
||||
println!("part.two={}", *guard_id as u32 * *minute);
|
||||
}
|
||||
Reference in New Issue
Block a user