summaryrefslogtreecommitdiff
path: root/2015/day7.exs
blob: c38a93146e458194bc768c2d0a03bfe6ec379a75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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}")