aoc_omni/ruby/2019/6/lib/universal_orbit_map.rb

56 lines
1.3 KiB
Ruby

class UniversalOrbitMap
attr_reader :orbits, :bodies
def initialize(orbits)
@orbits = orbits
body_names = orbits.map(&:orbitee) | orbits.map(&:orbiter)
@bodies = body_names.to_h { |name| [name, Body.new(name)] }
orbits.each do |orbit|
bodies[orbit.orbitee].orbiters << orbit.orbiter
bodies[orbit.orbiter].orbiting = bodies[orbit.orbitee]
end
end
def self.for(input)
new input.split("\n").map { |line| Orbit.for line }
end
def path_between(to, from)
to_chain = bodies[to].orbit_chain.map(&:name)
from_chain = bodies[from].orbit_chain.map(&:name)
common_chain = to_chain & from_chain
(from_chain - common_chain) + (to_chain - common_chain).reverse
end
class Body
attr_reader :name, :orbiters
attr_accessor :orbiting
def initialize(name)
@name = name
@orbiting = nil
@orbiters = []
end
def orbit_chain
chain = [orbiting]
while chain.last
chain << chain.last.orbiting
end
chain[..-2]
end
end
class Orbit
attr_accessor :orbitee, :orbiter, :orbitee_name, :orbiter_name
def initialize(orbitee, orbiter)
@orbiter = orbiter
@orbiter_name = orbiter
@orbitee = orbitee
@orbitee_name = orbitee
end
def self.for(line)
new *line.split(")")
end
end
end