day-24 done

This commit is contained in:
Dylan Thies
2023-12-28 14:53:11 -05:00
parent 6c8b4058fe
commit e034f6b859
4 changed files with 293 additions and 15 deletions

1
2023/Cargo.lock generated
View File

@@ -248,6 +248,7 @@ dependencies = [
"glam",
"itertools",
"nom",
"num",
]
[[package]]

View File

@@ -11,3 +11,4 @@ repository.workspace = true
nom = { workspace = true }
itertools = {workspace = true }
glam.workspace = true
num = "0.4.1"

View File

@@ -5,8 +5,9 @@ use nom::{
bytes::complete::tag,
character::complete,
multi::separated_list1,
number,
sequence::{separated_pair, tuple},
IResult, Parser, number,
IResult, Parser,
};
use itertools::Itertools;
@@ -29,7 +30,8 @@ impl Stones {
let slope1 = self.velocity.y / self.velocity.x;
let slope2 = other.velocity.y / other.velocity.x;
let denom = slope1 - slope2;
let x = (self.start.x *slope1 -other.start.x *slope2 + other.start.y - self.start.y) / denom;
let x =
(self.start.x * slope1 - other.start.x * slope2 + other.start.y - self.start.y) / denom;
let y = slope1 * (x - self.start.x) + self.start.y;
if !x.is_finite() || !y.is_finite() {
return None;
@@ -43,14 +45,31 @@ impl Stones {
}
}
/// day 24 part 1 of aoc 2023
///
/// # Arguments
/// - input the input for today's puzzle
///
/// # Panics
/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than
#[must_use]
pub fn part1(input: &str, min: f64, max: f64) -> String {
let (_, stones) = parse_input(input).expect("Aoc should have valid input");
stones.iter().combinations(2)
stones
.iter()
.combinations(2)
.filter_map(|pair| {
let [a, b] = pair[..] else { return None };
a.cross(b).and_then(|cross_position| (cross_position.x <= max && cross_position.y <= max && cross_position.x >= min && cross_position.y >= min).then_some(cross_position) )
}).count().to_string()
a.cross(b).and_then(|cross_position| {
(cross_position.x <= max
&& cross_position.y <= max
&& cross_position.x >= min
&& cross_position.y >= min)
.then_some(cross_position)
})
})
.count()
.to_string()
}
fn parse_tuple(input: &str) -> IResult<&str, DVec3> {
@@ -90,4 +109,3 @@ mod test {
assert_eq!(result, "2".to_string());
}
}

View File

