3 minute read

❄️ Back to Advent of Code 2023 solutions homepage ❄️

# Imports
from aoc23.utils import read_input
import math
input_4 = read_input(4)
n_cards = len(input_4)

Part 1

In the first part of this puzzle, we are given a collection of scratchcards, with each card consisting of two sets of numbers: the first set (before the |) are the winning numbers, and the second set are the numbers on the scratchcard. We are tasked first with determining how many numbers from te scratchard are winning numbers, and computing the associated point score for the card. Here is an example of one of the lines from the input:

input_4[0]
'Card   1:  8 86 59 90 68 52 55 24 37 69 | 10 55  8 86  6 62 69 68 59 37 91 90 24 22 78 61 58 89 52 96 95 94 13 36 81'

Let’s process this input, turning each string into a pair of lists for each card:

def process_input_4(input_4: list[str]) -> list[tuple[list[int]]]:
    processed_input = []
    for line in input_4:
        numbers = line.split(':')[1]
        winning_numbers, my_numbers = numbers.split(' | ')
        winning_numbers = winning_numbers.split()
        my_numbers = my_numbers.split()
        processed_input.append((winning_numbers, my_numbers))
        
    return processed_input
processed_input = process_input_4(input_4)
print(processed_input[0])
(['8', '86', '59', '90', '68', '52', '55', '24', '37', '69'], ['10', '55', '8', '86', '6', '62', '69', '68', '59', '37', '91', '90', '24', '22', '78', '61', '58', '89', '52', '96', '95', '94', '13', '36', '81'])

This problem is clearly calling for us to use a hash map, to check the scratchcard numbers against the winning numbers: so, create a dictionary for each card with winning numbers as the keys, and check the inclusion of each of the scratchcard numbers in turn. The specific scoring method described in the problem can also be implemented here - 1 point for a matching number, doubled for every subsequent match:

def scratchcard_matches(winning_numbers: list[str], scratchcard_numbers: list[str]) -> int:
    hash_map = {n: 1 for n in winning_numbers}
    return len([n for n in scratchcard_numbers if n in hash_map])
def scratchcard_score(n_matches: int) -> int:
    if n_matches == 0:
        return 0
    else:
        return 2**(n_matches-1)
matches = [
    scratchcard_matches(winning_numbers, scratchcard_numbers)
    for winning_numbers, scratchcard_numbers in processed_input
]
sum([
    scratchcard_score(n_match)
    for n_match in matches
])
25651

So the answer to part 1 is: 25651.

Part 2

The scoring method from the previous section has been scrapped - instead, we have the following method of duplicating scratchcards:

Specifically, you win copies of the scratchcards below the winning card equal to the number of matches. So, if card 10 were to have 5 matching numbers, you would win one copy each of cards 11, 12, 13, 14, and 15. Copies of scratchcards are scored like normal scratchcards and have the same card number as the card they copied. So, if you win a copy of card 10 and it has 5 matching numbers, it would then win a copy of the same cards that the original card 10 won: cards 11, 12, 13, 14, and 15. This process repeats until none of the copies cause you to win any more cards. (Cards will never make you copy a card past the end of the table.)

From part 1, we still matches, a list of the number of matches found on each scratchcard. This function will convert this list of matches into a final card count:

def final_card_number(matches: list[int]) -> int:
    # Initialise the card numbers - 1 of each card:
    n_cards = len(matches)
    card_numbers = n_cards*[1]

    for i in range(n_cards):
        n_matches = matches[i]
        for j in range(n_matches):
            # Add card_numbers[i] new copies of the next n_matches cards
            # Check that we aren't going off the end of the cards too
            if i+1+j < n_cards:
                card_numbers[i+1+j] += card_numbers[i]
    
    return sum(card_numbers)
final_card_number(matches)
19499881

And so the part 2 answer is: 19499881.

This was a much more straightforward puzzle than yesterday - the code for processing the input was almost longer than the solutions themselves!

❄️ Back to Advent of Code 2023 solutions homepage ❄️

Tags:

Updated:

Comments