Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Advent of Code 2024 - Day 17

2024/17.livemd

Advent of Code 2024 - Day 17

Mix.install([
  {:req, "~> 0.5"},
  {:benchee, "~> 1.3"}
])

Input

opts = [headers: [{"cookie", "session=#{System.fetch_env!("LB_AOC_SESSION")}"}]]
puzzle_input = Req.get!("https://adventofcode.com/2024/day/17/input", opts).body
[a, b, c, programm] =
  String.split(puzzle_input, "\n", trim: true)
  |> Enum.map(fn x ->
    case x do
      "Register" <> <<_::binary-size(4)>> <> register ->
        String.to_integer(register)

      "Program: " <> programm ->
        String.split(programm, ",")
        |> Enum.reject(&amp;(&amp;1 == ","))
        |> Enum.map(&amp;String.to_integer(&amp;1))
    end
  end)

state = %{a: a, b: b, c: c, output: [], programm: programm, pointer: 0}
defmodule Program do
  def run(state) do
    Stream.iterate(0, &amp;(&amp;1 + 1))
    |> Enum.reduce_while(state, fn _i, state ->
      %{a: a, b: b, c: c, programm: programm, pointer: pointer} = state
      opcode = Enum.at(programm, pointer)
      operand = Enum.at(programm, pointer + 1)

      case {opcode, operand} do
        {opcode, operand} when is_nil(opcode) or is_nil(operand) ->
          {:halt, state}

        {0, operand} ->
          Map.put(state, :a, div(a, 2 ** combo(operand, state)))
          |> cont()

        {1, operand} ->
          Map.put(state, :b, Bitwise.bxor(b, operand))
          |> cont()

        {2, operand} ->
          Map.put(state, :b, Integer.mod(combo(operand, state), 8))
          |> cont()

        {3, _operand} when a == 0 ->
          cont(state)

        {3, operand} when a != 0 ->
          cont(state, operand)

        {4, _operand} ->
          Map.put(state, :b, Bitwise.bxor(b, c))
          |> cont()

        {5, operand} ->
          Map.update!(state, :output, fn o -> [Integer.mod(combo(operand, state), 8) | o] end)
          |> cont()

        {6, operand} ->
          Map.put(state, :b, div(a, 2 ** combo(operand, state)))
          |> cont()

        {7, operand} ->
          Map.put(state, :c, div(a, 2 ** combo(operand, state)))
          |> cont()
      end
    end)
    |> then(fn %{output: output} ->
      Enum.reverse(output) |> Enum.intersperse(",") |> Enum.join()
    end)
  end

  def combo(operand, _state) when operand in 0..3, do: operand
  def combo(4, %{a: a}), do: a
  def combo(5, %{b: b}), do: b
  def combo(6, %{c: c}), do: c
  def combo(_operand, _state), do: nil

  def cont(state), do: {:cont, Map.update!(state, :pointer, &amp;(&amp;1 + 2))}
  def cont(state, pointer), do: {:cont, Map.put(state, :pointer, pointer)}
end

Puzzle 1

puzzle_1 = fn ->
  Program.run(state)
end

puzzle_1.()

Benchmarks

Benchee.run(%{
  "puzzle_1" => fn -> puzzle_1.() end
})
Name ips average deviation median 99th %
puzzle_1 145.36 K 6.88 μs ±111.02% 6.58 μs 13.25 μs