Day 4 - Advent of Code 2016

Working solutions for the day 4 puzzles.

Part One

""" day_04_01.py """

# usage: python3 day_04_01.py < input

import re


def make_checksum(text):
    """ calculate text checksum per puzzle description """
    counts = {}
    t = text.replace('-', '')
    while t:
        letter = t[0]
        freq = t.count(letter)
        letters = counts.get(freq, [])
        letters.append(letter)
        counts[freq] = sorted(letters)
        t = t.replace(letter, '')

    sequence = []
    for f in sorted(counts.keys(), reverse=True):
        sequence.extend(counts[f])
    return ''.join(sequence[:5])


name = re.compile(r'([^0-9]*)-[0-9]*\[')
sector = re.compile(r'[^0-9]*-([0-9]*)\[')
checksum = re.compile(r'\[([a-z]*)\]')

total = 0
while True:
    try:
        room = input()
    except EOFError:
        break
    name_value = name.findall(room)[0]
    if make_checksum(name_value) == checksum.findall(room)[0]:
        sector_value = int(sector.findall(room)[0])
        total += sector_value

print(total)

Part Two

""" day_04_02.py """

# usage: python3 day_04_02.py < input

import re


def make_checksum(text):
    """ calculate text checksum per puzzle description """
    counts = {}
    t = text.replace('-', '')
    while t:
        letter = t[0]
        freq = t.count(letter)
        letters = counts.get(freq, [])
        letters.append(letter)
        counts[freq] = sorted(letters)
        t = t.replace(letter, '')

    sequence = []
    for f in sorted(counts.keys(), reverse=True):
        sequence.extend(counts[f])
    return ''.join(sequence[:5])


def decrypt(text, shift):
    """ calculate cleartext per puzzle description """
    a = ord('a')
    letters = [chr((ord(char) - a + shift) % 26 + a) if char != '-' else ' '
               for char in text]
    return ''.join(letters)


name = re.compile(r'([^0-9]*)-[0-9]*\[')
sector = re.compile(r'[^0-9]*-([0-9]*)\[')
checksum = re.compile(r'\[([a-z]*)\]')

while True:
    try:
        room = input()
    except EOFError:
        break
    name_value = name.findall(room)[0]
    if make_checksum(name_value) == checksum.findall(room)[0]:
        sector_value = int(sector.findall(room)[0])
        if 'north' in decrypt(name_value, sector_value):
            print(sector_value)
            break