2018-12-04 - Repose Record
(original .ipynb)
import re
from collections import defaultdict
from datetime import datetime
from enum import Enum
puzzle_input_lines = open("puzzle_input/day4.txt").readlines()
test_input_lines = """[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""".split("\n")
# patterns because we are gonna abuse the 're' module
raw_input_line = "^\[(....)-(..)-(..) (..):(..)\]\s+(.+)"
begins_shift = "^Guard #(\d+) begins shift$"
falls_asleep = "^falls asleep$"
wakes_up = "^wakes up$"
class GuardEvent(Enum):
WAKES_UP = 0
FALLS_ASLEEP = 1
BEGINS_SHIFT = 2
def parse_line(line, guard):
parsed = re.search(raw_input_line, line)
assert(len(parsed.groups()) == 6)
year = int(parsed.group(1))
month = int(parsed.group(2))
day = int(parsed.group(3))
hour = int(parsed.group(4))
minute = int(parsed.group(5))
event_timestamp = datetime(year, month, day, hour, minute)
event = parsed.group(6)
begin_shift_match = re.search(begins_shift, event)
falls_asleep_match = re.search(falls_asleep, event)
wakes_up_match = re.search(wakes_up, event)
if begin_shift_match:
assert(len(begin_shift_match.groups()) == 1)
return (event_timestamp, GuardEvent.BEGINS_SHIFT, int(begin_shift_match.group(1)))
elif falls_asleep_match:
return (event_timestamp, GuardEvent.FALLS_ASLEEP, guard)
elif wakes_up_match:
return (event_timestamp, GuardEvent.WAKES_UP, guard)
raise Exception("unknown event")
def log_sleep(guard_sleep_mins, guard, from_time, to_time):
time_slept = from_time - to_time
current_minute = from_time.minute
while current_minute < to_time.minute:
guard_sleep_mins[guard][current_minute] += 1
current_minute += 1
def sleepiest_guard(guard_sleep_mins):
max_sleep_guard = None
max_sleep_mins = 0
for guard in guard_sleep_mins:
sleep_mins = sum(guard_sleep_mins[guard])
if sleep_mins > max_sleep_mins:
max_sleep_mins = sleep_mins
max_sleep_guard = guard
return max_sleep_guard
def guard_sleepiest_minute(sleep_mins):
sleepiest_minute = -1
sleepiest_minute_times = 0
for minute, times_asleep in enumerate(sleep_mins):
if times_asleep > sleepiest_minute_times:
sleepiest_minute = minute
sleepiest_minute_times = times_asleep
return sleepiest_minute
def build_sleepy_lookup(input_lines):
asleep = False
current_guard = None
current_timestamp = None
guard_sleep_mins = defaultdict(lambda: [0] * 60)
for line in sorted(input_lines):
event_timestamp, event, event_guard = parse_line(line, current_guard)
#print(event_guard)
if event == GuardEvent.BEGINS_SHIFT:
if asleep:
log_sleep(guard_sleep_mins, current_guard, current_timestamp, event_timestamp)
elif event == GuardEvent.FALLS_ASLEEP:
asleep = True
elif event == GuardEvent.WAKES_UP:
asleep = False
log_sleep(guard_sleep_mins, current_guard, current_timestamp, event_timestamp)
current_guard = event_guard
current_timestamp = event_timestamp
return guard_sleep_mins
def part_one(input_lines):
guard_sleep_mins = build_sleepy_lookup(input_lines)
guard = sleepiest_guard(guard_sleep_mins)
sleepiest_minute = guard_sleepiest_minute(guard_sleep_mins[guard])
return guard * sleepiest_minute
assert 240 == part_one(test_input_lines)
print("part one:", part_one(puzzle_input_lines))
part one: 35623
def part_two(input_lines):
guard_sleep_mins = build_sleepy_db(input_lines)
max_times = 0
max_minute = -1
max_guard = None
for guard in guard_sleep_mins:
for minute, time_asleep in enumerate(guard_sleep_mins[guard]):
if time_asleep > max_times:
max_minute = minute
max_times = time_asleep
max_guard = guard
return max_guard * max_minute
print("part two:", part_two(puzzle_input_lines))
part two: 23037