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
require "strscan"

mem = Hash.new(0)
mask = nil

ss = StringScanner.new(ARGF.read)
until ss.eos?
  case
  when ss.scan(/mask = ([10X]+)\n/)
    mask = ss.captures.fetch(0)
  when ss.scan(/mem\[(\d+)\] = (\d+)\n/)
    addr, value = ss.captures.map(&:to_i)

    # part 1
    # value &= mask.gsub(?X, ?1).to_i(2)
    # value |= mask.gsub(?X, ?0).to_i(2)
    # mem[addr] = value

    masked = ("%036b" % addr).chars.zip(mask.chars).map {|a,m|
      case m
      when ?X then ?X
      when ?1 then ?1
      when ?0 then a
      else fail
      end
    }.join
    floating = masked.count(?X)
    (0...2**floating).map {|i| i.to_s(2).chars }.each do |i|
      floated = masked.gsub(?X) { i.pop || "0" }.to_i(2)
      mem[floated] = value
    end
  else
    fail
  end
end

p mem.values.sum