Advent of Code: Day 4

Author: Leo Nguyen Dec 4, 2021

A giant squid appears.

No, really. On Day 4, a giant squid appears and wants to play Bingo with you. This time, there are several Bingo boards and you're given a list of numbers that will be drawn (cheating!). So your goal is to find out which board will win first. Thankfully, with technology's help, this matter shouldn't be too difficult.

def read(filename):
    file = open(filename)
    numbers = file.readline().split(',')
    lines = file.read().splitlines()

    rows = [line.split() for line in lines if line]
    boards = []

    while len(rows):
        boards.append(rows[:5])
        rows = rows[5:]

    return numbers, boards


def fill_board(board, number):
    for i in range(5):
        for j in range(5):
            if board[i][j] == number:
                board[i][j] = None


def board_wins(board):
    # Check rows
    for i in range(5):
        win = True
        for j in range(5):
            if board[i][j] is not None:
                win = False
                break
        if win:
            return True

    # Check columns
    for j in range(5):
        win = True
        for i in range(5):
            if board[i][j] is not None:
                win = False
                break
        if win:
            return True

    return False


def solve(numbers, boards):
    for number in numbers:
        for board in boards:
            fill_board(board, number)

            if board_wins(board):
                summary = sum([sum([int(number) for number in row if number is not None]) for row in board])
                print(summary * int(number))
                return


numbers, boards = read('input.txt')
solve(numbers, boards)

In Part 2, turns out some in your crew apparently watched Squid Game, and they don't want to anger the squid for fear of bad things happening. So they want you to help it win. And this time we will try to determine which board will win last.

def read(filename):
    file = open(filename)
    numbers = file.readline().split(',')
    lines = file.read().splitlines()

    rows = [line.split() for line in lines if line]
    boards = []

    while len(rows):
        boards.append(rows[:5])
        rows = rows[5:]

    return numbers, boards


def fill_board(board, number):
    for i in range(5):
        for j in range(5):
            if board[i][j] == number:
                board[i][j] = None


def board_wins(board):
    if board[0][0] == '-1':
        return False

    # Check rows
    for i in range(5):
        win = True
        for j in range(5):
            if board[i][j] is not None:
                win = False
                break
        if win:
            return True

    # Check columns
    for j in range(5):
        win = True
        for i in range(5):
            if board[i][j] is not None:
                win = False
                break
        if win:
            return True

    return False


# Mark board removed by filling first number with '-1'
def remove_board(board):
    board[0][0] = '-1'


def solve(numbers, boards):
    boards_won = 0

    for number in numbers:
        for board in boards:
            fill_board(board, number)

            if board_wins(board):
                boards_won += 1

                if boards_won == len(boards):
                    summary = sum([sum([int(number) for number in row if number is not None]) for row in board])
                    print(summary * int(number))
                    return

                # Remove this board from boards
                remove_board(board)


numbers, boards = read('input.txt')
solve(numbers, boards)

Takeaways

Surprisingly, this game has provided me with some clarity on programming and how to optimize for this kind of competition. Specifically, here are the rules I set for myself in future days of Advent of Code:

  • Variables will contain data that match their names and descriptions.

  • Use functions. As a newcomer to Python, I tend to do what beginners do: write everything in one block from top to bottom. As it turns out, learning and using a more procedural style make all this more manageable and effective.

  • Take in strides. This means no longer frantically try to code as fast as I can. I made this mistake in Day 3, which made my coding experience worse and actually prolonged the time to solution. This time, with all experience equipped so far, I will read the problem carefully, take leisure in mapping out the solution, and code in professional business method, not code golf.

If you're reading this and want to join us, there's still time. If you've beaten Day 4, congratulations and thanks for the companionship.