Sean McLemon | Advent of Code

2021-12-04 - Giant Squid

(original .ipynb)

Day 4 puzzle input is a sequence of comma-separated numbers representing the order that bingo balls are drawn, followed by a number of bingo cards (mine is here). Part 1 involves playing through the bingo game and finding the first card to have a complete row or column. Part 2 involves finding the very last one.

test_input_str = """7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1

22 13 17 11  0
8  2 23  4 24
21  9 14 16  7
6 10  3 18  5
1 12 20 15 19

3 15  0  2 22
9 18 13 17  5
19  8  7 25 23
20 11 10 24  4
14 21 16 12  6

14 21 17 24  4
10 16 15  9 19
18  8 23 26 20
22 11 13  6  5
2  0 12  3  7"""

def parse_card(block):
card = []
for line in block.split("\n"):
card.append(line.split())
return card

def parse_input(input_str):
blocks = [block for block in input_str.split("\n\n")]
numbers = [n for n in blocks.split(",")]
cards = [parse_card(card) for card in blocks[1:]]
return (numbers, cards)

def is_winner(card):
# check horizontals
for line in card:
all_true = True
for v in line:
all_true = all_true and v == None
if all_true:
return True

# check verticals - there's a neater way to do this but meh
for c in range(len(card)):
all_true = True
for r in range(len(card[c])):
all_true = all_true and card[r][c] == None
if all_true:
return True

return False

def update_card(card, number):
for r, row in enumerate(card):
for c, col in enumerate(row):
if col == number:
card[r][c] = None
return

def score(card, drawn_number):
card_total = 0
for row in card:
for col in row:
if col != None:
card_total += int(col)

return int(drawn_number) * card_total

def nth_bingo_score(numbers, cards, n):
winners = set()
for number in numbers:
for i, card in enumerate(cards):
if i in winners:
continue
update_card(card, number)
if is_winner(card):
if n == len(winners):
return score(card, number)

raise Exception("No winners")

def part_one(input_str):
numbers, cards = parse_input(input_str)
return nth_bingo_score(numbers, cards, 1)

assert 4512 == part_one(test_input_str)
print("part one:", part_one(puzzle_input_str))
part one: 71708
def part_two(input_str):
numbers, cards = parse_input(input_str)
return nth_bingo_score(numbers, cards, len(cards))

assert 1924 == part_two(test_input_str)
print("part two:", part_two(puzzle_input_str))
part two: 34726