diff options
-rw-r--r-- | 4.py | 68 |
1 files changed, 43 insertions, 25 deletions
@@ -1,21 +1,44 @@ from utils import open_day -from dataclasses import dataclass -@dataclass -class Cell: - num: int - marked: bool = False - -Board = list[list[Cell]] +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 bingo(board: Board) -> bool: - for row in board: - if all(cell.marked for cell in row): - return True - for x in range(len(board[0])): - if all(board[y][x].marked for y in range(len(board))): - return True - return False def solve(nums: list[int], boards: list[Board]) -> tuple[int, int]: won: set[int] = set() @@ -25,23 +48,18 @@ def solve(nums: list[int], boards: list[Board]) -> tuple[int, int]: i: int board: Board for i, board in enumerate(boards): - total = 0 - for row in board: - for cell in row: - if cell.num == num: - cell.marked = True - if not cell.marked: - total += cell.num - if i not in won and bingo(board): + if i in won: continue + board.call(num) + if board.has_bingo: won.add(i) - wins.append(num * total) + 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 = [[[Cell(int(n)) for n in l.split()] for l in b.split('\n')] for b in boards] +boards = [Board.from_string(b) for b in boards] part1, part2 = solve(nums, boards) print(part1) |