🎄 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)