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
input = ARGF.read

def hash(label)
  label.chars.inject(0) {|n,c|
    (n + c.ord) * 17 % 256
  }
end

# part one
p input.split(?,).sum { hash(_1) }

# part two
boxes = Hash.new {|h,k| h[k] = {} }
input.scan(/(\w+)([-=])(\d+)?/).each do |label, op, focal_length|
  box = boxes[hash(label)]
  case op
  when ?-
    box.delete(label)
  when ?=
    box[label] = focal_length.to_i
  else
    fail
  end
end

p boxes.flat_map {|box_i, box|
  box.map.with_index {|(label, focal_length), lens_i|
    [1 + box_i, 1 + lens_i, focal_length].inject(:*)
  }
}.sum