require "set" class CrossedWires attr_reader :wires def initialize(wires) @wires = wires end def self.for(input) new input.split("\n").map { |line| Wire.for line } end def intersections wires.map(&:positions).map(&:keys).reduce(&:&) end def intersection_distances intersections .map { |intersection| wires.map { |wire| wire.positions[intersection] }.sum } end def closest_intersection intersections .map{ |intersection| intersection.split(",").map(&:to_i) } .sort_by { |x, y| x.abs + y.abs }.min end class Wire attr_reader :turns def initialize(turns) @turns = turns end def self.for(line) new line.split(",").map { |turn| Turn.for turn } end def positions @positions ||= begin x = 0 y = 0 current_distance = 0 p = {} turns.each do |turn| turn.length.times do current_distance += 1 case turn.dir when "U" y -= 1 when "D" y += 1 when "L" x -= 1 when "R" x += 1 end p["#{x},#{y}"] = current_distance unless p.key?("#{x},#{y}") end end p end end end class Turn attr_reader :dir, :length def initialize(dir, length) @dir = dir @length = length end def self.for(string) new string[0], string[1..].to_i end end end