Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 7: Some Assembly Required

day_7_some_assembly_required.livemd

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