view day24.rb @ 35:ca54f9702892

Day 24 part 2 instructions and partial solution
author IBBoard <dev@ibboard.co.uk>
date Thu, 18 Apr 2024 19:54:59 +0100
parents 59620bbc4084
children
line wrap: on
line source

#! /usr/bin/env ruby

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)

box_range = 7..27
box_range = 200000000000000..400000000000000

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

# Reset our origin coordinates so that the bounding box starts at 0,0
# This prevents overflow with large numbers in the later calculation
offset = box_range.begin
box_range = 0..(box_range.size-1)
objects.each {|obj| obj.x -= offset; obj.y -= offset; obj.z -= offset}


def is_parallel?(a, b)
    (a.dx / b.dx) == (a.dy / b.dy)
end

def is_in_past?(obj, point)
    (obj.dx > 0 ? obj.x > point.x : obj.x < point.x) || (obj.dy > 0 ? obj.y > point.y : obj.y < point.y)
end

intersects = objects.combination(2).filter {|a, b| !is_parallel?(a, b) }.map do |a,b|
    # https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_two_points_on_each_line
    x_1 = a.x
    x_2 = a.x + a.dx
    x_3 = b.x
    x_4 = b.x + b.dx
    y_1 = a.y
    y_2 = a.y + a.dy
    y_3 = b.y
    y_4 = b.y + b.dy

    px = ((((x_1 * y_2) - (y_1 * x_2)) * (x_3 - x_4)) - ((x_1 - x_2) * ((x_3 * y_4) - (y_3 * x_4)))) / (((x_1 - x_2) * (y_3 - y_4)) - ((y_1 - y_2) * (x_3 - x_4)))
    py = ((((x_1 * y_2) - (y_1 * x_2)) * (y_3 - y_4)) - ((y_1 - y_2) * ((x_3 * y_4) - (y_3 * x_4)))) / (((x_1 - x_2) * (y_3 - y_4)) - ((y_1 - y_2) * (x_3 - x_4)))
    [a, b, Position.new(px, py, 0)]
end.filter do |a,b,intersect|
    box_range.include?(intersect.x) && box_range.include?(intersect.y) && !is_in_past?(a, intersect) && !is_in_past?(b, intersect)
end

puts intersects.length