29
|
1 #! /usr/bin/env ruby
|
|
2
|
|
3 if ARGV.length != 1
|
|
4 abort("Incorrect arguments - needs input file")
|
|
5 elsif not File.exist? (ARGV[0])
|
|
6 abort("File #{ARGV[0]} did not exist")
|
|
7 end
|
|
8
|
|
9 file = ARGV[0]
|
|
10
|
|
11 FlipFlop = Struct.new(:state, :next)
|
|
12 Conjunction = Struct.new(:state, :next)
|
|
13 SignalMessage = Struct.new(:source, :state, :target)
|
|
14
|
|
15 nodes = Hash.new
|
|
16 broadcast = []
|
|
17
|
|
18 File.open(file, "r").each_line(chomp: true) do |line|
|
|
19 input, output = line.split(" -> ")
|
|
20 outputs = output.split(", ")
|
|
21 if input[0] == "&"
|
|
22 nodes[input[1..-1]] = Conjunction.new(Hash.new, outputs)
|
|
23 elsif input[0] == "%"
|
|
24 nodes[input[1..-1]] = FlipFlop.new(false, outputs)
|
|
25 else
|
|
26 broadcast = outputs
|
|
27 end
|
|
28 end
|
|
29
|
|
30 nodes.each do |node_name, node|
|
|
31 node.next.each do |target_name|
|
|
32 target_node = nodes[target_name]
|
|
33 if target_node.is_a?(Conjunction)
|
|
34 target_node.state[node_name] = false
|
|
35 end
|
|
36 end
|
|
37 end
|
|
38
|
|
39 button_presses = 1000
|
|
40 high_count = 0
|
|
41 low_count = 0
|
|
42
|
|
43 button_presses.times do |press|
|
|
44 low_count += 1
|
|
45 signals = []
|
|
46 processed = []
|
|
47 broadcast.each {|output| signals << SignalMessage.new("broadcast", false, output)}
|
|
48 while signals.length > 0
|
|
49 #puts "#{signals}"
|
|
50 signal = signals.shift()
|
|
51 if signal.state
|
|
52 high_count += 1
|
|
53 else
|
|
54 low_count += 1
|
|
55 end
|
|
56 target = nodes[signal.target]
|
|
57 if target.nil?
|
|
58 puts "Inactive node '#{signal.target}'"
|
|
59 elsif target.is_a?(FlipFlop)
|
|
60 # High signals stop here
|
|
61 next if signal.state
|
|
62 # Low signals affect state
|
|
63 target.state = !target.state
|
|
64 target.next.each {|output| signals << SignalMessage.new(signal.target, target.state, output)}
|
|
65 elsif target.is_a?(Conjunction)
|
|
66 target.state[signal.source] = signal.state
|
|
67 all_high = target.state.values.all?
|
|
68 target.next.each {|output| signals << SignalMessage.new(signal.target, !all_high, output)}
|
|
69 end
|
|
70 end
|
|
71 end
|
|
72
|
|
73 puts "Low: #{low_count}; High: #{high_count}; Score: #{low_count * high_count}"
|