Powered by AppSignal & Oban Pro

🎄 Year 2020 🔔 Day 08

elixir/notebooks/2020/day08.livemd

🎄 Year 2020 🔔 Day 08

Parse input

filename = "#{__DIR__}/../../../inputs/2020/day08.txt"

parsed_input_stream =
  File.stream!(filename)
  |> Enum.map(&String.trim/1)
  |> Enum.map(&String.split/1)
  |> Enum.map(fn [instruction, count] ->
    {String.to_atom(instruction), String.to_integer(count)}
  end)

Shared code

Part One

defmodule Helper do
  def recurse(instructions) do
    recurse(instructions, 0, 0, [])
  end

  defp recurse(instructions, step, acc, prev_steps) do
    if Enum.any?(prev_steps, &(&1 == step)) do
      acc
    else
      prev_steps = [step | prev_steps]

      case Enum.at(instructions, step) do
        {:nop, _count} ->
          recurse(instructions, step + 1, acc, prev_steps)

        {:acc, count} ->
          recurse(instructions, step + 1, acc + count, prev_steps)

        {:jmp, count} ->
          recurse(instructions, step + count, acc, prev_steps)
      end
    end
  end
end

Helper.recurse(parsed_input_stream)

Part two

defmodule Helper do
  def recurse(instructions) do
    recurse(instructions, 0, 0, [])
  end

  defp recurse(instructions, step, acc, prev_steps) do
    if Enum.any?(prev_steps, &(&1 == step)) do
      :failed
    else
      prev_steps = [step | prev_steps]

      case Enum.at(instructions, step, :failed) do
        {:nop, _count} ->
          recurse(instructions, step + 1, acc, prev_steps)

        {:acc, count} ->
          recurse(instructions, step + 1, acc + count, prev_steps)

        {:jmp, count} ->
          recurse(instructions, step + count, acc, prev_steps)

        :failed ->
          :failed

        :success ->
          {:success, acc}
      end
    end
  end
end

instructions = Enum.concat(parsed_input_stream, [:success])

Stream.iterate(0, &(&1 + 1))
|> Enum.reduce_while(nil, fn i, nil ->
  case Enum.at(instructions, i) do
    {:acc, _} ->
      {:cont, nil}

    _ ->
      instructions =
        List.update_at(instructions, i, fn {inst, count} ->
          new_instruction = if inst == :nop, do: :jmp, else: :nop
          {new_instruction, count}
        end)

      case Helper.recurse(instructions) do
        :failed ->
          {:cont, nil}

        {:success, acc} ->
          {:halt, acc}
      end
  end
end)