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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
#!/usr/bin/env ruby
# What can I say? I like the word reify.
vars = {}
nets = []
class Var
def initialize(name)
@name = name
@value = nil
end
attr_reader :name, :value
def reified?
!@value.nil?
end
def try_reify_numeric!
if @name =~ /\A\d+\Z/
@value = @name.to_i
end
end
def reify!(value)
@value = value
end
def reify_negative!
@value = 65536 + @value if @value < 0
end
def reset!
@value = nil
end
end
class Net
def initialize(left, op, right, out)
@left = left
@op = op
@right = right
@out = out
@reified = false
end
def reified?
@reified
end
def reifiable?
return false unless @left.nil? || @left.reified?
return false unless @right.reified?
return true
end
def reify!
case @op
when nil
@out.reify!(@right.value)
when "NOT"
@out.reify!(~@right.value)
when "AND"
@out.reify!(@left.value & @right.value)
when "OR"
@out.reify!(@left.value | @right.value)
when "LSHIFT"
@out.reify!(@left.value << @right.value)
when "RSHIFT"
@out.reify!(@left.value >> @right.value)
end
@reified = true
end
def reset!
@reified = false
end
end
File.readlines("day7.input").map(&:strip).each do |line|
input, output = line.split(" -> ")
input = input.split
vars[output] = Var.new(output) if vars[output].nil?
output = vars[output]
case input.length
when 1
vars[input[0]] = Var.new(input[0]) if vars[input[0]].nil?
nets << Net.new(nil, nil, vars[input[0]], output)
when 2
vars[input[1]] = Var.new(input[1]) if vars[input[1]].nil?
nets << Net.new(nil, input[0], vars[input[1]], output)
when 3
vars[input[0]] = Var.new(input[0]) if vars[input[0]].nil?
vars[input[2]] = Var.new(input[2]) if vars[input[2]].nil?
nets << Net.new(vars[input[0]], input[1], vars[input[2]], output)
end
end
# Part 1
vars.values.each(&:try_reify_numeric!)
until nets.all?(&:reified?)
nets.each do |net|
net.reify! if net.reifiable?
end
end
vars.values.each(&:reify_negative!)
part1 = vars["a"].value
puts "Part 1: #{part1}"
# Part 2
vars.values.each(&:reset!)
nets.each(&:reset!)
vars.values.each(&:try_reify_numeric!)
until nets.all?(&:reified?)
nets.each do |net|
vars["b"].reify!(part1)
net.reify! if net.reifiable?
end
end
vars.values.each(&:reify_negative!)
part2 = vars["a"].value
puts "Part 2: #{part2}"
|