Code for the Advent of Code event
aoc advent-of-code
at rust 84 lines 2.2 kB view raw
1#!/usr/bin/env ruby 2# frozen_string_literal: true 3 4class Cuboid 5 attr_reader :left, :right, :bottom, :top, :front, :back 6 7 def initialize(left, right, bottom, top, front, back) 8 @left = left 9 @right = right 10 @bottom = bottom 11 @top = top 12 @front = front 13 @back = back 14 @removed = [] 15 end 16 17 def width = (right - left + 1).abs 18 def height = (top - bottom + 1).abs 19 def depth = (back - front + 1).abs 20 21 def volume 22 (width * depth * height) - @removed.sum(&:volume) 23 end 24 25 def clamp(range) 26 Cuboid.new left.clamp(range), right.clamp(range), bottom.clamp(range), top.clamp(range), front.clamp(range), back.clamp(range) 27 end 28 29 def clamp!(range) 30 @left = left.clamp range 31 @right = right.clamp range 32 @bottom = bottom.clamp range 33 @top = top.clamp range 34 @front = front.clamp range 35 @back = back.clamp range 36 self 37 end 38 39 def intersects?(other) 40 top >= other.bottom && bottom <= other.top && 41 right >= other.left && left <= other.right && 42 back >= other.front && front <= other.back 43 end 44 45 def intersection(other) 46 return nil unless intersects? other 47 bottom = [@bottom, other.bottom].max 48 top = [@top, other.top].min 49 left = [@left, other.left].max 50 right = [@right, other.right].min 51 front = [@front, other.front].max 52 back = [@back, other.back].min 53 Cuboid.new(left, right, bottom, top, front, back) 54 end 55 56 def remove!(cuboid) 57 @removed.each { |r| r.remove!(cuboid.intersection(r)) if r.intersects? cuboid } 58 @removed << cuboid 59 end 60 61 def to_s 62 "(X=#{left}..#{right},Y=#{bottom}..#{top},Z=#{front}..#{back})" 63 end 64end 65 66def format_number(n) 67 n.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1 ').reverse 68end 69 70reactor = [] 71 72ARGF.each_line do |line| 73 op, ranges = line.split.then { [_1.to_sym, _2] } 74 left, right, bottom, top, front, back = ranges.scan(/-?\d+/).map(&:to_i) 75 cuboid = Cuboid.new(left, right, bottom, top, front, back) 76 intersecting = reactor.select { |c| cuboid.intersects? c } 77 intersecting.each do |c| 78 intersection = c.intersection cuboid 79 c.remove! intersection 80 end 81 reactor << cuboid if op == :on 82end 83 84puts reactor.sum(&:volume)