Skip to content

Commit e5c9389

Browse files
committed
2018 day 4
1 parent fdf793f commit e5c9389

File tree

4 files changed

+145
-0
lines changed

4 files changed

+145
-0
lines changed

crates/utils/src/input.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ impl InputError {
6969

7070
(line_number, column_number, line.to_string())
7171
}
72+
73+
/// Returns the source error.
74+
#[must_use]
75+
pub fn into_source(self) -> Box<dyn Error> {
76+
self.source
77+
}
7278
}
7379

7480
impl Display for InputError {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[1518-11-01 00:00] Guard #10 begins shift
2+
[1518-11-01 00:05] falls asleep
3+
[1518-11-01 00:25] wakes up
4+
[1518-11-01 00:30] falls asleep
5+
[1518-11-01 00:55] wakes up
6+
[1518-11-01 23:58] Guard #99 begins shift
7+
[1518-11-02 00:40] falls asleep
8+
[1518-11-02 00:50] wakes up
9+
[1518-11-03 00:05] Guard #10 begins shift
10+
[1518-11-03 00:24] falls asleep
11+
[1518-11-03 00:29] wakes up
12+
[1518-11-04 00:02] Guard #99 begins shift
13+
[1518-11-04 00:36] falls asleep
14+
[1518-11-04 00:46] wakes up
15+
[1518-11-05 00:03] Guard #99 begins shift
16+
[1518-11-05 00:45] falls asleep
17+
[1518-11-05 00:55] wakes up

crates/year2018/src/day04.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use std::collections::HashMap;
2+
use utils::prelude::*;
3+
4+
/// Analysing guard sleep schedules.
5+
#[derive(Clone, Debug)]
6+
pub struct Day04 {
7+
guards: Vec<Guard>,
8+
}
9+
10+
#[derive(Clone, Debug)]
11+
struct Guard {
12+
id: u32,
13+
nights: Vec<u64>,
14+
most_frequent_minute: u32,
15+
most_frequent_count: u32,
16+
}
17+
18+
#[derive(Debug)]
19+
enum Event {
20+
BeginsShift(u32),
21+
FallsAsleep,
22+
WakesUp,
23+
}
24+
25+
impl Day04 {
26+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
27+
let mut lines: Vec<&str> = input.lines().collect();
28+
lines.sort_unstable();
29+
30+
let mut current_guard_idx = None;
31+
let mut guard_indexes = HashMap::new();
32+
let mut guards = Vec::new();
33+
for line in lines {
34+
let (_, _, _, min, event) = parser::number_range(1u32..=12)
35+
.with_prefix("[1518-")
36+
.with_suffix(b'-')
37+
.then(parser::number_range(1u32..=31).with_suffix(b' '))
38+
.then(parser::number_range(0u32..=23).with_suffix(b':'))
39+
.then(parser::number_range(0u32..=59).with_suffix("] "))
40+
.then(parser::one_of((
41+
parser::u32()
42+
.with_prefix("Guard #")
43+
.with_suffix(" begins shift")
44+
.map(Event::BeginsShift),
45+
"falls asleep".map(|_| Event::FallsAsleep),
46+
"wakes up".map(|_| Event::WakesUp),
47+
)))
48+
.parse_complete(line)
49+
.map_err(|e| InputError::new(input, line, e.into_source()))?;
50+
51+
if let Event::BeginsShift(id) = event {
52+
let guard_idx = *guard_indexes.entry(id).or_insert_with(|| {
53+
let idx = guards.len();
54+
guards.push(Guard {
55+
id,
56+
nights: Vec::with_capacity(16),
57+
most_frequent_count: 0,
58+
most_frequent_minute: 0,
59+
});
60+
idx
61+
});
62+
guards[guard_idx].nights.push(0);
63+
current_guard_idx = Some(guard_idx);
64+
continue;
65+
}
66+
67+
let Some(idx) = current_guard_idx else {
68+
return Err(InputError::new(input, line, "invalid first event"));
69+
};
70+
71+
let night = guards[idx].nights.last_mut().unwrap();
72+
let mask = (1u64 << (60 - min)) - 1;
73+
if let Event::FallsAsleep = event {
74+
*night |= mask;
75+
} else {
76+
*night &= !mask;
77+
}
78+
}
79+
80+
if guards.is_empty() {
81+
return Err(InputError::new(input, 0, "expected at least one guard"));
82+
}
83+
84+
for guard in &mut guards {
85+
(guard.most_frequent_minute, guard.most_frequent_count) = (0..60)
86+
.map(|m| {
87+
(
88+
m,
89+
guard
90+
.nights
91+
.iter()
92+
.filter(|&&b| b & (1u64 << (59 - m)) != 0)
93+
.count() as u32,
94+
)
95+
})
96+
.max_by_key(|&(_, c)| c)
97+
.unwrap();
98+
}
99+
100+
Ok(Self { guards })
101+
}
102+
103+
#[must_use]
104+
pub fn part1(&self) -> u32 {
105+
self.select_guard(|g| g.nights.iter().map(|b| b.count_ones()).sum())
106+
}
107+
108+
#[must_use]
109+
pub fn part2(&self) -> u32 {
110+
self.select_guard(|g| g.most_frequent_count)
111+
}
112+
113+
fn select_guard(&self, key_fn: impl Fn(&&Guard) -> u32) -> u32 {
114+
let guard = self.guards.iter().max_by_key(key_fn).unwrap();
115+
guard.id * guard.most_frequent_minute
116+
}
117+
}
118+
119+
examples!(Day04 -> (u32, u32) [
120+
{file: "day04_example0.txt", part1: 240, part2: 4455},
121+
]);

crates/year2018/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ utils::year!(2018 => year2018, ${
55
1 => day01::Day01,
66
2 => day02::Day02,
77
3 => day03::Day03,
8+
4 => day04::Day04,
89
});

0 commit comments

Comments
 (0)