60 lines
1.3 KiB
Elixir
60 lines
1.3 KiB
Elixir
defmodule AOC.Day8 do
|
|
def get_input do
|
|
AOC.Util.input_lines(8, 1)
|
|
|> Enum.map(fn line ->
|
|
[opcode, arg] = String.split(line)
|
|
{String.to_atom(opcode), String.to_integer(arg)}
|
|
end)
|
|
|> Enum.with_index()
|
|
|> Enum.into(%{}, fn {v, k} -> {k, v} end)
|
|
end
|
|
|
|
def find_loop(program), do: find_loop(program, 0, MapSet.new(), 0)
|
|
|
|
def find_loop(program, acc, seen, ip) do
|
|
cond do
|
|
MapSet.member?(seen, ip) ->
|
|
acc
|
|
|
|
ip >= length(Map.keys(program)) ->
|
|
{true, acc}
|
|
|
|
true ->
|
|
seen = MapSet.put(seen, ip)
|
|
|
|
{acc, ip} =
|
|
case program[ip] do
|
|
{:acc, arg} -> {acc + arg, ip + 1}
|
|
{:nop, _} -> {acc, ip + 1}
|
|
{:jmp, arg} -> {acc, ip + arg}
|
|
end
|
|
|
|
find_loop(program, acc, seen, ip)
|
|
end
|
|
end
|
|
|
|
def part1 do
|
|
get_input()
|
|
|> find_loop()
|
|
end
|
|
|
|
def perturb_program(program) do
|
|
program
|
|
|> Stream.reject(fn {_, {opcode, _}} -> opcode == :acc end)
|
|
|> Stream.map(fn
|
|
{ip, {:nop, arg}} -> {ip, {:jmp, arg}}
|
|
{ip, {:jmp, arg}} -> {ip, {:nop, arg}}
|
|
end)
|
|
|> Stream.map(fn {ip, v} ->
|
|
Map.put(program, ip, v)
|
|
end)
|
|
end
|
|
|
|
def part2 do
|
|
get_input()
|
|
|> perturb_program()
|
|
|> Stream.map(&find_loop/1)
|
|
|> Stream.filter(&is_tuple/1)
|
|
|> Enum.to_list()
|
|
end
|
|
end
|