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