view day24b.rb @ 38:8e92cb172e6b

Output final distance Also minor code cleanup
author IBBoard <dev@ibboard.co.uk>
date Fri, 20 Sep 2024 20:30:11 +0100
parents ca54f9702892
children
line wrap: on
line source

#! /usr/bin/env ruby

require 'prime'

if ARGV.length != 1
    abort("Incorrect arguments - needs input file")
elsif not File.exist? (ARGV[0])
abort("File #{ARGV[0]} did not exist")
end

file = ARGV[0]

MovingObject = Struct.new(:x, :y, :z, :dx, :dy, :dz)
Position = Struct.new(:x, :y, :z)

objects = File.open(file, "r").each_line(chomp: true).map do |line|
    pos, vel = line.split(" @ ")
    position = pos.split(", ").map(&:to_f)
    velocity = vel.split(",").map(&:to_f)
    MovingObject.new(position[0], position[1], position[2], velocity[0], velocity[1], velocity[2])
end

# Lots of answers talking about "gaussian elimination" and other maths, or use external libraries
# But some people pointed out that if there's two objects moving at the same speed in a given direction
# then the new object must move at some factor of the difference between their starting points
# so that it can cover the other two dimensions between them
matches = objects.combination(2).filter {|a,b| a.dx == b.dx || a.dy == b.dy || a.dz == b.dz}.group_by {|a,b| [a.dx == b.dx, a.dy == b.dy, a.dz == b.dz]}
puts "#{matches}"
x_objs = matches[[true,false,false]]
y_objs = matches[[false,true,false]]
z_objs = matches[[false,false,true]]
x_dist = (x_objs[0][0].x - x_objs[0][1].x).abs.to_i
y_dist = (y_objs[0][0].y - y_objs[0][1].y).abs.to_i
z_dist = (z_objs[0][0].z - z_objs[0][1].z).abs.to_i

puts "Starting distance gap: same x = #{x_dist}; same y = #{y_dist}; same z = #{z_dist}"
puts "GCD of x and y: #{x_dist.gcd(y_dist)}"
puts "GCD of x and z: #{x_dist.gcd(z_dist)}"
puts "GCD of x, y and z: #{x_dist.gcd(y_dist).gcd(z_dist)}"

# We can't use lowest common factor/greatest common divisor
# So try prime divisors that people talk about.
# (DistanceDifference % (RockVelocity-HailVelocity) = 0
x_candidates = x_objs.reduce(nil) do |accum, pair|
    a, b = pair
    x_diff = (a.x - b.x).abs.to_i

    if x_diff > 0
        candidates = (1..1000).map {|i| x_diff % i == 0 ? i + a.dx.abs : nil}.compact
        puts "#{x_diff} => #{candidates}"
        accum.nil? ? candidates : accum & candidates
    else
        accum
    end
end
puts x_candidates