1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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.bins.values_at(0, 1, 2).map(&:value).inject(:*)
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__