Powered by AppSignal & Oban Pro

--- Day 6: Trash Compactor ---

2025/day_6.livemd

— Day 6: Trash Compactor —

Mix.install([{:kino_aoc, "~> 0.1"}])

Setup

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2025", "6", System.fetch_env!("LB_AOC_SESSION_COOKIE"))
test_input = Kino.Input.textarea("test_input")
test_input = Kino.Input.read(test_input)
defmodule TrashCompactor do
  def parse_homework(input) do
    {nums_strings, [ops_string]} = split_nums_ops(input)

    nums =
      nums_strings
      |> Enum.map(fn nums_string ->
        nums_string
        |> String.split(" ", trim: true)
        |> Enum.map(&String.to_integer/1)
        |> Enum.with_index(&{&2, &1})
        |> Map.new()
      end)

    {nums, ops_map(ops_string)}
  end

  def split_nums_ops(input) do
    input
    |> String.split("\n")
    |> Enum.split_with(fn
      "*" <> _ -> false
      "+" <> _ -> false
      _ -> true
    end)
  end

  def ops_map(ops_string) do
    ops_string |> String.split(" ", trim: true) |> Enum.with_index(&amp;{&amp;2, &amp;1})
  end

  def do_op("*", nums), do: Enum.product(nums)
  def do_op("+", nums), do: Enum.sum(nums)
end

Part 1

import TrashCompactor

# {nums, ops} = parse_homework(test_input)
{nums, ops} = parse_homework(puzzle_input)

Enum.reduce(ops, 0, fn {col_index, op}, acc ->
  variables = for row <- nums, do: row[col_index]
  acc + do_op(op, variables)
end)

Part 2

import TrashCompactor

# {nums_strings, [ops_string]} = split_nums_ops(test_input)
{nums_strings, [ops_string]} = split_nums_ops(puzzle_input)
column_separator = String.duplicate(" ", length(nums_strings))
row_length = (nums_strings |> Enum.at(0) |> String.length()) - 1
ops = ops_map(ops_string)

vertical_number_map =
  Enum.reduce(0..row_length, %{0 => []}, fn i, acc ->
    vertical_num_string =
      for row <- nums_strings, reduce: "" do
        new_string -> new_string <> binary_slice(row, i..i)
      end

    # all spaces with no digits means new column
    if vertical_num_string == column_separator do
      Map.put(acc, map_size(acc), [])
    else
      vertical_num = vertical_num_string |> String.trim() |> String.to_integer()
      Map.update!(acc, map_size(acc) - 1, &amp;[vertical_num | &amp;1])
    end
  end)

Enum.sum_by(ops, fn {col_index, op} -> do_op(op, vertical_number_map[col_index]) end)