[2023][ruby][3.*] clean up parsing

main
Alpha Chen 11 months ago
parent 8c72adad6d
commit e6ae06a605
Signed by: alpha
SSH Key Fingerprint: SHA256:3fOT8fiYQG/aK9ntivV3Bqtg8AYQ7q4nV6ZgihOA20g

@ -1,69 +1,55 @@
require "strscan"
Part = Data.define(:number) do Part = Data.define(:number) do
def eql?(other) def eql?(other)
self.object_id == other.object_id self.object_id == other.object_id
end end
end end
CurrentNumber = Data.define(:coords, :acc)
cur_num = nil def parse(input)
nums = {} ss = StringScanner.new(input)
syms = {} y = x = 0
ARGF.readlines(chomp: true).each.with_index do |row, y| schematic = {}
row.chars.each.with_index do |c, x| until ss.eos?
case c case
when /\d/ when ss.scan(/\./)
if cur_num x += 1
cur_num.coords << [y,x] when num = ss.scan(/\d+/)
cur_num.acc << c 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 else
cur_num = CurrentNumber.new([[y,x]], c) fail
end
else
if cur_num
part = Part.new(cur_num.acc.to_i)
nums.merge!(cur_num.coords.to_h { [_1, part] })
cur_num = nil
end
if c != ?.
syms[[y,x]] = c
end
end end
end end
schematic
if cur_num
part = Part.new(cur_num.acc.to_i)
nums.merge!(cur_num.coords.to_h { [_1, part] })
cur_num = nil
end
end 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 # part one
p syms p syms.keys.flat_map { neighboring_parts.(_1) }.uniq.sum(&:number)
.flat_map {|(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) }
.uniq
}
.sum(&:number)
# part two
p syms p syms
.select { _2 == ?* } .select { _2 == ?* }
.filter_map {|(y,x), _| .filter_map {|coord, _|
dy = (-1..1).to_a parts = neighboring_parts.(coord).uniq
dx = (-1..1).to_a parts.length == 2 ? parts : nil
parts = dy.product(dx)
.map {|dy,dx| [y+dy,x+dx] }
.filter_map { nums.fetch(_1, nil) }
.uniq
if parts.length == 2
parts
else
nil
end
} }
.sum { _1.map(&:number).inject(:*) } .sum { _1.map(&:number).inject(:*) }

Loading…
Cancel
Save