@@ -1,20 +1,278 @@
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::similar_names)]
use glam::I64Vec3;
use nom::{
bytes::complete::tag,
character::complete,
multi::separated_list1,
sequence::{separated_pair, tuple},
IResult, Parser,
};
use itertools::Itertools;
use num::rational::Ratio;
type Cord = Ratio<i128>;
#[derive(Debug, Clone, Copy)]
struct Stones {
pub start: I64Vec3,
pub velocity: I64Vec3,
}
impl Stones {
fn cross_xy(&self, other: &Self) -> Option<(Cord, Cord)> {
let pax = Cord::from(i128::from(self.start.x));
let pay = Cord::from(i128::from(self.start.y));
let pbx = Cord::from(i128::from(other.start.x));
let pby = Cord::from(i128::from(other.start.y));
let vax = Cord::from(i128::from(self.velocity.x));
let vay = Cord::from(i128::from(self.velocity.y));
let vbx = Cord::from(i128::from(other.velocity.x));
let vby = Cord::from(i128::from(other.velocity.y));
let slope1 = vay / vax;
let slope2 = vby / vbx;
let denom = slope1 - slope2;
if denom == num::Zero::zero() {
return None;
}
let x = (pax * slope1 - pbx * slope2 + pby - pay) / denom;
let y = slope1 * (x - pax) + pay;
let t1 = (x - pax) / vax;
let t2 = (x - pbx) / vbx;
if t1 < num::zero() || t2 < num::zero() {
return None;
}
Some((x, y))
}
fn cross_xz(&self, other: &Self) -> Option<(Cord, Cord)> {
let pax = Cord::from(i128::from(self.start.x));
let paz = Cord::from(i128::from(self.start.z));
let pbx = Cord::from(i128::from(other.start.x));
let pbz = Cord::from(i128::from(other.start.z));
let vax = Cord::from(i128::from(self.velocity.x));
let vaz = Cord::from(i128::from(self.velocity.z));
let vbx = Cord::from(i128::from(other.velocity.x));
let vbz = Cord::from(i128::from(other.velocity.z));
let slope1 = vaz / vax;
let slope2 = vbz / vbx;
let denom = slope1 - slope2;
if denom == num::Zero::zero() {
return None;
}
let x = (pax * slope1 - pbx * slope2 + pbz - paz) / denom;
let z = slope1 * (x - pax) + paz;
let t1 = (x - pax) / vax;
let t2 = (x - pbx) / vbx;
if t1 < num::zero() || t2 < num::zero() {
return None;
}
Some((x, z))
}
fn stone_to_tuples(&self) -> ((Cord, Cord, Cord), (Cord, Cord, Cord)) {
let Stones {
start:
I64Vec3 {
x: p_x,
y: p_y,
z: p_z,
},
velocity:
I64Vec3 {
x: v_x,
y: v_y,
z: v_z,
},
} = *self;
(
(
Cord::from(i128::from(p_x)),
Cord::from(i128::from(p_y)),
Cord::from(i128::from(p_z)),
),
(
Cord::from(i128::from(v_x)),
Cord::from(i128::from(v_y)),
Cord::from(i128::from(v_z)),
),
)
}
}
/// day 24 part 2 of aoc 2023
///
/// # Arguments
/// - input the input for today's puzzle
///
/// # Panics
/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than
#[must_use]
pub fn part2 (_input: &str) -> String {
"Not Finished".to_string()
pub fn part2(input: &str) -> String {
let (_, stones) = parse_input(input).expect("Aoc should have valid input");
let iteresting_stones = stones
.iter()
.combinations(2)
.filter_map(|pair| {
let [a, b] = pair[..] else {
return None;
};
match (a.cross_xy(b), a.cross_xz(b)) {
(None, None) => false,
(None, Some(_)) | (Some(_), None) => true,
(Some((x1, _)), Some((x2, _))) => x1 != x2,
}
.then_some(*b)
})
.skip(4)
.take(3)
.collect::<Vec<_>>();
let ((p_ax, p_ay, p_az), (v_ax, v_ay, v_az)) = iteresting_stones[0].stone_to_tuples();
let ((p_bx, p_by, p_bz), (v_bx, v_by, v_bz)) = iteresting_stones[1].stone_to_tuples();
let ((p_cx, p_cy, p_cz), (v_cx, v_cy, v_cz)) = iteresting_stones[2].stone_to_tuples();
//setting up the syystem of equations
//println!("{v_az} - {v_cz} = {:?}", v_az - v_cz);
let mut equations = [
[
Cord::default(),
v_az - v_cz,
v_cy - v_ay,
Cord::default(),
p_cz - p_az,
p_ay - p_cy,
p_ay * v_az - p_az * v_ay - p_cy * v_cz + p_cz * v_cy,
],
[
v_az - v_cz,
Cord::default(),
v_cx - v_ax,
p_cz - p_az,
Cord::default(),
p_ax - p_cx,
p_ax * v_az - p_az * v_ax - p_cx * v_cz + p_cz * v_cx,
],
[
v_cy - v_ay,
v_ax - v_cx,
Cord::default(),
p_ay - p_cy,
p_cx - p_ax,
Cord::default(),
p_ay * v_ax - p_ax * v_ay - p_cy * v_cx + p_cx * v_cy,
],
[
Cord::default(),
v_bz - v_cz,
v_cy - v_by,
Cord::default(),
p_cz - p_bz,
p_by - p_cy,
p_by * v_bz - p_bz * v_by - p_cy * v_cz + p_cz * v_cy,
],
[
v_bz - v_cz,
Cord::default(),
v_cx - v_bx,
p_cz - p_bz,
Cord::default(),
p_bx - p_cx,
p_bx * v_bz - p_bz * v_bx - p_cx * v_cz + p_cz * v_cx,
],
[
v_cy - v_by,
v_bx - v_cx,
Cord::default(),
p_by - p_cy,
p_cx - p_bx,
Cord::default(),
p_by * v_bx - p_bx * v_by - p_cy * v_cx + p_cx * v_cy,
],
];
//println!("{equations:?}");
//gausian elimination
for i in 0..6 {
//need to make sure i,i is not zero
let none_zero_index = (i..6)
.find(|&row| equations[row][i] != Cord::default())
.unwrap();
//perform swap if need be
if i != none_zero_index {
(equations[i], equations[none_zero_index]) = (equations[none_zero_index], equations[i]);
}
// make i,i 1 and adjust the row
let current_leader = equations[i][i];
equations[i][i] = Cord::from_integer(1);
for pos in &mut equations[i][(i + 1)..] {
*pos /= current_leader;
}
//gausean elimination
for row in (i + 1)..6 {
let mult = equations[row][i];
if mult != Cord::default() {
equations[row][i] = Cord::default();
for col in (i + 1)..7 {
equations[row][col] -= equations[i][col] * mult;
}
}
}
}
//upper triangle done now to make it identity
//but doing a trick to turn col 6
for i in (0..6).rev() {
for row in 0..i {
//equality row
equations[row][6] -= equations[i][6] * equations[row][i];
equations[row][i] = Cord::default();
}
}
equations
.iter()
.take(3)
.map(|x| x[6].to_integer())
.sum::<i128>()
.to_string()
}
fn parse_tuple(input: &str) -> IResult<&str, I64Vec3> {
let (input, x) = complete::i64(input)?;
let (input, _) = tuple((tag(","), complete::space0))(input)?;
let (input, y) = complete::i64(input)?;
let (input, _) = tuple((tag(","), complete::space0))(input)?;
let (input, z) = complete::i64(input)?;
Ok((input, I64Vec3::new(x, y, z)))
}
fn parse_input(input: &str) -> IResult<&str, Vec<Stones>> {
separated_list1(
complete::line_ending,
separated_pair(
parse_tuple,
tuple((complete::space0, tag("@"), complete::space0)),
parse_tuple,
)
.map(|(start, velocity)| Stones { start, velocity }),
)(input)
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "";
const INPUT: &str = "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 part2_works() {
let result = part2(INPUT);
assert_eq!(result, "Not Finished".to_string());
assert_eq!(result, "47".to_string());
}
}