83 lines
2 KiB
Python
83 lines
2 KiB
Python
import re
|
|
|
|
# PART 1
|
|
|
|
ROOM_RE = r"(.*)-(\d+)\[(.{5})\]"
|
|
|
|
|
|
def load_rooms(inputstr):
|
|
rooms = []
|
|
for line in inputstr.splitlines():
|
|
match = re.fullmatch(ROOM_RE, line)
|
|
name, sector, checksum = match.groups()
|
|
name = name.split("-")
|
|
sector = int(sector)
|
|
rooms.append((name, sector, checksum))
|
|
return rooms
|
|
|
|
|
|
def checksum(name):
|
|
name = "".join(name)
|
|
freqs = {}
|
|
for char in name:
|
|
freqs[char] = freqs.get(char, 0) + 1
|
|
|
|
top = freqs.items()
|
|
top = sorted(top, key=lambda x: x[0])
|
|
top = sorted(top, key=lambda x: x[1], reverse=True)
|
|
top = list(top)[:5]
|
|
top = map(lambda x: x[0], top)
|
|
return "".join(top)
|
|
|
|
|
|
def sum_correct_sectors(rooms):
|
|
total = 0
|
|
for name, sector, chk in rooms:
|
|
if checksum(name) == chk:
|
|
total += sector
|
|
return total
|
|
|
|
|
|
# PART 2
|
|
|
|
|
|
def shift(s):
|
|
new_s = []
|
|
for c in s:
|
|
if ord("a") <= ord(c) <= ord("z"):
|
|
new_c = chr(
|
|
ord("a") + ((ord(c) - ord("a") + 1) % (ord("z") - ord("a") + 1))
|
|
)
|
|
new_s.append(new_c)
|
|
elif ord("A") <= ord(c) <= ord("Z"):
|
|
new_c = chr(
|
|
ord("A") + ((ord(c) - ord("A") + 1) % (ord("Z") - ord("A") + 1))
|
|
)
|
|
new_s.append(new_c)
|
|
else:
|
|
new_s.append("?")
|
|
return "".join(new_s)
|
|
|
|
|
|
def decrypt_name(name, sector):
|
|
for _ in range(sector % 26):
|
|
name = map(shift, name)
|
|
return " ".join(name)
|
|
|
|
|
|
def decrypt_names(rooms, filename):
|
|
with open(filename, "w") as f:
|
|
for name, sector, chk in rooms:
|
|
if checksum(name) == chk:
|
|
name = decrypt_name(name, sector)
|
|
line = f"{name}-{sector}[{chk}]\n"
|
|
f.write(line)
|
|
|
|
|
|
def solve(inputstr):
|
|
rooms = load_rooms(inputstr)
|
|
total = sum_correct_sectors(rooms)
|
|
print(f"Part 1: {total}")
|
|
# filename_2 = inputstr + ".decrypted"
|
|
# decrypt_names(rooms, filename_2)
|
|
# print(f"Part 2: see {filename_2} (search for 'northpole object storage')")
|