#!/usr/bin/env python3 import collections import datetime import re import sys class Event: def __init__(self, date, event): m = re.match('(?P\d{4})-(?P\d{2})-(?P\d{2}) (?P\d{2}):(?P\d{2})', date) self.date = datetime.datetime(int(m.group('year')), int(m.group('month')), int(m.group('day')), int(m.group('hour')), int(m.group('minute'))) self.event = event def __str__(self): return "[{}] {}".format(self.date, self.event) class Guard: def __init__(self, id): self.id = id self.midnight_sleep = collections.Counter() self.on_shift = False self.sleep = False def start_shift(self, date): self.on_shift = date def end_shift(self, date): self.on_shift = False if self.sleep: self.wake_up(date) def fall_asleep(self, date): self.sleep = date def wake_up(self, date): self.process_sleep(self.sleep, date) self.sleep = False def process_sleep(self, start, end): current_datetime = start # If the end is outside the start hour, clip it clip_end = datetime.datetime(start.year, start.month, start.day, start.hour + 1, 0) clip = False if clip_end < end: clip = True end = clip_end #print("Processing sleep for guard {} from {} to {} ({})".format( # self.id, start, end, clip)) #print(self.midnight_sleep) while current_datetime < end: if current_datetime.hour != 0: current_datetime += datetime.timedelta(minutes = 1) continue self.midnight_sleep.update({current_datetime.minute: 1}) current_datetime += datetime.timedelta(minutes = 1) #print(self.midnight_sleep) def total_sleep(self): return sum(self.midnight_sleep.values()) def common_minute(self): r = self.midnight_sleep.most_common(1) if not r: r = [(-1, -1)] return r def replay(events): guards = {} current_guard = None p = re.compile('Guard #(?P\d+) begins shift') for e in events: m = p.match(e.event) if m: if current_guard: current_guard.end_shift(e.date) # Guard is coming on shift if m.group('id') in guards.keys(): current_guard = guards[m.group('id')] else: current_guard = Guard(m.group('id')) guards[m.group('id')] = current_guard current_guard.start_shift(e.date) continue if e.event == 'falls asleep': current_guard.fall_asleep(e.date) if e.event == 'wakes up': current_guard.wake_up(e.date) return guards if __name__ == '__main__': lines = sys.stdin.readlines() p = re.compile('\[(?P\d{4}-\d{2}-\d{2} \d{2}:\d{2})\] (?P.*)') events = [] for line in lines: m = p.match(line) if not m: print("Warning line '{}' did not match".format(line)) else: events.append(Event(m.group('date'), m.group('event'))) events.sort(key=lambda e: e.date) guards = list(replay(events).values()) #print(guards) guards.sort(key=lambda g: g.total_sleep()) for g in guards: print("{}: {} minutes asleep, most common minute {}".format( g.id, g.total_sleep(), g.common_minute())) print('------------------------------------') guards.sort(key=lambda g: g.common_minute()[0][1] if g.common_minute() else 0) for g in guards: print("{}: {} minutes asleep, most common minute {}".format( g.id, g.total_sleep(), g.common_minute())) #print(guards[-1].id * guards[-1].common_minute()[0]) #for e in events: # print(e)