aoc/20/lib/days/day8.ex
2023-12-04 10:25:33 +01:00

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