from copy import deepcopy from helpers import Helper helper = Helper(debug=True) load_input = helper.load_input debug = helper.debug class Card: """ A single scratch-off card for AOC 2023 day 4. """ def __init__(self, input_line): card_id, numbers = input_line.split(": ") winning, have = numbers.split(" | ") self.idnum = int(card_id.split()[1]) self.winning = [int(n) for n in winning.split()] self.have = [int(n) for n in have.split()] @property def num_winners(self) -> int: winners = 0 for number in self.have: if number in self.winning: winners += 1 return winners @property def score(self) -> int: return 2**(self.num_winners-1) if self.num_winners > 0 else 0 def main(): lines = load_input(4) cards = [] for line in lines: cards.append(Card(input_line=line)) # For every matching number #M (that's ordinal, not the actual matching number) # on card N, I get a copy of card N+M. So if card 1 has three matching numbers, # I get copies of cards 2 (1+1), 3 (1+2), and 4 (1+3). # Don't process this iteratively; you will quickly overwhelm the interpreter. # You don't actually need a new copy of each card. You just need to know # how many copies of each card you have. cards_dicts = [] for card in cards: # Each card has a count of how many of it we have cards_dicts.append({"card": card, "count": 1}) for i, card in enumerate(cards_dicts): # NOT the score, that way lies madness and IndexErrors winning_nums = card["card"].num_winners current_add = 1 while winning_nums > 0: # Each copy of the current card adds 1 count to each target card cards_dicts[i + current_add]["count"] += card["count"] winning_nums -= 1 current_add += 1 print(f"Total cards: {sum([v['count'] for v in cards_dicts])}") if __name__ == "__main__": main()