56 lines
1.3 KiB
Ruby
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
|