Solution to http://adventofcode.com/2016/day/4
#!/usr/bin/env python3 | |
# Solution to http://adventofcode.com/2016/day/4 part 1 | |
# Mark Jenkins <mark@markjenkins.ca> | |
from sys import stdin | |
from collections import Counter | |
from itertools import islice | |
CHECKSUM_SIZE = 5 | |
def parse_room(line): | |
parts = line.split("-") | |
sector_id_and_checksum = parts[-1].split("[") | |
return ( | |
''.join(c for c in parts[:-1] if c!="-"), # name letters without "-" | |
int(sector_id_and_checksum[0]), # sector id | |
sector_id_and_checksum[1][0:CHECKSUM_SIZE] # checksum | |
) | |
def checksum(name): | |
counts = Counter(name) | |
# make a sorted iterable of the counts and letters, | |
# use reverse=True to get the counts in descending order | |
# | |
# to take full advantage of sorted, we reverse the ordering of the | |
# alphabet by converting to integer and subtracting from 'z' | |
# so that the use of reverse=True doesn't give us z-a, but instead a-z | |
sorted_count_let_num = sorted( | |
( (count, ord('z') - ord(let) ) | |
for let, count in counts.items()), | |
reverse=True) | |
# construct a string using the first CHECKSUM_SIZE entries | |
return ''.join( | |
chr(ord('z') - da_let) # fix the letter reversing and convert back | |
for da_count, da_let in islice(sorted_count_let_num, | |
0, CHECKSUM_SIZE) # islice | |
) # join | |
def valid_room(name, checksum_in): | |
return checksum(name)==checksum_in | |
print( sum( sector_id | |
for name, sector_id, checksum in (parse_room(line) | |
for line in stdin ) | |
if valid_room(name, checksum) | |
) # sum | |
#!/usr/bin/env python3 | |
# Solution to http://adventofcode.com/2016/day/4 part 2 | |
# Mark Jenkins <mark@markjenkins.ca> | |
from sys import stdin | |
from collections import Counter | |
from itertools import islice | |
CHECKSUM_SIZE = 5 | |
def parse_room(line): | |
parts = line.split("-") | |
sector_id_and_checksum = parts[-1].split("[") | |
return ( | |
parts[:-1], # name in parts | |
int(sector_id_and_checksum[0]), # sector id | |
sector_id_and_checksum[1][0:CHECKSUM_SIZE] # checksum | |
) | |
def checksum(name): | |
counts = Counter(name) | |
# make a sorted iterable of the counts and letters, | |
# use reverse=True to get the counts in descending order | |
# | |
# to take full advantage of sorted, we reverse the ordering of the | |
# alphabet by converting to integer and subtracting 'z' | |
# so that the use of reverse=True doesn't give us z-a, but instead a-z | |
sorted_count_let_num = sorted( | |
( (count, ord('z') - ord(let) ) | |
for let, count in counts.items()), | |
reverse=True) | |
# construct a string using the first CHECKSUM_SIZE entries | |
return ''.join( | |
chr(ord('z') - da_let) # fix the letter reversing and convert back | |
for da_count, da_let in islice(sorted_count_let_num, | |
0, CHECKSUM_SIZE) # islice | |
) # join | |
def valid_room(name, checksum_in): | |
return checksum(''.join(name)) ==checksum_in | |
def decrypt_letter(c, key): | |
return chr( | |
( (ord(c) - ord('a') + key) % 26 ) + | |
ord('a') | |
) # chr | |
def decrypt_room(name, sector_id): | |
return ' '.join( ''.join( decrypt_letter(c, sector_id) for c in name_part ) | |
for name_part in name ) | |
print( '\n'.join( "%s %s" % (decrypt_room(name, sector_id), sector_id) | |
for name, sector_id, checksum in (parse_room(line) | |
for line in stdin ) | |
if valid_room(name, checksum) | |
) # join | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment