[2016][ruby][10.0]
change vkqxqmvvkxrzktvztxzmzwqwvlrqnxkw
commit c2ea9778d14f82e813ae333ee001d668c59f937e
author Alpha Chen <alpha.chen@gmail.com>
date
parent vprnorzr
diff --git a/2016/ruby/day_10.rb b/2016/ruby/day_10.rb
new file mode 100644
index 0000000..6a9ab73
--- /dev/null
+++ b/2016/ruby/day_10.rb
@@ -0,0 +1,112 @@
+class Factory
+  attr_reader :bots, :bins
+
+  def initialize
+    @bots = Hash.new {|h,k| h[k] = Bot.new(self) }
+    @bins = Hash.new {|h,k| h[k] = Bin.new }
+  end
+
+  def <<(instruction)
+    case instruction
+    when /value (\d+) goes to bot (\d+)/
+      bots[$2.to_i] << $1.to_i
+    when /bot (\d+) gives low to (.+) (\d+) and high to (.+) (\d+)/
+      bot = bots[$1.to_i]
+      bot.outs = [out($2, $3.to_i),
+                  out($4, $5.to_i)]
+    else
+      raise "invalid instruction: #{instruction}"
+    end
+  end
+
+  private
+
+  def out(type, id)
+    case type
+    when 'bot'
+      bots[id]
+    when 'output'
+      bins[id]
+    else
+      raise "invalid type: #{type}"
+    end
+  end
+end
+
+class Bot
+  attr_reader :factory, :values, :outs, :log
+
+  def initialize(factory)
+    @factory = factory
+    @values = []
+    @log = []
+  end
+
+  def <<(value)
+    values << value
+    try_run
+  end
+
+  def outs=(outs)
+    @outs = outs
+    try_run
+  end
+
+  private
+
+  def try_run
+    return unless outs && values.size == 2
+
+    log << values.sort
+
+    low, high = values.sort
+    values.clear
+
+    outs[0] << low
+    outs[1] << high
+  end
+end
+
+class Bin
+  attr_reader :value
+
+  def <<(value)
+    @value = value
+  end
+end
+
+if __FILE__ == $0
+  factory = Factory.new
+  DATA.each_line do |line|
+    factory << line
+  end
+
+  p factory.bots.find {|id, bot|
+    bot.log.include?([17, 61])
+  }.first
+end
+
+require 'minitest'
+# require 'minitest/autorun'
+
+class TestDay10 < Minitest::Test
+  def test_day_10
+    instructions = <<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
+INSTRUCTIONS
+
+    factory = Factory.new
+    instructions.lines.each do |line|
+      factory << line
+    end
+
+    assert_equal [5, 2, 3], factory.bins.sort_by {|k,_| k }.map(&:last).map(&:value)
+  end
+end
+
+__END__