95 lines
2.2 KiB
Python
95 lines
2.2 KiB
Python
![]() |
#!/usr/bin/env python
|
||
|
from datetime import datetime
|
||
|
import re
|
||
|
|
||
|
RE_BEGIN = re.compile("^\[(.*)\] Guard #(\d+) begins shift$")
|
||
|
RE_SLEEP = re.compile("^\[(.*)\] falls asleep$")
|
||
|
RE_AWAKE = re.compile("^\[(.*)\] wakes up$")
|
||
|
|
||
|
guards = dict()
|
||
|
|
||
|
def read_input():
|
||
|
with open('input.txt', 'r') as f:
|
||
|
data = f.read().splitlines()
|
||
|
return sorted(data)
|
||
|
|
||
|
def convert_time(data):
|
||
|
return datetime.strptime(data, '%Y-%m-%d %H:%M')
|
||
|
|
||
|
def guard_stop_shift(guard, date):
|
||
|
guard_awake(guard, date)
|
||
|
|
||
|
def guard_start_shift(guard, date):
|
||
|
if guard is None:
|
||
|
return
|
||
|
if guard not in guards:
|
||
|
guards[guard] = {
|
||
|
'guard': guard,
|
||
|
'state': 'awake',
|
||
|
'min': [0]*60,
|
||
|
'sleep': 0,
|
||
|
'last_time': None
|
||
|
}
|
||
|
guard_awake(guard, date)
|
||
|
|
||
|
def guard_sleep(guard, date):
|
||
|
if guard is None:
|
||
|
return
|
||
|
guards[guard]['state'] = 'sleep'
|
||
|
guards[guard]['last_time'] = date
|
||
|
|
||
|
def guard_awake(guard, date):
|
||
|
if guard is None:
|
||
|
return
|
||
|
if guards[guard]['state'] in ['awake']:
|
||
|
guards[guard]['last_time'] = date
|
||
|
return
|
||
|
|
||
|
m = int((date - guards[guard]['last_time']).total_seconds() / 60)
|
||
|
m1 = guards[guard]['last_time'].minute
|
||
|
for x in range(m):
|
||
|
m2 = (x + m1) % 60
|
||
|
guards[guard]['min'][m2] += 1
|
||
|
guards[guard]['sleep'] += m
|
||
|
guards[guard]['state'] = 'awake'
|
||
|
guards[guard]['last_time'] = date
|
||
|
|
||
|
|
||
|
current_guard = None
|
||
|
for line in read_input():
|
||
|
m = RE_BEGIN.match(line)
|
||
|
if m:
|
||
|
d = convert_time(m.group(1))
|
||
|
guard_stop_shift(current_guard, d)
|
||
|
current_guard = (int)(m.group(2))
|
||
|
guard_start_shift(current_guard, d)
|
||
|
continue
|
||
|
|
||
|
m = RE_SLEEP.match(line)
|
||
|
if m:
|
||
|
d = convert_time(m.group(1))
|
||
|
guard_sleep(current_guard, d)
|
||
|
continue
|
||
|
|
||
|
m = RE_AWAKE.match(line)
|
||
|
if m:
|
||
|
d = convert_time(m.group(1))
|
||
|
guard_awake(current_guard, d)
|
||
|
continue
|
||
|
|
||
|
print(line)
|
||
|
raise Exception('unpasable line')
|
||
|
|
||
|
max_min = 0
|
||
|
max_guard = None
|
||
|
|
||
|
for g in guards.values():
|
||
|
m = max(g['min'])
|
||
|
if m > max_min:
|
||
|
max_guard = g
|
||
|
max_min = m
|
||
|
|
||
|
max_min_pos = [i for i, j in enumerate(max_guard['min']) if j == max_min]
|
||
|
|
||
|
print(max_guard['guard'] * max_min_pos[0])
|