Skip to content

Commit 6f02dff

Browse files
committed
Refactor away from GenServer
1 parent bac3cce commit 6f02dff

File tree

6 files changed

+118
-465
lines changed

6 files changed

+118
-465
lines changed

lib/2015/day_07.ex

Lines changed: 53 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,111 +3,84 @@ defmodule AdventOfCode.Y2015.Day07 do
33
--- Day 7: Some Assembly Required ---
44
Problem Link: https://adventofcode.com/2015/day/7
55
Difficulty: m
6-
Tags: genserver data-modelling op-code
6+
Tags: graph dag logic-gates bitwise
77
"""
8+
import Bitwise
89
alias AdventOfCode.Helpers.{InputReader, Transformers}
9-
alias AdventOfCode.Y2015.Day07.ControlPanel
1010

1111
def input, do: InputReader.read_from_file(2015, 7)
1212

13-
@bin_ops ~w/RSHIFT LSHIFT AND OR/
14-
1513
def run(input \\ input()) do
16-
parsed_input = parse(input)
17-
solution_1 = run_1(parsed_input)
18-
solution_2 = run_2(parsed_input, solution_1)
14+
wires = parse(input)
1915

20-
{solution_1, solution_2}
21-
end
16+
values_1 = solve_circuit(wires)
17+
solution_1 = values_1["a"]
2218

23-
defp run_1(parsed_input) do
24-
process_and_get_signal(parsed_input, "a")
25-
end
19+
wires_2 = Map.put(wires, "b", {:assign, [solution_1]})
20+
values_2 = solve_circuit(wires_2)
21+
solution_2 = values_2["a"]
2622

27-
defp run_2({assignments, relations}, override) do
28-
assignments
29-
|> Enum.map(fn
30-
{"b", assignment} -> {"b", Map.merge(assignment, %{relation: {:assign, override}})}
31-
assignment -> assignment
32-
end)
33-
|> then(fn assignments -> {assignments, relations} end)
34-
|> process_and_get_signal("a")
23+
{solution_1, solution_2}
3524
end
3625

37-
def parse(data \\ input()) do
38-
data
39-
|> Transformers.lines()
40-
|> Enum.map(&tokenize/1)
41-
|> Map.new(fn {instruction, wire} ->
42-
{wire, %{relation: instruction, providers: get_providers(instruction)}}
43-
end)
44-
|> Enum.split_with(fn
45-
{_, %{providers: []}} -> true
46-
_ -> false
47-
end)
48-
end
26+
defp solve_circuit(wires) do
27+
edges =
28+
for {target, {_op, args}} <- wires,
29+
arg <- args,
30+
is_binary(arg),
31+
do: {arg, target, 1}
4932

50-
# --- <Solution Functions> ---
51-
defp process_and_get_signal({assignments, relations} = instructions, wire) do
52-
ControlPanel.start_servers()
33+
graph =
34+
Map.keys(wires)
35+
|> Enum.reduce(Yog.directed(), fn wire, g -> Yog.add_node(g, wire, nil) end)
36+
|> Yog.add_edges!(edges)
5337

54-
ControlPanel.create_wires(instructions)
55-
ControlPanel.build_dependencies(relations)
56-
ControlPanel.provide_signals(assignments)
38+
{:ok, sorted} = Yog.Traversal.topological_sort(graph)
5739

58-
result = ControlPanel.get_signal(wire)
40+
Enum.reduce(sorted, %{}, fn wire, values ->
41+
{op, args} = wires[wire]
5942

60-
ControlPanel.stop_servers()
43+
arg_vals =
44+
Enum.map(args, fn
45+
arg when is_integer(arg) -> arg
46+
arg when is_binary(arg) -> Map.get(values, arg)
47+
end)
6148

62-
result
63-
end
64-
65-
defp tokenize(line) do
66-
line
67-
|> String.split("->")
68-
|> then(fn [lhs, rhs] ->
69-
{parse_instruction(lhs), String.trim(rhs)}
49+
Map.put(values, wire, compute(op, arg_vals))
7050
end)
7151
end
7252

73-
defp get_providers(relation) do
74-
case relation do
75-
{_, value} when is_binary(value) ->
76-
[value]
77-
78-
{_, value_a, value_b} when is_binary(value_a) and is_binary(value_b) ->
79-
[value_a, value_b]
80-
81-
{_, value, _} when is_binary(value) ->
82-
[value]
53+
defp compute(:assign, [x]), do: x
54+
defp compute(:not, [x]), do: bnot(x) &&& 0xFFFF
55+
defp compute(:and, [x, y]), do: x &&& y &&& 0xFFFF
56+
defp compute(:or, [x, y]), do: (x ||| y) &&& 0xFFFF
57+
defp compute(:lshift, [x, y]), do: x <<< y &&& 0xFFFF
58+
defp compute(:rshift, [x, y]), do: x >>> y &&& 0xFFFF
8359

84-
{_, _, value} when is_binary(value) ->
85-
[value]
86-
87-
_ ->
88-
[]
89-
end
60+
def parse(data \\ input()) do
61+
data
62+
|> Transformers.lines()
63+
|> Map.new(fn line ->
64+
[lhs, rhs] = String.split(line, " -> ")
65+
{rhs, parse_op(lhs)}
66+
end)
9067
end
9168

92-
defp parse_instruction(s) do
93-
case Regex.split(~r/\s+/, s, trim: true) do
94-
["NOT", value] ->
95-
{:not, sanitize(value)}
96-
97-
[value_1, op, value_2] when op in @bin_ops ->
98-
{String.to_atom(String.downcase(op)), sanitize(value_1), sanitize(value_2)}
99-
100-
[value] ->
101-
{:assign, sanitize(value)}
69+
defp parse_op(s) do
70+
case String.split(s) do
71+
["NOT", x] -> {:not, [val(x)]}
72+
[x, "AND", y] -> {:and, [val(x), val(y)]}
73+
[x, "OR", y] -> {:or, [val(x), val(y)]}
74+
[x, "LSHIFT", y] -> {:lshift, [val(x), val(y)]}
75+
[x, "RSHIFT", y] -> {:rshift, [val(x), val(y)]}
76+
[x] -> {:assign, [val(x)]}
10277
end
10378
end
10479

105-
defp sanitize(value) do
106-
case Integer.parse(value) do
107-
{value, ""} -> value
108-
:error -> value
80+
defp val(s) do
81+
case Integer.parse(s) do
82+
{n, ""} -> n
83+
_ -> s
10984
end
11085
end
111-
112-
# --- </Solution Functions> ---
11386
end

lib/2015/day_07/control_panel.ex

Lines changed: 0 additions & 78 deletions
This file was deleted.

lib/2015/day_07/wire.ex

Lines changed: 0 additions & 123 deletions
This file was deleted.

0 commit comments

Comments
 (0)