diff --git a/ruby/2019/6/bin/problem b/ruby/2019/6/bin/problem new file mode 100644 index 0000000..d9b2838 --- /dev/null +++ b/ruby/2019/6/bin/problem @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby + +require "universal_orbit_map" + +map = UniversalOrbitMap.for STDIN.read.chomp + +puts "Part 1: #{map.bodies.values.map(&:orbit_chain).map(&:length).sum}" + +puts "Part 2: #{map.path_between("YOU", "SAN").length}" diff --git a/ruby/2019/6/lib/universal_orbit_map.rb b/ruby/2019/6/lib/universal_orbit_map.rb new file mode 100644 index 0000000..49be95a --- /dev/null +++ b/ruby/2019/6/lib/universal_orbit_map.rb @@ -0,0 +1,55 @@ +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