view day20.rb @ 33:676461cc3a70

Day 23 - track segments, not each space This allows us to explore the branches once then do quicker calculations for valid route lengths. But still requires exploring 1,262,816 routes to find the longest!
author IBBoard <dev@ibboard.co.uk>
date Thu, 04 Jan 2024 14:52:24 +0000
parents 739415015d27
children
line wrap: on
line source

#! /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}"