Skip to content

Commit c107f1e

Browse files
committed
Day 20 part 1 Ruby solution
1 parent 6908b0d commit c107f1e

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

20-1.rb

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#!/usr/bin/env ruby
2+
3+
class Network
4+
attr_reader :gates
5+
6+
def initialize(input)
7+
gate_format = /^(?<name>[[:alpha:]&%]+) -> (?<outputs>.*)$/
8+
@gates = {}
9+
10+
input.each do |line|
11+
m = line.match gate_format
12+
outputs = m['outputs'].split(',').map(&:strip)
13+
if m['name'] == 'broadcaster'
14+
name = m['name']
15+
gate = Broadcaster.new(name, outputs)
16+
elsif m['name'].start_with? '%'
17+
name = m['name'][1..]
18+
gate = Flip_Flop.new(name, outputs)
19+
elsif m['name'].start_with? '&'
20+
name= m['name'][1..]
21+
gate = Conjunction.new(name, outputs)
22+
else
23+
abort "Unknown gate type #{m['name']}"
24+
end
25+
@gates[name] = gate
26+
end
27+
28+
@gates.each_value do |g|
29+
g.outputs.each do |o|
30+
@gates[o].connect_input g.name if @gates.include? o
31+
end
32+
end
33+
34+
@button_presses = 0
35+
end
36+
37+
def score
38+
(@button_presses +
39+
gates.values.map { |g| g.pulses[:low] }.reduce(&:+)) *
40+
gates.values.map { |g| g.pulses[:high] }.reduce(&:+)
41+
end
42+
43+
def step(queue)
44+
source, target, signal = queue.shift
45+
if @gates.include? target
46+
queue + @gates[target].receive(source, signal)
47+
else
48+
queue
49+
end
50+
end
51+
52+
def push_button!
53+
@button_presses += 1
54+
queue = [['button', 'broadcaster', :low]]
55+
queue = step(queue) until queue.empty?
56+
end
57+
end
58+
59+
class Gate
60+
attr_reader :name, :inputs, :outputs, :pulses
61+
62+
def initialize(name, outputs)
63+
@name = name
64+
@outputs = outputs
65+
@inputs = {}
66+
@pulses = Hash.new 0
67+
end
68+
69+
def connect_input(name)
70+
@inputs[name] = nil
71+
end
72+
73+
def receive(input, signal) end
74+
75+
def send(signal)
76+
res = []
77+
@outputs.each do |o|
78+
res << [@name, o, signal]
79+
@pulses[signal] += 1
80+
end
81+
res
82+
end
83+
84+
def inspect
85+
to_s
86+
end
87+
88+
def to_s
89+
"<#{self.class}: #{@name} -> #{@outputs.join ', '}>"
90+
end
91+
end
92+
93+
class Broadcaster < Gate
94+
def receive(input, signal)
95+
send signal
96+
end
97+
end
98+
99+
class Flip_Flop < Gate
100+
def initialize(name, outputs)
101+
super
102+
@state = :off
103+
end
104+
105+
def connect_input(name)
106+
@inputs[name] = :low
107+
end
108+
109+
def receive(input, signal)
110+
return [] if signal == :high
111+
112+
@inputs[input] = signal
113+
case @state
114+
when :off
115+
@state = :on
116+
return send :high
117+
when :on
118+
@state = :off
119+
return send :low
120+
end
121+
res
122+
end
123+
end
124+
125+
class Conjunction < Gate
126+
def connect_input(name)
127+
@inputs[name] = :low
128+
end
129+
130+
def receive(input, signal)
131+
@inputs[input] = signal
132+
133+
if @inputs.values.all? :high
134+
return send :low
135+
else
136+
return send :high
137+
end
138+
end
139+
end
140+
141+
input = File.read('20.input').lines.map(&:strip)
142+
143+
net = Network.new(input)
144+
1_000.times { |_| net.push_button! }
145+
print net.score, "\n"

0 commit comments

Comments
 (0)