2018: day04: part 1
This commit is contained in:
parent
cef2fba255
commit
9278a5472a
1017
aoc2018/input/day04.txt
Normal file
1017
aoc2018/input/day04.txt
Normal file
File diff suppressed because it is too large
Load diff
216
aoc2018/src/day04.rs
Normal file
216
aoc2018/src/day04.rs
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use super::err;
|
||||||
|
use super::Result;
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../input/day04.txt");
|
||||||
|
|
||||||
|
fn sorted_lines(input: &str) -> String {
|
||||||
|
let mut lines: Vec<_> = input.lines().collect();
|
||||||
|
lines.sort_unstable();
|
||||||
|
lines.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run() -> Result<()> {
|
||||||
|
println!("part 1: {}", part1(&sorted_lines(INPUT))?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Event {
|
||||||
|
ShiftChange(u64),
|
||||||
|
FallAsleep,
|
||||||
|
WakeUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Event {
|
||||||
|
type Err = Box<dyn Error>;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
|
if s.find("wakes up").is_some() {
|
||||||
|
Ok(Event::WakeUp)
|
||||||
|
} else if s.find("falls asleep").is_some() {
|
||||||
|
Ok(Event::FallAsleep)
|
||||||
|
} else if s.find("begins shift").is_some() {
|
||||||
|
let pound = s.find('#').ok_or_else(|| err!("`#` not found"))?;
|
||||||
|
let s = &s[(pound + 1)..];
|
||||||
|
let space = s.find(' ').ok_or_else(|| err!("` ` not found after `#`"))?;
|
||||||
|
let id = s[..space].parse()?;
|
||||||
|
Ok(Event::ShiftChange(id))
|
||||||
|
} else {
|
||||||
|
Err(err!("unknown event type"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Date {
|
||||||
|
year: u32,
|
||||||
|
month: u8,
|
||||||
|
day: u8,
|
||||||
|
|
||||||
|
hour: u8,
|
||||||
|
minute: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Date {
|
||||||
|
type Err = Box<dyn Error>;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
|
let lbracket = s.find('[').ok_or_else(|| err!("`[` not found"))?;
|
||||||
|
let s = &s[(lbracket + 1)..];
|
||||||
|
let dash = s.find('-').ok_or_else(|| err!("`-` not found"))?;
|
||||||
|
|
||||||
|
let year = s[..dash].parse()?;
|
||||||
|
let s = &s[(dash + 1)..];
|
||||||
|
let dash = s.find('-').ok_or_else(|| err!("`-` not found"))?;
|
||||||
|
|
||||||
|
let month = s[..dash].parse()?;
|
||||||
|
let s = &s[(dash + 1)..];
|
||||||
|
let space = s.find(' ').ok_or_else(|| err!("` ` not found"))?;
|
||||||
|
|
||||||
|
let day = s[..space].parse()?;
|
||||||
|
let s = &s[(space + 1)..];
|
||||||
|
let colon = s.find(':').ok_or_else(|| err!("`:` not found"))?;
|
||||||
|
|
||||||
|
let hour = s[..colon].parse()?;
|
||||||
|
let s = &s[(colon + 1)..];
|
||||||
|
let rbracket = s.find(']').ok_or_else(|| err!("`]` not found"))?;
|
||||||
|
|
||||||
|
let minute = s[..rbracket].parse()?;
|
||||||
|
|
||||||
|
Ok(Date {
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
day,
|
||||||
|
hour,
|
||||||
|
minute,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct LogEntry {
|
||||||
|
date: Date,
|
||||||
|
event: Event,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for LogEntry {
|
||||||
|
type Err = Box<dyn Error>;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
|
let date: Date = s.parse().map_err(|e| err!("couldn't parse date: {}", e))?;
|
||||||
|
let event = s.parse().map_err(|e| err!("couldn't parse event: {}", e))?;
|
||||||
|
|
||||||
|
let entry = LogEntry { date, event };
|
||||||
|
|
||||||
|
match entry.event {
|
||||||
|
Event::FallAsleep | Event::WakeUp => {
|
||||||
|
assert!(entry.date.hour == 0);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> Result<u64> {
|
||||||
|
let mut guard_id = None;
|
||||||
|
let mut map: HashMap<u64, Vec<LogEntry>> = HashMap::new();
|
||||||
|
|
||||||
|
for line in input.lines() {
|
||||||
|
let log_entry: LogEntry = line.parse()?;
|
||||||
|
|
||||||
|
if let Event::ShiftChange(id) = log_entry.event {
|
||||||
|
guard_id = Some(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
match guard_id {
|
||||||
|
Some(id) => map.entry(id).or_default().push(log_entry),
|
||||||
|
None => return Err(err!("event before first shift")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill frequency by minute and by guard
|
||||||
|
let mut sleep_freq_per_guard = HashMap::new();
|
||||||
|
|
||||||
|
for (id, log_entries) in map {
|
||||||
|
let mut fell_asleep = None;
|
||||||
|
let mut sleep_freq: HashMap<u8, u64> = HashMap::new();
|
||||||
|
|
||||||
|
for e in log_entries {
|
||||||
|
match e.event {
|
||||||
|
Event::ShiftChange(_) => fell_asleep = None, // new day!
|
||||||
|
Event::FallAsleep => fell_asleep = Some(e.date.minute),
|
||||||
|
Event::WakeUp => match fell_asleep {
|
||||||
|
Some(asleep) => {
|
||||||
|
let awake = e.date.minute;
|
||||||
|
for m in asleep..awake {
|
||||||
|
*sleep_freq.entry(m).or_default() += 1;
|
||||||
|
}
|
||||||
|
fell_asleep = None;
|
||||||
|
}
|
||||||
|
None => return Err(err!("woke up before falling asleep")),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fell_asleep.is_some() {
|
||||||
|
return Err(err!("fell asleep but never woke up!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep_freq_per_guard.insert(id, sleep_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (heavy_sleeper, _) = sleep_freq_per_guard
|
||||||
|
.iter()
|
||||||
|
.max_by_key(|(_, freqs)| freqs.values().sum::<u64>())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let heavy_sleeper_freq = &sleep_freq_per_guard[heavy_sleeper];
|
||||||
|
|
||||||
|
let (best_minute, _) = heavy_sleeper_freq
|
||||||
|
.iter()
|
||||||
|
.max_by_key(|(_, freq)| *freq)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok((*best_minute as u64) * heavy_sleeper)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const PROVIDED: &str = "[1518-11-01 00:00] Guard #10 begins shift
|
||||||
|
[1518-11-01 00:05] falls asleep
|
||||||
|
[1518-11-01 00:25] wakes up
|
||||||
|
[1518-11-01 00:30] falls asleep
|
||||||
|
[1518-11-01 00:55] wakes up
|
||||||
|
[1518-11-01 23:58] Guard #99 begins shift
|
||||||
|
[1518-11-02 00:40] falls asleep
|
||||||
|
[1518-11-02 00:50] wakes up
|
||||||
|
[1518-11-03 00:05] Guard #10 begins shift
|
||||||
|
[1518-11-03 00:24] falls asleep
|
||||||
|
[1518-11-03 00:29] wakes up
|
||||||
|
[1518-11-04 00:02] Guard #99 begins shift
|
||||||
|
[1518-11-04 00:36] falls asleep
|
||||||
|
[1518-11-04 00:46] wakes up
|
||||||
|
[1518-11-05 00:03] Guard #99 begins shift
|
||||||
|
[1518-11-05 00:45] falls asleep
|
||||||
|
[1518-11-05 00:55] wakes up
|
||||||
|
";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_provided() {
|
||||||
|
assert_eq!(part1(PROVIDED).unwrap(), 240);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_real() {
|
||||||
|
assert_eq!(part1(&sorted_lines(INPUT)).unwrap(), 142515);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod day01;
|
pub mod day01;
|
||||||
pub mod day02;
|
pub mod day02;
|
||||||
pub mod day03;
|
pub mod day03;
|
||||||
|
pub mod day04;
|
||||||
pub mod day05;
|
pub mod day05;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
|
@ -3,12 +3,13 @@ use std::env;
|
||||||
use aoc2018::day01;
|
use aoc2018::day01;
|
||||||
use aoc2018::day02;
|
use aoc2018::day02;
|
||||||
use aoc2018::day03;
|
use aoc2018::day03;
|
||||||
|
use aoc2018::day04;
|
||||||
use aoc2018::day05;
|
use aoc2018::day05;
|
||||||
|
|
||||||
use aoc2018::Result;
|
use aoc2018::Result;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let days: &[fn() -> Result<()>] = &[day01::run, day02::run, day03::run, day05::run];
|
let days: &[fn() -> Result<()>] = &[day01::run, day02::run, day03::run, day04::run, day05::run];
|
||||||
|
|
||||||
let mut args = env::args();
|
let mut args = env::args();
|
||||||
args.next();
|
args.next();
|
||||||
|
|
Loading…
Reference in a new issue