···11import fileinput
22from collections import Counter, defaultdict
3344-from utils import parse_line
44+from utils import parse_nums
556677# Read problem input
88-EVENTS = []
99-for line in fileinput.input():
1010- data = parse_line(r'\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (.+)', line)
1111- EVENTS.append(data)
1212-1313-EVENTS.sort()
88+EVENTS = sorted(parse_nums(line, negatives=False) for line in fileinput.input())
1491510# Process events
1611SHIFTS = Counter()
1712GUARDS = defaultdict(Counter)
1813curr_id = None
1919-sleep = None
1414+sleep_min = None
20152121-for year, month, date, hour, minute, action in EVENTS:
2222- if 'begins' in action:
2323- curr_id = int(action.split()[1][1:])
1616+for record in EVENTS:
1717+ if len(record) == 6: # shift begins
1818+ curr_id = int(record[-1])
24192525- elif 'asleep' in action:
2626- sleep = hour, minute
2020+ elif sleep_min is None: # falls asleep
2121+ sleep_min = record[-1]
27222828- elif 'wakes' in action:
2929- h, m = sleep
3030- SHIFTS[curr_id] += ((hour - h) % 24) * 60 + (minute - m)
3131- sleep = None
2323+ else: # wakes up
2424+ minute = record[-1]
2525+ SHIFTS[curr_id] += minute - sleep_min
2626+ for m in range(sleep_min, minute):
2727+ GUARDS[curr_id][m] += 1
32283333- for x in range(h * 60 + m, hour * 60 + minute):
3434- GUARDS[curr_id][x % 60] += 1
2929+ sleep_min = None
35303631# Compute Part 1 answer
3732guard_id = SHIFTS.most_common(1)[0][0]
···3934print "Strategy 1 checksum:", guard_id * minute
40354136# Compute Part 2 answer
4242-max_cnt = 0
4343-max_min = 0
4444-max_id = 0
4545-4646-for guard_id, minutes in GUARDS.items():
4747- minute, count = minutes.most_common(1)[0]
4848- if count > max_cnt:
4949- max_cnt = count
5050- max_min = minute
5151- max_id = guard_id
5252-5353-print "Strategy 2 checksum:", max_id * max_min
3737+guard_id, (minute, _) = max(((i, c.most_common(1)[0]) for i, c in GUARDS.items()), key=lambda x: x[1][1])
3838+print "Strategy 2 checksum:", guard_id * minute
+3-2
2018/utils.py
···2121 return ret
222223232424-def parse_nums(line):
2525- return [int(n) for n in re.findall(r'-?\d+', line)]
2424+def parse_nums(line, negatives=True):
2525+ num_re = r'-?\d+' if negatives else r'\d+'
2626+ return [int(n) for n in re.findall(num_re, line)]
262727282829def new_table(val, width, height):