parent
76266b5bf3
commit
1fb181e7d2
@ -0,0 +1,109 @@
|
||||
require "set"
|
||||
|
||||
steps = ARGF.read.scan(/(on|off) x=(.+),y=(.+),z=(.+)/)
|
||||
.map {|power, *ranges| [power == "on", *ranges.map { eval(_1) }] }
|
||||
# .select {|_, *ranges| ranges.all? { _1.begin >= -50 && _1.end <= 50 }}
|
||||
|
||||
# reactor = Hash.new(false)
|
||||
# steps.each do |power,x,y,z|
|
||||
# x.each do |x|
|
||||
# y.each do |y|
|
||||
# z.each do |z|
|
||||
# reactor[[x,y,z]] = power
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
# p reactor.count { _2 }
|
||||
|
||||
# xs = steps.flat_map { [_2.begin, _2.end] }.minmax
|
||||
# ys = steps.flat_map { [_3.begin, _3.end] }.minmax
|
||||
# zs = steps.flat_map { [_4.begin, _4.end] }.minmax
|
||||
# ons = Range.new(*xs).sum {|x| Range.new(*ys).sum {|y| Range.new(*zs).count {|z|
|
||||
# step = steps.find { _2.cover?(x) && _3.cover?(y) && _4.cover?(z) }
|
||||
# step ? step[0] : false
|
||||
# }}}
|
||||
|
||||
# p ons
|
||||
|
||||
class Range
|
||||
def overlap(other)
|
||||
if cover?(other.begin)
|
||||
min = other.begin
|
||||
max = [self.end, other.end].min
|
||||
(min..max)
|
||||
elsif cover?(other.end)
|
||||
min = [self.begin, other.begin].max
|
||||
max = other.end
|
||||
(min..max)
|
||||
elsif other.cover?(self.begin)
|
||||
min = self.begin
|
||||
max = [self.end, other.end].min
|
||||
(min..max)
|
||||
elsif other.cover?(self.end)
|
||||
min = [self.begin, other.begin].max
|
||||
max = self.end
|
||||
(min..max)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def split(other)
|
||||
overlap = self.overlap(other)
|
||||
return [] if overlap.nil?
|
||||
|
||||
splits = [ overlap ]
|
||||
splits << (self.begin..overlap.begin-1) if overlap.begin > self.begin
|
||||
splits << (overlap.end+1..self.end) if overlap.end < self.end
|
||||
splits
|
||||
end
|
||||
end
|
||||
|
||||
Cube = Struct.new(:xs, :ys, :zs) do
|
||||
def -(other)
|
||||
return self unless o = overlap(other)
|
||||
|
||||
xxs = xs.split(other.xs)
|
||||
yys = ys.split(other.ys)
|
||||
zzs = zs.split(other.zs)
|
||||
|
||||
cuboids = xxs.flat_map {|x| yys.flat_map {|y| zzs.map {|z|
|
||||
Cube.new(x, y, z)
|
||||
}}}
|
||||
cuboids.delete(o)
|
||||
|
||||
cuboids
|
||||
end
|
||||
|
||||
def overlap(other)
|
||||
overlaps = to_a.zip(other.to_a).map { _1.overlap(_2) }
|
||||
return nil if overlaps.any?(&:nil?)
|
||||
|
||||
Cube.new(*overlaps)
|
||||
end
|
||||
|
||||
def overlap?(other) = !overlap(other).nil?
|
||||
|
||||
def volume = (xs.end - xs.begin + 1) * (ys.end - ys.begin + 1) * (zs.end - zs.begin + 1)
|
||||
|
||||
def to_s = "[#{[xs, ys, zs].map(&:to_s).join(", ")}]"
|
||||
alias_method :inspect, :to_s
|
||||
end
|
||||
|
||||
steps = steps.map {|power, *ranges| [power, Cube.new(*ranges)] }
|
||||
|
||||
reactor = Set.new
|
||||
steps.each do |power, cube|
|
||||
reactor
|
||||
.select { _1.overlap?(cube) }
|
||||
.each do |overlap|
|
||||
reactor.delete(overlap)
|
||||
reactor.merge(overlap - cube)
|
||||
end
|
||||
|
||||
reactor << cube if power
|
||||
end
|
||||
|
||||
p reactor.sum(&:volume)
|
Loading…
Reference in new issue