blob: 5f15a8d8d7b57698a7a04689f3ae64d21ef47b0f (
plain)
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
|
from utils import open_day
class Board:
cells: list[int | None]
width: int
height: int
col_hits: list[int]
row_hits: list[int]
has_bingo: bool
unmarked_sum: int
def __init__(self, cells: list[list[int]]):
self.width = len(cells[0])
self.height = len(cells)
self.col_hits = [0 for _ in range(self.width)]
self.row_hits = [0 for _ in range(self.height)]
self.unmarked_sum = 0
self.cells = []
for row in cells:
for cell in row:
self.unmarked_sum += cell
self.cells.append(cell)
self.has_bingo = False
def check_bingo(self):
self.has_bingo = (
any(hits == self.height for hits in self.col_hits) or
any(hits == self.width for hits in self.row_hits)
)
def call(self, num: int):
for y in range(self.height):
for x in range(self.width):
cell = self.cells[x + self.width * y]
if cell == num:
self.col_hits[x] += 1
self.row_hits[y] += 1
self.unmarked_sum -= cell
self.check_bingo()
return
@staticmethod
def from_string(s: str) -> 'Board':
return Board([[int(n) for n in l.split()] for l in s.split('\n')])
def solve(nums: list[int], boards: list[Board]) -> tuple[int, int]:
won: set[int] = set()
wins: list[int] = []
num: int
for num in nums:
i: int
board: Board
for i, board in enumerate(boards):
if i in won: continue
board.call(num)
if board.has_bingo:
won.add(i)
wins.append(num * board.unmarked_sum)
return wins[0], wins[-1]
nums: str | list[int]
boards: list[str] | list[Board]
nums, *boards = open_day(4).read().rstrip().split('\n\n')
nums = list(map(int, nums.split(',')))
boards = [Board.from_string(b) for b in boards]
part1, part2 = solve(nums, boards)
print(part1)
print(part2)
|