My advent of code solutions
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

153 lines
3.9 KiB

"""
Advent of Code 2021 - Day 08
Run with:
python puzzles/day08.py inputs/day08.txt
"""
import pathlib
import sys
from collections import defaultdict
from typing import List, Tuple
class Display:
"""
0 (6) 1 (2*) 2 (5) 3 (5) 4 (4*)
aaaa .... aaaa aaaa ....
b c . c . c . c b c
b c . c . c . c b c
.... .... dddd dddd dddd
e f . f e . . f . f
e f . f e . . f . f
gggg .... gggg gggg ....
5 (5) 6 (6) 7 (3*) 8 (7*) 9 (6)
aaaa aaaa aaaa aaaa aaaa
b . b . . c b c b c
b . b . . c b c b c
dddd dddd .... dddd dddd
. f e f . f e f . f
. f e f . f e f . f
gggg gggg .... gggg gggg
"""
def __init__(self, entries: List[str]):
self.entries = self._parse(entries)
def decode(self):
results = []
for entry in self.entries:
cipher = self._generate_cipher(entry["signals"])
decrypt = self._decrypt(cipher, entry["outputs"])
results.append(decrypt)
return sum(results)
def unique_count(self):
unique = 0
for entry in self.entries:
unique += self._get_unique(entry)
return unique
@staticmethod
def _decrypt(cipher, enc_string):
output = ""
for code in enc_string:
output += str(cipher["".join(sorted(code))])
return int(output)
@staticmethod
def _generate_cipher(entry):
codes = {} # Length: Actual Number
filtered = defaultdict(list)
for signal in entry:
filtered[len(signal)].append(set(signal))
codes[1] = filtered[2][0]
codes[4] = filtered[4][0]
codes[7] = filtered[3][0]
codes[8] = filtered[7][0]
for code in filtered[5]:
if len(code.union(codes[1])) == 5:
codes[3] = code
elif len(code.union(codes[4])) == 7:
codes[2] = code
else:
codes[5] = code
for code in filtered[6]:
if len(code.union(codes[7])) == 7:
codes[6] = code
elif len(code.union(codes[5])) == 6:
codes[9] = code
else:
codes[0] = code
# Let's reformat the results so we can reference by string
results = {"".join(sorted(code)): value for value, code in codes.items()}
return results
@staticmethod
def _get_unique(entries):
unique = 0
for entry in entries["outputs"]:
length = len(entry)
unique += length in [2, 4, 3, 7] # 1,4,7,8
return unique
@staticmethod
def _parse(lines):
entries = []
for line in lines:
split = line.split()
entries.append({
"signals": list(split[0:10]),
"outputs": list(split[11:]),
})
return entries
def part1(inputs: List[int]) -> int:
d = Display(inputs)
return d.unique_count()
def part2(inputs: List[int]) -> int:
d = Display(inputs)
return d.decode()
def parse(inputs: str) -> List[int]:
"""Parse the input string"""
return [line for line in inputs.split("\n")]
def solve(path: str) -> Tuple[int, int]:
"""Solve the puzzle"""
puzzle_input = parse(pathlib.Path(path).read_text().strip())
part1_result = part1(puzzle_input)
part2_result = part2(puzzle_input)
return part1_result, part2_result
def main() -> None:
for path in sys.argv[1:]:
print(f"Input File: {path}")
part1_result, part2_result = solve(path)
print(f"Part 1 Result: {part1_result}")
print(f"Part 2 Result: {part2_result}")
if __name__ == "__main__":
main()