122 lines
2.2 KiB
Elixir
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
|