# HG changeset patch # User IBBoard # Date 1713466499 -3600 # Node ID ca54f9702892664b22ecf4e4d220577fe6662f0d # Parent 59620bbc4084d437b527a13906d28e9da1eb56fb Day 24 part 2 instructions and partial solution diff -r 59620bbc4084 -r ca54f9702892 day24.txt --- a/day24.txt Fri Jan 05 11:42:13 2024 +0000 +++ b/day24.txt Thu Apr 18 19:54:59 2024 +0100 @@ -56,4 +56,33 @@ Look for future intersections that happen with an X and Y position each at least 200000000000000 and at most 400000000000000. Disregard the Z axis entirely. -Note: Some objects are moving upwards. \ No newline at end of file +Note: Some objects are moving upwards. + +--- Part 2 --- + +The objects won't _actually_ collide because of the Z dimension. So what starting point and velocity is required +for an additional object to be thrown such that it hits _all_ objects? + +For the example above, given a start of 24, 13, 10 and a velocity of -3, 1, 2 then we get: + +Object: 19, 13, 30 @ -2, 1, -2 +Collision time: 5 +Collision position: 9, 18, 20 + +Object: 18, 19, 22 @ -1, -1, -2 +Collision time: 3 +Collision position: 15, 16, 16 + +Object: 20, 25, 34 @ -2, -2, -4 +Collision time: 4 +Collision position: 12, 17, 18 + +Object: 12, 31, 28 @ -1, -2, -1 +Collision time: 6 +Collision position: 6, 19, 22 + +Object: 20, 19, 15 @ 1, -5, -3 +Collision time: 1 +Collision position: 21, 14, 12 + +Adding the starting position coordinates together, we get 47. \ No newline at end of file diff -r 59620bbc4084 -r ca54f9702892 day24b.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/day24b.rb Thu Apr 18 19:54:59 2024 +0100 @@ -0,0 +1,56 @@ +#! /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 \ No newline at end of file