day24
This commit is contained in:
parent
bdc150d0ed
commit
14c6da72d9
144
src/day24.rs
Normal file
144
src/day24.rs
Normal file
@ -0,0 +1,144 @@
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
|
||||
//const RANGE: RangeInclusive<f64> = 7.0..=27.0;
|
||||
const RANGE: RangeInclusive<f64> = 200_000_000_000_000.0..=400_000_000_000_000.0;
|
||||
|
||||
#[aoc_generator(day24)]
|
||||
fn parse(input: &str) -> Vec<[f64; 6]> {
|
||||
let input: Vec<[f64; 6]> = input.lines()
|
||||
.map(|line| {
|
||||
line.split("@")
|
||||
.flat_map(|components| {
|
||||
components.split(",")
|
||||
.map(str::trim)
|
||||
.map(|num| num.parse::<f64>().unwrap())
|
||||
})
|
||||
.collect::<Vec<_>>().try_into().unwrap()
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
input
|
||||
}
|
||||
|
||||
#[aoc(day24, part1)]
|
||||
fn part1(input: &[[f64; 6]]) -> u32 {
|
||||
let mut total = 0;
|
||||
|
||||
// It's just solve the linear equations. I'm using a matrix.
|
||||
for i in 1..input.len() {
|
||||
for j in 0..i {
|
||||
let [a, b, _, d, e, _] = input[i];
|
||||
let [g, h, _, j, k, _] = input[j];
|
||||
|
||||
let determinant = e * j - d * k;
|
||||
if determinant == 0.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let t = (j * (h - b) - k * (g - a)) / determinant;
|
||||
let u = (d * (h - b) - e * (g - a)) / determinant;
|
||||
|
||||
let x = a + t * d;
|
||||
let y = b + t * e;
|
||||
|
||||
if t >= 0.0 && u >= 0.0 && RANGE.contains(&x) && RANGE.contains(&y) {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
|
||||
#[aoc(day24, part2)]
|
||||
fn part2(input: &[[f64; 6]]) -> f64 {
|
||||
let [a, b, c, d, e, f] = input[0];
|
||||
let [g, h, i, j, k, l] = input[1];
|
||||
let [m, n, o, p, q, r] = input[2];
|
||||
|
||||
let mut matrix = [
|
||||
[0.0, l - f, e - k, 0.0, c - i, h - b, e * c - b * f + h * l - k * i],
|
||||
[0.0, r - f, e - q, 0.0, c - o, n - b, e * c - b * f + n * r - q * o],
|
||||
[f - l, 0.0, j - d, i - c, 0.0, a - g, a * f - d * c + j * i - g * l],
|
||||
[f - r, 0.0, p - d, o - c, 0.0, a - m, a * f - d * c + p * o - m * r],
|
||||
[k - e, d - j, 0.0, b - h, g - a, 0.0, d * b - a * e + g * k - j * h],
|
||||
[q - e, d - p, 0.0, b - n, m - a, 0.0, d * b - a * e + m * q - p * n],
|
||||
];
|
||||
|
||||
// Use Gaussian elimination to solve for the 6 unknowns.
|
||||
// Forward elimination, processing columns from left to right.
|
||||
// This will leave a matrix in row echelon form.
|
||||
// That's right, I got a D in applied linear algebra.
|
||||
for pivot in 0..6 {
|
||||
// Make leading coefficient of each row positive to make subsequent calculations easier.
|
||||
for row in &mut matrix[pivot..] {
|
||||
if row[pivot] < 0.0 {
|
||||
row.iter_mut().for_each(|num| *num = -*num);
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
let column = matrix.map(|row| row[pivot]);
|
||||
|
||||
// If only one non-zero coefficient remaining in the column then we're done.
|
||||
if column[pivot..].iter().filter(|&&c| c > 0.0).count() == 1 {
|
||||
// Move this row into the pivot location
|
||||
let index = column.iter().rposition(|&c| c > 0.0).unwrap();
|
||||
matrix.swap(pivot, index);
|
||||
break;
|
||||
}
|
||||
|
||||
// Find the row with the lowest non-zero leading coefficient.
|
||||
let min = *column[pivot..].iter().filter(|&&c| c > 0.0).min_by(|a, b| a.total_cmp(b)).unwrap();
|
||||
let index = column.iter().rposition(|&c| c == min).unwrap();
|
||||
|
||||
// Subtract as many multiples of this minimum row from each other row as possible
|
||||
// to shrink the coefficients of our column towards zero.
|
||||
for row in pivot..6 {
|
||||
if row != index && column[row] != 0.0 {
|
||||
let factor = column[row] / min;
|
||||
|
||||
for col in pivot..7 {
|
||||
matrix[row][col] -= factor * matrix[index][col];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Back substitution, processing columns from right to left.
|
||||
// This will leave the matrix in reduced row echelon form.
|
||||
// The solved unknowns are then in the 7th column.
|
||||
for pivot in (0..6).rev() {
|
||||
matrix[pivot][6] /= matrix[pivot][pivot];
|
||||
|
||||
for row in 0..pivot {
|
||||
matrix[row][6] -= matrix[pivot][6] * matrix[row][pivot];
|
||||
}
|
||||
}
|
||||
|
||||
(matrix[0][6] + matrix[1][6] + matrix[2][6]).floor()
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const EX: &str = r"19, 13, 30 @ -2, 1, -2
|
||||
18, 19, 22 @ -1, -1, -2
|
||||
20, 25, 34 @ -2, -2, -4
|
||||
12, 31, 28 @ -1, -2, -1
|
||||
20, 19, 15 @ 1, -5, -3";
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
assert_eq!(part1(&parse(EX)), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
assert_eq!(part2(&parse(EX)), 47.0);
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
mod day24;
|
||||
mod day23;
|
||||
mod day22;
|
||||
mod day21;
|
||||
|
Loading…
Reference in New Issue
Block a user