You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
56 lines
1.1 KiB
56 lines
1.1 KiB
require "strscan"
|
|
|
|
Part = Data.define(:number) do
|
|
def eql?(other)
|
|
self.object_id == other.object_id
|
|
end
|
|
end
|
|
|
|
def parse(input)
|
|
ss = StringScanner.new(input)
|
|
y = x = 0
|
|
schematic = {}
|
|
until ss.eos?
|
|
case
|
|
when ss.scan(/\./)
|
|
x += 1
|
|
when num = ss.scan(/\d+/)
|
|
coords = (0...num.length).map {|dx| [y, x+dx] }
|
|
part = Part.new(num.to_i)
|
|
schematic.merge!(coords.to_h { [_1, part] })
|
|
x += num.length
|
|
when ss.scan(/\n/)
|
|
y += 1
|
|
x = 0
|
|
when sym = ss.scan(/./)
|
|
schematic[[y,x]] = sym
|
|
x += 1
|
|
else
|
|
fail
|
|
end
|
|
end
|
|
schematic
|
|
end
|
|
|
|
schematic = parse(ARGF.read)
|
|
syms, nums = schematic.partition { String === _2 }.map(&:to_h)
|
|
neighboring_parts = ->((y,x)) {
|
|
dy = (-1..1).to_a
|
|
dx = (-1..1).to_a
|
|
dy.product(dx)
|
|
.map {|dy,dx| [y+dy,x+dx] }
|
|
.filter_map { nums.fetch(_1, nil) }
|
|
}
|
|
|
|
# part one
|
|
p syms.keys.flat_map { neighboring_parts.(_1) }.uniq.sum(&:number)
|
|
|
|
# part two
|
|
p syms
|
|
.select { _2 == ?* }
|
|
.filter_map {|coord, _|
|
|
parts = neighboring_parts.(coord).uniq
|
|
parts.length == 2 ? parts : nil
|
|
}
|
|
.sum { _1.map(&:number).inject(:*) }
|