view day20.rb @ 30:6de4f4d5404d

Implement Day 21 "possible spaces in a maze" Part 2 needs something like "find the repeats and lowest common multiple" that I'm not bothering with
author IBBoard <dev@ibboard.co.uk>
date Wed, 03 Jan 2024 12:01:18 +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}"