Day 7: Some Assembly Required
Section
defmodule P1 do
import Bitwise
def resolve_values(lines) do
Enum.reduce(lines, %{}, fn {k, v}, acc ->
{value, updated_acc} = resolve_value(v, acc, lines)
Map.put(updated_acc, k, value)
end)
end
defp resolve_value(value, resolved, lines) when is_binary(value) do
if String.contains?(value, " ") do
eval_expr(value, resolved, lines)
else
case Integer.parse(value) do
{number, ""} ->
{number, resolved}
:error ->
if Map.has_key?(resolved, lines[value]) do
{Map.fetch!(resolved, lines[value]), resolved}
else
{resolved_value, updated_resolved} = resolve_value(lines[value], resolved, lines)
{resolved_value, Map.put(updated_resolved, lines[value], resolved_value)}
end
end
end
end
defp resolve_value(value, resolved, _lines) when is_integer(value),
do: {value, resolved}
defp eval_expr(expr, resolved, lines) do
case Regex.run(~r/NOT (\w*)/, expr) do
[_, var] ->
{resolved_value, updated_resolved} = resolve_value(var, resolved, lines)
{~~~resolved_value &&& 0xFFFF, updated_resolved}
nil ->
[l, op, r] = String.split(expr)
{l, l_res} = resolve_value(l, resolved, lines)
{r, r_res} = resolve_value(r, l_res, lines)
{apply_op(l, op, r), r_res}
end
end
defp apply_op(l, "AND", r), do: l &&& r
defp apply_op(l, "OR", r), do: l ||| r
defp apply_op(l, "LSHIFT", r), do: l <<< r
defp apply_op(l, "RSHIFT", r), do: l >>> r
end
# "123 -> x
# 456 -> y
# x AND y -> d
# x OR y -> e
# x LSHIFT 2 -> f
# y RSHIFT 2 -> g
# NOT x -> h
# NOT y -> i"
lines =
"/Users/eli/Desktop/input.txt"
|> File.read!()
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
[v, k] = String.split(line, " -> ")
{k, v}
end)
|> Enum.into(%{})
a =
lines
|> P1.resolve_values()
|> Map.get("a")
a
956
lines
|> Map.put("b", a)
|> P1.resolve_values()
|> Map.get("a")
40149