import shared
import re
from pprint import pprint

pattern = r"Card\s+(\d+): ([\d\s]+) \| ([\d\s]+)"


def load_cards(rows):
    cards = {}
    for row in rows:
        match = re.match(pattern, row)
        card_number = int(match.group(1))
        winning_numbers = set(list(map(int, match.group(2).split())))
        have_numbers = set(list(map(int, match.group(3).split())))
        have = winning_numbers.intersection(have_numbers)
        cards[card_number] = dict(
            winning_numbers=winning_numbers,
            have_numbers=have_numbers,
            have=have,
            have_count=len(have),
            points=0,
            refs=0,
        )
        if have:
            points = 1
            for _ in range(len(have) - 1):
                points *= 2
            cards[card_number]["points"] = points
    return cards


# @shared.profile
def part1(cards):
    print(sum(card["points"] for _, card in cards.items()))


# @shared.profile
def part2(cards):
    card_ids = list(range(len(cards) + 1))
    for card_id, card in cards.items():
        nn = [x + 1 + card_id for x in range(card["have_count"])]
        if not nn:
            continue

        # One point for initially having the card
        for idx in nn:
            cards[idx]["refs"] += 1
        # X more points for how many times this card is referenced
        for _ in range(card["refs"]):
            for idx in nn:
                cards[idx]["refs"] += 1
    # Sum the ref counts, and then add the total cards in
    print(sum(card["refs"] for _, card in cards.items()) + len(cards))


def main():
    rows = [row for row in shared.load_rows(4)]
    cards = load_cards(rows)
    with shared.elapsed_timer() as elapsed:
        part1(cards)
        print("🕒", elapsed())

    with shared.elapsed_timer() as elapsed:
        part2(cards)
        print("🕒", elapsed())


if __name__ == "__main__":
    main()
