Powered by AppSignal & Oban Pro

Advent of code day 10

2025/livebooks/day-10.livemd

Advent of code day 10

Mix.install([
  {:kino, "~> 0.5.0"}
])

Setup input

example = Kino.Input.textarea("Please paste your input example:")
input = Kino.Input.textarea("Please paste your real input:")
defmodule Combinations do
  def combinations(_, 0), do: [[]]
  def combinations([], _), do: []
  
  def combinations([h | t], r) do
    (for combo <- combinations(t, r - 1), do: [h | combo]) ++ combinations(t, r)
  end
end

Part 01

lines =
  example
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(fn line ->
    [target | rest] = String.split(line, " ", trim: true)
    [j | buttons] = Enum.reverse(rest)
    
    buttons =
      Enum.reverse(buttons)
      |> Enum.map(fn button ->
        button
        |> String.trim_leading("(")
        |> String.trim_trailing(")")
        |> String.split(",")
        |> Enum.map(&amp;String.to_integer/1)
        |> Enum.into(MapSet.new())
      end)
    
    target =
      target
      |> String.trim_leading("[")
      |> String.trim_trailing("]")
      |> String.split("", trim: true)
      |> Enum.with_index()
      |> Enum.filter(fn {v, _i} -> v == "#" end)
      |> Enum.map(fn {_, i} -> i end)
      |> Enum.into(MapSet.new())
    
    {target, buttons, j}
  end)

total =
  Enum.reduce(lines, 0, fn {target, buttons, _}, acc ->
    result = Enum.reduce_while(1..length(buttons), 0, fn count, _inner_acc ->
      found = Enum.reduce_while(Combinations.combinations(buttons, count), nil, fn attempt, _light ->
        lights = Enum.reduce(attempt, MapSet.new(), fn button, lights ->
          MapSet.symmetric_difference(lights, button)
        end)
        
        if MapSet.equal?(lights, target) do
          {:halt, count}
        else
          {:cont, nil}
        end
      end)
      
      if found != nil do
        {:halt, found}
      else
        {:cont, 0}
      end
    end)
    
    acc + result
  end)

Part 02