require_relative 'util' # --- Day 10: Balance Bots --- # You come upon a factory in which many robots are zooming around # handing small microchips to each other. # Upon closer examination, you notice that each bot only proceeds when # it has two microchips, and once it does, it gives each one to a # different bot or puts it in a marked "output" bin. Sometimes, bots # take microchips from "input" bins, too. # Inspecting one of the microchips, it seems like they each contain a # single number; the bots must use some logic to decide what to do # with each chip. You access the local control computer and download # the bots' instructions (your puzzle input). # Some of the instructions specify that a specific-valued microchip # should be given to a specific bot; the rest of the instructions # indicate what a given bot should do with its lower-value or # higher-value chip. # For example, consider the following instructions: # value 5 goes to bot 2 # bot 2 gives low to bot 1 and high to bot 0 # value 3 goes to bot 1 # bot 1 gives low to output 1 and high to bot 0 # bot 0 gives low to output 2 and high to output 0 # value 2 goes to bot 2 # - Initially, bot 1 starts with a value-3 chip, and bot 2 starts with # a value-2 chip and a value-5 chip. # - Because bot 2 has two microchips, it gives its lower one (2) to # bot 1 and its higher one (5) to bot 0. # - Then, bot 1 has two microchips; it puts the value-2 chip in output # 1 and gives the value-3 chip to bot 0. # - Finally, bot 0 has two microchips; it puts the 3 in output 2 and # the 5 in output 0. # In the end, output bin 0 contains a value-5 microchip, output bin 1 # contains a value-2 microchip, and output bin 2 contains a value-3 # microchip. In this configuration, bot number 2 is responsible for # comparing value-5 microchips with value-2 microchips. # Based on your instructions, what is the number of the bot that is # responsible for comparing value-61 microchips with value-17 # microchips? class OutputBin attr_accessor :id, :values def initialize(id) @id = id @values = [] end def receive(value) @values << value end end class Bot attr_accessor :id, :values def initialize(id) @id = id @values = [] @low_to = nil @high_to = nil end def receive(value) @values << value give(@low_to, @high_to) end def give(low_to, high_to) @low_to = low_to @high_to = high_to return unless @values.length == 2 low, high = @values.sort @low_to.receive(low) if @low_to @high_to.receive(high) if @high_to end end input = File.open('10.txt') { |f| f.readlines.map(&:chomp) } test_input = [ 'value 5 goes to bot 2', 'bot 2 gives low to bot 1 and high to bot 0', 'value 3 goes to bot 1', 'bot 1 gives low to output 1 and high to bot 0', 'bot 0 gives low to output 2 and high to output 0', 'value 2 goes to bot 2' ] def parse(bots, outputs, receiver) target, id = receiver.split(' ') return bots[id.to_i] if target == 'bot' return outputs[id.to_i] if target == 'output' end def count(input, type) haystack = input.join("\n") re = Regexp.new("#{type} (\\d+)") haystack.scan(re).map { |m| m[0].to_i }.max + 1 end def simulate(input) bots = Array.new(count(input, 'bot')) { |i| Bot.new(i) } outputs = Array.new(count(input, 'output')) { |i| OutputBin.new(i) } input.each do |line| case line when /value (\d+) goes to bot (\d+)/ bots[$2.to_i].receive($1.to_i) when /bot (\d+) gives low to (\w+ \d+) and high to (\w+ \d+)/ bots[$1.to_i].give(parse(bots, outputs, $2), parse(bots, outputs, $3)) end end [bots, outputs] end def easy(input) bots, _outputs = simulate(input) bots.find { |bot| bot.values == [61, 17] || bot.values == [17, 61] }.id end puts "easy(input): #{easy(input)}" # --- Part Two --- # What do you get if you multiply together the values of one chip in # each of outputs 0, 1, and 2? def hard(input) _bots, outputs = simulate(input) outputs[0].values[0] * outputs[1].values[0] * outputs[2].values[0] end puts "hard(input): #{hard(input)}"