1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
from collections import Counter
from copy import copy
from typing import List, Tuple, Dict, FrozenSet
from aoc import BaseAssignment
class UnknownException(Exception):
pass
Item = FrozenSet[str]
Information = Tuple[List[Item], List[Item]]
class Assignment(BaseAssignment):
def parse_item(self, item: str) -> Tuple[List[Item], List[Item]]:
input, output = item.split('|')
return (
[frozenset(i.strip()) for i in input.split(' ') if i != ''],
[frozenset(i.strip()) for i in output.split(' ') if i != '']
)
def read_input(self, example = False) -> List[Tuple[List[str], List[str]]]:
return list(super().read_input(example))
@staticmethod
def calc_digit(item: Item, known_numbers: Dict[int, Item] = None) -> int:
if known_numbers is None:
known_numbers = {}
match len(item):
case 2:
return 1
case 3:
return 7
case 4:
return 4
case 5:
if 1 in known_numbers and item.issuperset(known_numbers[1]):
return 3
elif 4 in known_numbers and len(item | known_numbers[4]) == 7:
return 2
else:
return 5
case 6:
if 1 in known_numbers and not item.issuperset(known_numbers[1]):
return 6
elif 3 in known_numbers and item.issuperset(known_numbers[3]):
return 9
else:
return 0
case 7:
return 8
case _:
raise UnknownException()
@staticmethod
def unique_filter(item: Item) -> bool:
try:
return Assignment.calc_digit(item) in [1, 4, 7, 8]
except UnknownException:
return False
class AssignmentOne(Assignment):
example_result = 26
def run(self, input: List[Information]) -> int:
return sum([
len(list(filter(Assignment.unique_filter, output)))
for _, output in input
])
class AssignmentTwo(Assignment):
example_result = 61229
@staticmethod
def find_all_numbers(items: List[Item]) -> Dict[int, Item]:
known_numbers = {
Assignment.calc_digit(item): item
for item in filter(Assignment.unique_filter, items)
}
unknown_numbers = {
item
for item
in filter(
lambda item: item not in known_numbers.values(),
items
)
}
while len(unknown_numbers) > 0:
for number in copy(unknown_numbers):
try:
nr = Assignment.calc_digit(number, known_numbers)
known_numbers[nr] = number
unknown_numbers.remove(number)
except UnknownException:
continue
return known_numbers
def run(self, input: List[Information]) -> int:
return sum([
sum(
self.calc_digit(item, self.find_all_numbers(input + output))
* (10 ** (len(output) - index - 1))
for index, item in enumerate(output)
)
for input, output in input
])
|