advent-of-code/2015-elixir-2/lib/solutions/day_07.ex
2023-11-20 20:54:43 +01:00

122 lines
2.2 KiB
Elixir

defmodule Aoc.Solution.Day07 do
import Bitwise
import Aoc.Utils
@name "Day 7: Some Assembly Required"
@behaviour Solution
@impl Solution
def get_name, do: @name
@impl Solution
def parse!(raw) do
split_lines(raw)
|> Enum.map(fn l -> parse_values(l, " -> ") end)
end
@impl Solution
def solve(input, k \\ "a") do
wires = Map.new()
all = Enum.count(input)
wire(wires, all, input) |> Map.get(k)
end
@impl Solution
def solve_again(input) do
value = solve(input)
solve(
Enum.map(
input,
fn [o, i] ->
case i do
"b" -> [Integer.to_string(value), i]
_ -> [o, i]
end
end
)
)
end
def wire(wires, all, queue) do
wires = walk(wires, queue)
case Enum.count(wires) do
^all -> wires
_ -> wire(wires, all, queue)
end
end
def walk(wires, []), do: wires
def walk(wires, [[output, input] | remain]) do
case apply_rule(wires, String.split(output)) do
nil ->
walk(wires, remain)
v ->
walk(
Map.put_new(
wires,
input,
v
),
remain
)
end
end
def apply_rule(wires, ["NOT", wire]) do
case Map.get(wires, wire) do
nil -> nil
v -> 65536 + bnot(v)
end
end
def apply_rule(wires, [l, "AND", r]) do
l = _value(wires, l)
r = _value(wires, r)
case Enum.all?([l, r]) do
false -> nil
true -> l &&& r
end
end
def apply_rule(wires, [l, "OR", r]) do
l = _value(wires, l)
r = _value(wires, r)
case Enum.all?([l, r]) do
false -> nil
true -> bor(l, r)
end
end
def apply_rule(wires, [l, "RSHIFT", r]) do
case Map.get(wires, l) do
nil -> nil
l -> l >>> String.to_integer(r)
end
end
def apply_rule(wires, [l, "LSHIFT", r]) do
case Map.get(wires, l) do
nil -> nil
l -> l <<< String.to_integer(r)
end
end
def apply_rule(wires, [wire]) do
_value(wires, wire)
end
def _value(seen, k) do
try do
case Map.get(seen, k) do
nil -> String.to_integer(k)
v -> v
end
rescue
_e -> nil
end
end
end