@@ -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> ---
11386end
0 commit comments