advent-of-code/2018-python/solutions/day_04.py

68 lines
2.8 KiB
Python
Raw Normal View History

2021-11-01 16:40:46 +01:00
import heapq
import itertools
import re
from collections import defaultdict
from datetime import datetime, timezone
from solutions import BaseSolution
class Solution(BaseSolution):
input_file = '04.in'
def __str__(self):
return 'Day 4: Repose Record'
def solve(self, puzzle_input):
data = self._parse_and_group_data(puzzle_input)
timelines = self._get_guard_timelines(data)
sorted_timelines = sorted(timelines, key=lambda kv: sum([len(r) for r in kv[1]]), reverse=True)
guard_id, rows = sorted_timelines[0]
most_common_minute, _count = self._get_most_common_minute(rows)
return guard_id * most_common_minute
def solve_again(self, puzzle_input):
data = self._parse_and_group_data(puzzle_input)
timelines = self._get_guard_timelines(data)
hiscores = [(guard_id, *self._get_most_common_minute(rows)) for guard_id, rows in timelines]
guard_id, most_common_minute, _count = heapq.nlargest(1, hiscores, key=lambda hs: hs[2])[0]
return guard_id * most_common_minute
def _parse_and_group_data(self, data):
shift_sep = re.compile(r'\[.+\] Guard #\d+ begins shift')
sorted_data = '\n'.join(sorted(data.splitlines()))
entry_heads = shift_sep.findall(sorted_data)
entry_tails = shift_sep.split(sorted_data)[1:]
return list(map(lambda s: '\n'.join(map(str.strip, s)), zip(entry_heads, entry_tails)))
def _get_guard_timelines(self, data):
id_pattern = re.compile(r'Guard #(\d+)')
asleep_pattern = re.compile(r'\[(.+)\] f.*\n\[(.+)\] w', re.MULTILINE)
time_format = '%Y-%m-%d %H:%M'
rem = 60 * 60 * 24
timeline = defaultdict(list)
for entry in data:
guard_id = int(id_pattern.search(entry).groups()[0])
for felt_asleep, woke_up in asleep_pattern.findall(entry):
if guard_id not in timeline:
timeline[guard_id] = []
felt_asleep_dt = datetime.strptime(felt_asleep, time_format)
felt_asleep_ts = int(felt_asleep_dt.replace(tzinfo=timezone.utc).timestamp())
felt_asleep_ts = (felt_asleep_ts % rem) // 60
woke_up_dt = datetime.strptime(woke_up, time_format)
woke_up_ts = int(woke_up_dt.replace(tzinfo=timezone.utc).timestamp())
woke_up_ts = (woke_up_ts % rem) // 60
timeline[guard_id].append(range(felt_asleep_ts, woke_up_ts))
return timeline.items()
def _get_most_common_minute(self, rows):
minutes = defaultdict(int)
for m in itertools.chain(*rows):
minutes[m] += 1
return heapq.nlargest(1, minutes.items(), key=lambda kv: kv[1])[0]
if __name__ == '__main__':
solution = Solution()
solution.show_results()