Skip to content

Commit

Permalink
[2023] Day 24: Part A
Browse files Browse the repository at this point in the history
  • Loading branch information
connorslade committed Dec 24, 2023
1 parent 9daac19 commit 51dec13
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Thank you to [Eric Wastl](http://was.tl) for running this incredible yearly even
- [Day 21: Step Counter](aoc_2023/src/day_21.rs)
- [Day 22: Sand Slabs](aoc_2023/src/day_22.rs)
- [Day 23: A Long Walk](aoc_2023/src/day_23.rs)
- [Day 24: Never Tell Me The Odds](aoc_2023/src/day_24.rs)
<!-- MARKER -->

## [2022](https://adventofcode.com/2022) [![aoc_2022](https://github.com/Basicprogrammer10/advent-of-code/actions/workflows/aoc_2022.yml/badge.svg)](https://github.com/Basicprogrammer10/advent-of-code/actions/workflows/aoc_2022.yml)
Expand Down
105 changes: 105 additions & 0 deletions aoc_2023/src/day_24.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use std::ops::RangeInclusive;

use common::{Answer, Solution};
use itertools::Itertools;
use nd_vec::{vector, Vec2, Vec3};

type Pos = Vec3<f64>;

pub struct Day24;

impl Solution for Day24 {
fn name(&self) -> &'static str {
"Never Tell Me The Odds"
}

fn part_a(&self, input: &str) -> Answer {
let stones = parse(input);

const RANGE: RangeInclusive<f64> = 200000000000000.0..=400000000000000.0;
stones
.iter()
.tuple_combinations()
.filter_map(|(a, b)| a.collision(b))
.filter(|&pos| RANGE.contains(&pos.x()) && RANGE.contains(&pos.y()))
.count()
.into()
}

fn part_b(&self, input: &str) -> Answer {
Answer::Unimplemented
}
}

#[derive(Debug)]
struct HailStone {
pos: Pos,
vel: Pos,
}

impl HailStone {
fn collision(&self, other: &Self) -> Option<Vec2<f64>> {
let a_slope = self.vel.y() / self.vel.x();
let a_intercept = self.pos.y() - a_slope * self.pos.x();

let b_slope = other.vel.y() / other.vel.x();
let b_intercept = other.pos.y() - b_slope * other.pos.x();

let x_pos = (b_intercept - a_intercept) / (a_slope - b_slope);
let y_pos = a_slope * x_pos + a_intercept;

(x_pos.is_normal()
&& y_pos.is_normal()
&& !(self.vel.x() > 0.0 && x_pos < self.pos.x())
&& !(self.vel.x() < 0.0 && x_pos > self.pos.x())
&& !(other.vel.x() > 0.0 && x_pos < other.pos.x())
&& !(other.vel.x() < 0.0 && x_pos > other.pos.x()))
.then(|| vector!(x_pos, y_pos))
}
}

fn parse(input: &str) -> Vec<HailStone> {
let mut out = Vec::new();

for line in input.lines() {
let parts = line.split_whitespace().collect::<Vec<_>>();
let parse = |i| {
parts[i as usize]
.trim_end_matches(',')
.parse::<f64>()
.unwrap()
};
out.push(HailStone {
pos: vector!(parse(0), parse(1), parse(2)),
vel: vector!(parse(4), parse(5), parse(6)),
});
}

out
}

#[cfg(test)]
mod test {
use common::Solution;
use indoc::indoc;

use super::Day24;

const CASE: &str = indoc! {"
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 part_a() {
assert_eq!(Day24.part_a(CASE), 0.into());
}

#[test]
fn part_b() {
assert_eq!(Day24.part_b(CASE), ().into());
}
}
2 changes: 2 additions & 0 deletions aoc_2023/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ mod day_20;
mod day_21;
mod day_22;
mod day_23;
mod day_24;
// [import_marker]

#[rustfmt::skip]
Expand Down Expand Up @@ -52,5 +53,6 @@ pub const ALL: &[&dyn Solution] = &[
&day_21::Day21,
&day_22::Day22,
&day_23::Day23,
&day_24::Day24,
// [list_marker]
];

0 comments on commit 51dec13

Please sign in to comment.