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.
 

105 lines
2.7 KiB

"""
Advent of Code 2021 - Day 04
Run with:
python puzzles/day04.py inputs/day04.txt
"""
import pathlib
import sys
from typing import Dict, List, Tuple
import numpy as np
class Bingo:
boards = None
draws = None
def __init__(self, inputs: str) -> None:
inputs = inputs.split("\n\n")
# Convert all values to int
self.draws = list(map(int, inputs.pop(0).split(",")))
self.boards = np.array(
[
[list(map(int, value.split())) for value in line.split("\n")]
for line in inputs
],
dtype=object,
)
def solve(self, squid_rules: bool = False) -> int:
game = self.boards.copy()
winning_scores = []
for draw in self._draw():
game[game == draw] = np.nan
for index, board in enumerate(game):
if self._is_solved(board):
winning_scores.append(self._calculate_score(board, draw))
if not squid_rules:
return winning_scores[0]
try:
game = np.delete(game, index, axis=0)
except IndexError: # I don't understand why this is needed
# Need to rework the whole class
# Wrong way to go about this
pass
if len(winning_scores) == np.size(self.boards, axis=0):
break
index = -1 if squid_rules else 0
return winning_scores[index]
def _draw(self) -> int:
for draw in self.draws:
yield draw
@staticmethod
def _calculate_score(solved_board, last_draw: int) -> int:
board_score = np.nansum(solved_board)
return board_score * last_draw
@staticmethod
def _is_solved(board) -> bool:
# Solved if any row or column is 0
cols = np.nansum(board, axis=0)
rows = np.nansum(board, axis=1)
return (np.count_nonzero(cols) != cols.size or np.count_nonzero(rows) != rows.size)
def part1(inputs: str) -> int:
game = Bingo(inputs)
return game.solve()
def part2(inputs: str) -> int:
game = Bingo(inputs)
return game.solve(squid_rules=True)
def solve(path: str) -> Tuple[int, int]:
"""Solve the puzzle"""
inputs = pathlib.Path(path).read_text().strip()
part1_result = part1(inputs)
part2_result = part2(inputs)
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()