81 lines
2.0 KiB
Python
81 lines
2.0 KiB
Python
from collections.abc import Iterable
|
|
from pathlib import Path
|
|
|
|
|
|
class Card:
|
|
num: int
|
|
winning: set[int]
|
|
picks: set[int]
|
|
|
|
def __init__(self, num: int, winning: set[int], picks: set[int]) -> None:
|
|
self.num = num
|
|
self.winning = winning
|
|
self.picks = picks
|
|
self.won = 0
|
|
|
|
def matching(self) -> int:
|
|
return len(self.winning & self.picks)
|
|
|
|
def score(self) -> int:
|
|
return int(2**(self.matching()-1))
|
|
|
|
def cards_won(self) -> Iterable[int]:
|
|
# print(f"Card {self.num} wins cards {[self.num + x + 1 for x in range(self.matching())]}")
|
|
for x in range(self.matching()):
|
|
# print(f"Card {self.num} wins card {self.num + x + 1}")
|
|
yield self.num + x + 1
|
|
|
|
|
|
def parse_line(line: str) -> Card:
|
|
card_str, _, nums = line.partition(":")
|
|
card_num = int(card_str.partition(" ")[2])
|
|
|
|
winning_str, _, picks_str = nums.partition("|")
|
|
winning = {int(n.strip()) for n in winning_str.split(" ") if n}
|
|
picks = {int(n.strip()) for n in picks_str.split(" ") if n.strip()}
|
|
|
|
return Card(card_num, winning, picks)
|
|
|
|
|
|
def part1(input: Path) -> int:
|
|
total = 0
|
|
with input.open() as f:
|
|
for line in f:
|
|
card = parse_line(line)
|
|
score = card.score()
|
|
# print(f"Card {card.num} is worth {score} points")
|
|
total += score
|
|
|
|
return total
|
|
|
|
|
|
def play(cards: list[Card], card_num: int):
|
|
card = cards[card_num - 1]
|
|
card.won += 1
|
|
for won in card.cards_won():
|
|
play(cards, won)
|
|
|
|
|
|
def part2(input: Path) -> int:
|
|
cards: list[Card] = []
|
|
with input.open() as f:
|
|
cards = [parse_line(line) for line in f]
|
|
|
|
for card in range(len(cards)):
|
|
play(cards, card + 1)
|
|
|
|
total = 0
|
|
for card in cards:
|
|
# print(f"Card {card.num} was won {card.won} times")
|
|
total += card.won
|
|
|
|
return total
|
|
|
|
|
|
if __name__ == "__main__":
|
|
result1 = part1(Path("input.txt"))
|
|
print("part 1", result1)
|
|
|
|
result2 = part2(Path("input.txt"))
|
|
print("part 2", result2)
|