Skip to content

Instantly share code, notes, and snippets.

@kevbuchanan
Created June 21, 2013 20:02
Show Gist options
  • Save kevbuchanan/5833912 to your computer and use it in GitHub Desktop.
Save kevbuchanan/5833912 to your computer and use it in GitHub Desktop.
class Asteroid
attr_accessor :x, :y, :z, :connections
LIMIT = 150
def initialize(x, y, z, vx, vy, vz)
@x, @y, @z = x, y, z
@vx, @vy, @vz = vx, vy, vz
end
def travel
@x += @vx
@y += @vy
@z += @vz
end
def reached_limit?
@x.abs >= LIMIT || @y.abs >= LIMIT || @z.abs >= LIMIT
end
def distance_to(other)
dx = self.x - other.x
dy = self.y - other.y
dz = self.z - other.z
Math.sqrt(dx**2 + dy**2 + dz**2).round
end
def find_closest(others)
closest = (others - [self]).first
(others - [self]).each do |other|
distance = distance_to(other)
closest = other if distance < distance_to(closest)
end
closest
end
def coords
[@x, @y, @z]
end
end
class Relay
attr_accessor :asteroids
def initialize(asteroids_array)
@asteroids = asteroids_array
end
def distance
@asteroids.first.distance_to(@asteroids.last)
end
def ==(other)
other.class == self.class && other.asteroids.all? { |asteroid| self.asteroids.include?(asteroid) }
end
end
class RelaySystem
attr_reader :asteroids, :relays, :setups
def initialize(asteroids_array)
@asteroids = asteroids_array
@relays = []
@setups = 0
find_shortest
end
def all_connected?
@relays.size == @asteroids.size - 1
end
def shortest_path_from(asteroid, others)
until all_connected?
closest = asteroid.find_closest(others)
@relays << Relay.new([asteroid, closest])
break if all_connected?
next_closest = closest.find_closest(others - [asteroid])
if closest.distance_to(next_closest) < asteroid.distance_to(next_closest)
shortest_path_from(closest, others - [asteroid])
else
shortest_path_from(asteroid, others - [closest])
end
end
@relays
end
def find_shortest
shortest = nil
shortest_distance = nil
@asteroids.each do |asteroid|
path = shortest_path_from(asteroid, @asteroids)
distance = total_distance
if (shortest.nil? || distance < shortest_distance)
shortest = path
shortest_distance = distance
end
@relays = []
end
@setups += 1
@relays = shortest
shortest
end
def total_distance
total = 0
@relays.each { |relay| total += relay.distance }
total
end
def monitor
check = RelaySystem.new(@asteroids.map(&:clone))
if check.total_distance < total_distance
@relays = []
find_shortest
end
end
def start
until @asteroids.any?(&:reached_limit?)
@asteroids.each(&:travel)
monitor
end
puts "Case 1: #{@setups}"
@setups
end
end
asteroid_array = []
while input = gets
lines = input.split('\n')
lines.each do |line|
args = line.split(' ').map(&:to_i)
asteroid_array << Asteroid.new(args[0], args[1], args[2], args[3], args[4], args[5]) if args.size == 6
RelaySystem.new(asteroid_array).start if args.size == 0
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment