This repository has been archived on 2018-12-05. You can view files and clone it, but cannot push or open issues or pull requests.
aoc2018/4/guard.py

119 lines
3.8 KiB
Python
Raw Permalink Normal View History

2018-12-04 21:24:11 +00:00
#!/usr/bin/env python3
import collections
import datetime
import re
import sys
class Event:
def __init__(self, date, event):
m = re.match('(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}) (?P<hour>\d{2}):(?P<minute>\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<id>\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<date>\d{4}-\d{2}-\d{2} \d{2}:\d{2})\] (?P<event>.*)')
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)