#[path = "../lib.rs"] mod lib; use std::convert::TryInto; fn parse_input() -> Vec<([i64; 3], [i64; 3])> { return lib::iter_input().map(|line| { let (a, b) = line.split_once('@').unwrap(); let p: Vec = a.split(',').map(|s| s.trim().parse().unwrap()).collect(); let d: Vec = b.split(',').map(|s| s.trim().parse().unwrap()).collect(); return ( p.try_into().unwrap(), d.try_into().unwrap(), ); }).collect(); } fn intersect(h1: ([i64; 3], [i64; 3]), h2: ([i64; 3], [i64; 3])) -> bool { // 200_000_000_000_000 <= x1 + t1*dx1 = x2 + t2*dx2 <= 400_000_000_000_000 // 200_000_000_000_000 <= y1 + t1*dy1 = y2 + t2*dy2 <= 400_000_000_000_000 // t1 = (x2 - x1 + t2*dx2) / dx1 // y1 + (x2 - x1 + t2*dx2) / dx1 * dy1 = y2 + t2*dy2 // y1 + x2*dy1/dx1 - x1*dy1/dx1 + t2*dx2*dy1/dx1 = y2 + t2*dy2 // y1 - y2 + x2*dy1/dx1 - x1*dy1/dx1 = t2*dy2 - t2*dx2*dy1/dx1 // y1 - y2 + x2*dy1/dx1 - x1*dy1/dx1 = t2 * (dy2 - dx2*dy1/dx1) // t2 = ((y1 - y2) + (x2 - x1)*dy1/dx1) / (dy2 - dx2*dy1/dx1) // t2 = ((y1 - y2)*dx1 - (x1 - x2)*dy1) / (dy2*dx1 - dx2*dy1) // in xy, lines intersect if they are not parallel // dy1 / dx1 != dy2 / dx2 // dy1 * dx2 != dy2 * dx1 let ([x1, y1, _z1], [dx1, dy1, _dz1]) = h1; let ([x2, y2, _z2], [dx2, dy2, _dz2]) = h2; let d = dy1 * dx2 - dx1 * dy2; if d == 0 { return false; } let dt1 = (y2 - y1) * dx2 - (x2 - x1) * dy2; if (dt1 < 0 && d >= 0) || (dt1 >= 0 && d < 0) { return false; } let dt2 = (y2 - y1) * dx1 - (x2 - x1) * dy1; if (dt2 < 0 && d >= 0) || (dt2 >= 0 && d < 0) { return false; } let x = x1 as f64 + dx1 as f64 * dt1 as f64 / d as f64; let y = y1 as f64 + dy1 as f64 * dt1 as f64 / d as f64; // let min = 7.0; // let max = 27.0; let min = 200_000_000_000_000.0; let max = 400_000_000_000_000.0; return x >= min && x <= max && y >= min && y <= max; } fn part1(hail: &Vec<([i64; 3], [i64; 3])>) -> i64 { let mut count = 0; for i in 0..hail.len() { for j in 0..i { if intersect(hail[i], hail[j]) { count += 1; } } } return count; } fn solve(matrix: &[[f64; N]; N], b: &[f64; N]) -> [f64; N] { let mut tmp = matrix.clone(); let mut result = b.clone(); for k in 0..N { result[k] = result[k] / tmp[k][k]; for j in (k..N).rev() { tmp[k][j] = tmp[k][j] / tmp[k][k]; } for i in (k + 1)..N { result[i] = result[i] - result[k] * tmp[i][k]; for j in (k..N).rev() { tmp[i][j] = tmp[i][j] - tmp[k][j] * tmp[i][k]; } } } for k in (0..N).rev() { for i in 0..k { result[i] = result[i] - result[k] * tmp[i][k]; } } return result; } fn part2(hail: &Vec<([i64; 3], [i64; 3])>) -> i64 { // x + ti*dx = xi + ti*dxi // y + ti*dy = yi + ti*dyi // z + ti*dz = zi + ti*dzi // (p - pi) / (di - d) = ti // (x - xi) / (dxi - dx) = ti // (p - pi) / (di - d) = (x - xi) / (dxi - dx) // p*dxi - d*xi - x*di + dx*pi + x*d - p*dx = pi*dxi - xi*di // p*(dxi - dxj) - d*(xi - xj) - x*(di - dj) + dx*(pi - pj) = pi*dxi - xi*di - pj*dxj + xj*dj let mut matrix = [[0.0; 4]; 4]; let mut b = [0.0; 4]; let ([xj, yj, zj], [dxj, dyj, dzj]) = hail[0]; let pj = xj + yj + zj; let dj = dxj + dyj + dzj; for i in 0..4 { let ([xi, yi, zi], [dxi, dyi, dzi]) = hail[i + 1]; let pi = xi + yi + zi; let di = dxi + dyi + dzi; matrix[i][0] = (dxi - dxj) as f64; matrix[i][1] = (xj - xi) as f64; matrix[i][2] = (dj - di) as f64; matrix[i][3] = (pi - pj) as f64; b[i] = (pi * dxi - xi * di - pj * dxj + xj * dj) as f64; } let result = solve(&matrix, &b); return result[0] as i64; } fn main() { let hail = parse_input(); println!("part1: {}", part1(&hail)); println!("part2: {}", part2(&hail)); }