Skip to content

Advent of Code 2025 Day 6: Trash Compactor

"""Advent of Code 2025: Day 6 - Trash Compactor"""

from advent import parse, atoms, operator, reduce, compose, Generator


def apply(op_sym: str, args: list[int]) -> int:
    """Apply an operator to a list of arguments. For example, apply('+', [1,2,3]) returns 6."""
    return reduce({'+': operator.add, '*': operator.mul}[op_sym], args)


def part1() -> int:
    """
    1. Parse the input into rows
    2. Transpose rows to columns using zip(*rows)
    3. Sum the result of applying the operator to the args for each column"""
    return sum([apply(col[-1], col[:-1]) for col in zip(*parse(6, atoms))])


def part2() -> int:
    """
    1. Transform our input so columns become rows after reversing each line, and
    forming the transpose. Then filter out any rows containing only spaces:
    [[ '1', '2', '3', ' ', ' ', '6' ],     [[ '6', '8', ' '],
     [ '4', '5', ' ', ' ', '7', '8' ], -->  [ ' ', '7', '*'], 68 * 7
     [ '+', ' ', ' ', ' ', '*', ' ' ]]      [ '3', ' ', ' '],
                                            [ '2', '5', ' '],
                                            [ '1', '4', '+']] 3 + 25 + 14
    2. Return the sum of all answers generated by our helper function.
    """
    rows = filter(
        lambda row: ''.join(row).strip(),
        zip(*parse(6, compose(reversed, list), do_rstrip=False)),
    )

    def answers(rows, args: list[int] = []) -> Generator[int, None, None]:
        """Accumulate an int argument from each row, until a row ends with an operator, then apply
        the operator to the accumulated args, yield the answer, clear the arg list, and repeat."""
        for row in rows:
            args.append(int(''.join(row[:-1]).strip()))

            if row[-1] in ['+', '*']:
                yield apply(row[-1], args)
                args = []

    return sum(answers(rows))


assert part1() == 3525371263915
assert part2() == 6846480843636

Day 6

Input Parsing

Parsing is a big part of today's puzzles! Consider our sample input:

123 328  51 64 
 45 64  387 23 
  6 98  215 314
*   +   *   +  

For part 1, I'd like to have the following structure:

[ ( 123,  45,   6, '*' ),
  ( 328,  64,  98, '+' ),
  (  51, 387, 215, '*' ),
  (  64,  23, 314, '+' ) ]

This is accomplished by transposing the matrix with : zip(*parse(6, atoms))

For part 2, I'd like to have the following structure:

[ (   4, 431, 623, '+' ),
  ( 175, 581,  32, '*' ),
  (   8, 248, 369, '+' ),
  ( 356,  24,   1, '*' ) ]

But I'll settle for the following :)

[ (' ', ' ', '4', ' '), 
  ('4', '3', '1', ' '), 
  ('6', '2', '3', '+'), 
  (' ', ' ', ' ', ' '), 
  ('1', '7', '5', ' '), 
  ('5', '8', '1', ' '), 
  (' ', '3', '2', '*'), 
  (' ', ' ', ' ', ' '), 
  ('8', ' ', ' ', ' '), 
  ('2', '4', '8', ' '), 
  ('3', '6', '9', '+'), 
  (' ', ' ', ' ', ' '), 
  ('3', '5', '6', ' '), 
  ('2', '4', ' ', ' '), 
  ('1', ' ', ' ', '*') ]

This is accomplished by transposing the matrix, after we reverse the rows, with: zip(*parse(6, compose(reversed, list), do_rstrip=False)) I needed to add a do_rstrip argument to my parse function because by default it strips spaces from the end of the file, and that removes crucial ending spaces!

Solution

For part 1, given the structure provided by our parsing, I just need to evaluate each tuple in the list by applying the operator (the last element) to the arguments (all but the last element), and sum all the results together.

For part 2, I have a little more work to do still. First, filter out the tuples containing only spaces, since they're meaningless now. I created a generator helper function to yield all the answers we need to sum up. For each row, it converts the tuple of digit strings into an integer, and accumulates them in a list. If the tuple ends in an operator, we apply the operator to the accumulated args, yield the answer, clear the arg list, and repeat until we're done.

End