use nalgebra::{Matrix2, Point2, Point3, Vector2, Vector3}; use nom::{ bytes::complete::tag, character::complete::{i64, line_ending}, combinator::map, multi::separated_list1, sequence::{separated_pair, tuple}, IResult, }; use std::fs; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_24.txt")?; let parsed = Hailstones::parser(&input).unwrap().1; dbg!(&parsed.count_intersections_2d(200000000000000., 400000000000000.)); Ok(()) } #[derive(Debug)] struct Hailstones(Vec); #[derive(Debug)] struct Hailstone { initial_position: Point3, velocity: Vector3, } impl Hailstones { fn parser(input: &str) -> IResult<&str, Self> { map(separated_list1(line_ending, Hailstone::parser), Hailstones)(input) } fn count_intersections_2d(&self, min: f64, max: f64) -> usize { self.0 .iter() .enumerate() .map(|(i, hailstone)| { self.0 .iter() .skip(i + 1) .filter(|other_hailstone| hailstone.intersects_2d(other_hailstone, min, max)) .count() }) .sum() } } impl Hailstone { fn parser(input: &str) -> IResult<&str, Self> { map( separated_pair( map( tuple((i64, tag(", "), i64, tag(", "), i64)), |(x, _, y, _, z)| Point3::new(x as f64, y as f64, z as f64), ), tag(" @ "), map( tuple((i64, tag(", "), i64, tag(", "), i64)), |(x, _, y, _, z)| Vector3::new(x as f64, y as f64, z as f64), ), ), |(initial_position, velocity)| Hailstone { initial_position, velocity, }, )(input) } fn intersects_2d(&self, other: &Hailstone, min: f64, max: f64) -> bool { let variables = Matrix2::new( self.velocity.x, -other.velocity.x, self.velocity.y, -other.velocity.y, ); let constants = Vector2::new( other.initial_position.x - self.initial_position.x, other.initial_position.y - self.initial_position.y, ); if let Some(variables_inverse) = variables.try_inverse() { let intersection = variables_inverse * constants; let self_t = intersection.x; let other_t = intersection.y; let intersection = self.initial_position.xy() + self.velocity.xy() * self_t; self_t >= 0. && other_t >= 0. && intersection.x >= min && intersection.x <= max && intersection.y >= min && intersection.y <= max } else { false } } }