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.
puzzle_input_str = open("puzzle_input/day4.txt").read()
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[0].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[0])):
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):
winners.add(i)
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