diff day20.rb @ 29:739415015d27

Implement Day 20 switches part 1
author IBBoard <dev@ibboard.co.uk>
date Wed, 03 Jan 2024 11:35:22 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/day20.rb	Wed Jan 03 11:35:22 2024 +0000
@@ -0,0 +1,73 @@
+#! /usr/bin/env ruby
+
+if ARGV.length != 1
+    abort("Incorrect arguments - needs input file")
+elsif not File.exist? (ARGV[0])
+abort("File #{ARGV[0]} did not exist")
+end
+
+file = ARGV[0]
+
+FlipFlop = Struct.new(:state, :next)
+Conjunction = Struct.new(:state, :next)
+SignalMessage = Struct.new(:source, :state, :target)
+
+nodes = Hash.new
+broadcast = []
+
+File.open(file, "r").each_line(chomp: true) do |line|
+    input, output = line.split(" -> ")
+    outputs = output.split(", ")
+    if input[0] == "&"
+        nodes[input[1..-1]] = Conjunction.new(Hash.new, outputs)
+    elsif input[0] == "%"
+        nodes[input[1..-1]] = FlipFlop.new(false, outputs)
+    else
+        broadcast = outputs
+    end
+end
+
+nodes.each do |node_name, node|
+    node.next.each do |target_name|
+        target_node = nodes[target_name]
+        if target_node.is_a?(Conjunction)
+            target_node.state[node_name] = false
+        end
+    end
+end
+
+button_presses = 1000
+high_count = 0
+low_count = 0
+
+button_presses.times do |press|
+    low_count += 1
+    signals = []
+    processed = []
+    broadcast.each {|output| signals << SignalMessage.new("broadcast", false, output)}
+    while signals.length > 0
+        #puts "#{signals}"
+        signal = signals.shift()
+        if signal.state
+            high_count += 1
+        else
+            low_count += 1
+        end
+        target = nodes[signal.target]
+        if target.nil?
+            puts "Inactive node '#{signal.target}'"
+        elsif target.is_a?(FlipFlop)
+            # High signals stop here
+            next if signal.state
+            # Low signals affect state
+            target.state = !target.state
+            target.next.each {|output| signals << SignalMessage.new(signal.target, target.state, output)}
+        elsif target.is_a?(Conjunction)
+            target.state[signal.source] = signal.state
+            all_high = target.state.values.all?
+            target.next.each {|output| signals << SignalMessage.new(signal.target, !all_high, output)}
+        end
+    end
+end
+
+puts "Low: #{low_count}; High: #{high_count}; Score: #{low_count * high_count}"