gates = File.stream!("inputs/day7.txt") gateRegex = ~r/(([a-z]+|[0-9]+) )?(([A-Z]+) )?([a-z]+|[0-9]+) -> ([a-z]+)/ circuit = Enum.reduce(gates, Map.new(), fn gate, acc -> [_, _, input1, _, op, input2, output] = Regex.run(gateRegex, gate) inputs = Enum.filter([input1, input2], fn input -> input != "" end) |> Enum.map(fn input -> case Integer.parse(input) do {num, ""} -> num :error -> input end end) Map.put(acc, output, {op, inputs}) end) defmodule MemoizedCircuitSolver do use Agent def start do Agent.start_link(fn -> %{} end, name: __MODULE__) end def evaluate(circuit, id) when is_integer(id) do id end def evaluate(circuit, id) do cached_value = Agent.get(__MODULE__, &Map.get(&1, {circuit, id})) if cached_value do cached_value else {op, inputs} = Map.get(circuit, id) inputs = Enum.map(inputs, fn i -> evaluate(circuit, i) end) result = case op do "" -> [result] = inputs result "NOT" -> [input] = inputs Bitwise.bnot(input) "AND" -> Enum.reduce(inputs, &Bitwise.band(&1, &2)) "OR" -> Enum.reduce(inputs, &Bitwise.bor(&1, &2)) "LSHIFT" -> [input, amount] = inputs Bitwise.bsl(input, amount) "RSHIFT" -> [input, amount] = inputs Bitwise.bsr(input, amount) end Agent.update(__MODULE__, &Map.put(&1, {circuit, id}, result)) result end end end {:ok, _} = MemoizedCircuitSolver.start() aValue = MemoizedCircuitSolver.evaluate(circuit, "a") IO.puts("Initial A value: #{aValue}") secondCircuit = Map.put(circuit, "b", {"", [aValue]}) aValue2 = MemoizedCircuitSolver.evaluate(secondCircuit, "a") IO.puts("Final A value: #{aValue2}")