Advent of Code 2025; Day 6: Trash Compactor

Helping some cephalopods with their maths homework after falling into a garbage chute.

Part 1: Cephalopod Homework

After helping the elves in the cafeteria, I was taking a break and helping them re-enact a classic movie scene when I over-enthusiastically jumped into the garbage chute. Not my finest moment.

I find myself in a sealed trash compactor with some cephalopods who can apparently help me open the door - but first, they need help with their maths homework. I suppose I’m not in a position to argue.

Their worksheet is laid out rather unusually with numbers stacked vertically and operators at the bottom of each problem:

1
2
3
4
123 328  51 64 
 45 64  387 23 
  6 98  215 314
*   +   *   +  

Each column of numbers with an operator at the bottom is a separate problem. Reading left to right: 123 * 45 * 6 = 33210, then 328 + 64 + 98 = 490, then 51 * 387 * 215 = 4243455, and finally 64 + 23 + 314 = 401. The worksheet answer is the sum of all individual problem answers: 4277556.

I’m told that the whitespace can be ignored, which seems a little suspicious - will have to see what part 2 holds for me there. There’s a few ways I could look at this, I tend to like parsing input into meaningful data but sometimes that comes at the cost of additional work / processing.

Keeping things from getting too complicated, I have opted to just parse each column of values into lists of ints. Then I have separately parsed the operator row into a list - since each column has a corresponding operator these indexes will correlate perfectly.

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def load_worksheet(input_data: str) -> tuple[list[list[int]], list[str]]:
    lines = input_data.strip().splitlines()

    numbers: list[list[int]] = []
    ops: list[str] = []

    for line in lines:
        line = line.strip().split()
        if not line[0].isdigit():
            ops = line
            break
        numbers.append([int(i) for i in line])

    return (numbers, ops)

To process this I’ve got a few choices again, I could go through each column and calculate it’s result; alternatively I could process each row of numbers and incrementally process each column. Either way I feel they are fairly equivalent in terms of cost. I’ve opted to go row-by-row; using the first row as initial values and applying subsequent rows with the appropriate operator:

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def part1(input_data: str) -> int:
    numbers, ops = load_worksheet(input_data)
    answers = numbers[0]
    for row in numbers[1:]:
        for i, n in enumerate(row):
            if ops[i] == "+":
                answers[i] += n
            elif ops[i] == "*":
                answers[i] *= n

    return sum(answers)

Starting with answers = numbers[0] gives me the first row’s values. Then for each subsequent row, I apply the column’s operator to accumulate the result. Summing the final answers list gives me the worksheet total.

The cephalopods seem satisfied. Now about that door…

Part 2: Cephalopod Homework Correction

Ah. The cephalopods have just informed me that I was reading the worksheet wrong. They read right-to-left and their numbers are written vertically in columns, not horizontally. Each column of digits, read top-to-bottom, forms a single number.

Looking at the same worksheet again:

1
2
3
4
123 328  51 64
 45 64  387 23
  6 98  215 314
*   +   *   +

Reading the rightmost character columns (right-to-left), we find individual digits stacked vertically. The first is just 4 as there are no other digits in that column. The next is 4 from 64, 3 from 23, and 1 from 314 in one column form the number 431. The operator in that column’s bottom row tells us what to do - but if it’s a space we keep collecting the numbers that are part of each “problem”.

So reading right-to-left: first we encounter 4 (a column with just one digit), then 431, then 623, and finally hit the + operator. That means we sum all collected numbers: 4 + 431 + 623 = 1058. Then we continue collecting for the next problem until we hit another operator.

This requires a completely different parsing approach. After a bit of thought, I think actually I’m better off not parsing too much - it’s because of how important the whitespace is on these inputs.

It also isn’t actually necessary to read right-to-left to solve this problem, as all of the mathematical operations are commutative. However, reading it that way presents an opportunity because the input appears to be formatted to favour it: each operator signals the end of a problem boundary!

There’s probably a way I could convince python to read these values in as matrices too - then it becomes a simple transpose to get the int values from columns. I’ve got another idea that should work though.

The trick is zip(*map(reversed, numbers)) - it looks a little crazy but it’s using some nice python features:

  • reversed on each line reads characters right-to-left
  • map applies the reversed function to each line
  • zip(*) iterates all the rows at once (the * expands the iterable map which contains the reversed iterables of each line) - effectively transposing a column of input into a tuple / row
  • Combined, I iterate through character columns in right-to-left order
python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def solve_worksheet_rtlc(numbers: list[str]):
    problem: list[int] = []
    for col in zip(*map(reversed, numbers)):
        nstr = ''.join(col[:-1]).strip()
        if not nstr.isdigit():
            continue

        problem.append(int(nstr))
        operator = col[-1]

        if operator != " ":
            if operator == "+":
                yield sum(problem)
            elif operator == "*":
                yield math.prod(problem)

            problem.clear()

This is quite different from Part 1. For each character column:

  • col[:-1] gives all characters except the last (the operator)
  • Join those characters and strip whitespace to form the number (whitespace can be ignored safely now)
  • col[-1] is the operator character from the bottom row
  • If the operator is a space, keep collecting numbers into the problem list
  • When I hit + or *, apply it to all collected numbers and yield the result

Using yield creates a generator - each time we complete a problem, I yield its result. This pairs nicely with the calling code:

python
1
2
3
def part2(input_data: str) -> int:
    lines = input_data.splitlines()
    return sum(solve_worksheet_rtlc(lines))

I’ll confess this one took me a moment to wrap my head around. The shift from reading whole numbers horizontally to reading digits vertically took a bit of a rethink. Reading right-to-left helped my implementation though - it meant the operator naturally marked the end of each problem.

As always, full code is available at github.com/lordmoocow/aoc25.


Today was more about parsing and understanding the problem than algorithmic complexity. Once I understood what the cephalopods actually wanted, the implementation was fairly straightforward. Half way now, six days to go!