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
113
114
115
116
117
118
119
120
121
|
from collections import Counter
from copy import copy
from dataclasses import dataclass
from typing import Iterator, List, Optional, Tuple, Callable
from aoc import BaseAssignment
def bold(item: str, condition: Callable[[], bool]):
return f'\033[36m{item}\033[0m' if condition() else item
@dataclass
class Number:
nr: int
marked: bool = False
def __int__(self):
return self.nr
def __bool__(self):
return self.marked
def __radd__(self, other):
return other + int(self)
def mark(self):
self.marked = True
@dataclass
class BingoCard:
card: List[List[Number]]
@property
def bingo(self) -> bool:
return any([
*[all(bool(item) for item in row) for row in self.card],
*[all(bool(row[col_index]) for row in self.card) for col_index in range(5)]
])
def mark(self, nr: int):
for row in self.card:
for item in row:
if int(item) == nr:
item.mark()
@property
def unmarked(self):
return [
item
for row in self.card
for item in row
if not bool(item)
]
def __str__(self):
return '\n'.join([
''.join([
bold(str(int(item)).rjust(2, ' ').ljust(3, ' '), lambda: item.marked)
for item in row
])
for row in self.card
])
class Assignment(BaseAssignment):
def read_input(self, example = False) -> Tuple[List[int], List[BingoCard]]:
cards = []
card = None
input = super().read_input(example)
nrs = [ int(n) for n in next(input).split(',') ]
try:
row = next(input)
while True:
if row == '':
if card is not None:
cards.append(BingoCard(card=card))
card = []
else:
card.append([ Number(nr=int(item)) for item in row.split(' ') if item != ''])
row = next(input)
except StopIteration:
if card is not None:
cards.append(BingoCard(card=card))
return nrs, cards
class AssignmentOne(Assignment):
example_result = 4512
def run(self, input: Tuple[List[int], List[BingoCard]]) -> int:
nrs, cards = input
for nr in nrs:
for card in cards:
card.mark(nr)
if card.bingo:
return nr * sum(card.unmarked)
class AssignmentTwo(Assignment):
example_result = 1924
def run(self, input: Tuple[List[int], List[BingoCard]]) -> int:
nrs, cards = input
in_game = copy(cards)
for nr in nrs:
for card in copy(in_game):
card.mark(nr)
if card.bingo:
in_game.remove(card)
if len(in_game) == 0:
return nr * sum(card.unmarked)
|