Added Solution for 2021 day 17
This commit is contained in:
parent
cda358ee23
commit
1b5424b94f
6 changed files with 256 additions and 0 deletions
8
2021/day17_trick_shot/Cargo.toml
Normal file
8
2021/day17_trick_shot/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "day17_trick_shot"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
123
2021/day17_trick_shot/challenge.txt
Normal file
123
2021/day17_trick_shot/challenge.txt
Normal file
|
@ -0,0 +1,123 @@
|
|||
You finally decode the Elves' message. `HI`, the message says. You continue searching for the sleigh keys.
|
||||
|
||||
Ahead of you is what appears to be a large [ocean trench](https://en.wikipedia.org/wiki/Oceanic_trench). Could the keys have fallen into it? You'd better send a probe to investigate.
|
||||
|
||||
The probe launcher on your submarine can fire the probe with any [integer](https://en.wikipedia.org/wiki/Integer) velocity in the `x` (forward) and `y` (upward, or downward if negative) directions. For example, an initial `x,y` velocity like `0,10` would fire the probe straight up, while an initial velocity like `10,-1` would fire the probe forward at a slight downward angle.
|
||||
|
||||
The probe's `x,y` position starts at `0,0`. Then, it will follow some trajectory by moving in *steps*. On each step, these changes occur in the following order:
|
||||
|
||||
* The probe's `x` position increases by its `x` velocity.
|
||||
* The probe's `y` position increases by its `y` velocity.
|
||||
* Due to drag, the probe's `x` velocity changes by `1` toward the value `0`; that is, it decreases by `1` if it is greater than `0`, increases by `1` if it is less than `0`, or does not change if it is already `0`.
|
||||
* Due to gravity, the probe's `y` velocity decreases by `1`.
|
||||
|
||||
For the probe to successfully make it into the trench, the probe must be on some trajectory that causes it to be within a *target area* after any step. The submarine computer has already calculated this target area (your puzzle input). For example:
|
||||
|
||||
```
|
||||
target area: x=20..30, y=-10..-5
|
||||
```
|
||||
|
||||
This target area means that you need to find initial `x,y` velocity values such that after any step, the probe's `x` position is at least `20` and at most `30`, *and* the probe's `y` position is at least `-10` and at most `-5`.
|
||||
|
||||
Given this target area, one initial velocity that causes the probe to be within the target area after any step is `7,2`:
|
||||
|
||||
```
|
||||
.............#....#............
|
||||
.......#..............#........
|
||||
...............................
|
||||
S........................#.....
|
||||
...............................
|
||||
...............................
|
||||
...........................#...
|
||||
...............................
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTT#TT
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
|
||||
```
|
||||
|
||||
In this diagram, `S` is the probe's initial position, `0,0`. The `x` coordinate increases to the right, and the `y` coordinate increases upward. In the bottom right, positions that are within the target area are shown as `T`. After each step (until the target area is reached), the position of the probe is marked with `#`. (The bottom-right `#` is both a position the probe reaches and a position in the target area.)
|
||||
|
||||
Another initial velocity that causes the probe to be within the target area after any step is `6,3`:
|
||||
|
||||
```
|
||||
...............#..#............
|
||||
...........#........#..........
|
||||
...............................
|
||||
......#..............#.........
|
||||
...............................
|
||||
...............................
|
||||
S....................#.........
|
||||
...............................
|
||||
...............................
|
||||
...............................
|
||||
.....................#.........
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
....................T#TTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
|
||||
```
|
||||
|
||||
Another one is `9,0`:
|
||||
|
||||
```
|
||||
S........#.....................
|
||||
.................#.............
|
||||
...............................
|
||||
........................#......
|
||||
...............................
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTT#
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
....................TTTTTTTTTTT
|
||||
|
||||
```
|
||||
|
||||
One initial velocity that *doesn't* cause the probe to be within the target area after any step is `17,-4`:
|
||||
|
||||
```
|
||||
S..............................................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
.................#.............................................
|
||||
....................TTTTTTTTTTT................................
|
||||
....................TTTTTTTTTTT................................
|
||||
....................TTTTTTTTTTT................................
|
||||
....................TTTTTTTTTTT................................
|
||||
....................TTTTTTTTTTT..#.............................
|
||||
....................TTTTTTTTTTT................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
................................................#..............
|
||||
...............................................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
...............................................................
|
||||
..............................................................#
|
||||
|
||||
```
|
||||
|
||||
The probe appears to pass through the target area, but is never within it after any step. Instead, it continues down and to the right - only the first few steps are shown.
|
||||
|
||||
If you're going to fire a highly scientific probe out of a super cool probe launcher, you might as well do it with *style*. How high can you make the probe go while still reaching the target area?
|
||||
|
||||
In the above example, using an initial velocity of `6,9` is the best you can do, causing the probe to reach a maximum `y` position of `*45*`. (Any higher initial `y` velocity causes the probe to overshoot the target area entirely.)
|
||||
|
||||
Find the initial velocity that causes the probe to reach the highest `y` position and still eventually be within the target area after any step. *What is the highest `y` position it reaches on this trajectory?*
|
||||
|
||||
To begin, [get your puzzle input](17/input).
|
||||
|
||||
Answer:
|
BIN
2021/day17_trick_shot/day17_trick_shot-f4.core
Normal file
BIN
2021/day17_trick_shot/day17_trick_shot-f4.core
Normal file
Binary file not shown.
123
2021/day17_trick_shot/src/lib.rs
Normal file
123
2021/day17_trick_shot/src/lib.rs
Normal file
|
@ -0,0 +1,123 @@
|
|||
use core::fmt::Display;
|
||||
use std::num::ParseIntError;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ParseError {
|
||||
ParseIntError(std::num::ParseIntError),
|
||||
LineMalformed(String),
|
||||
}
|
||||
|
||||
impl From<ParseIntError> for ParseError {
|
||||
fn from(value: ParseIntError) -> Self {
|
||||
Self::ParseIntError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ParseIntError(e) => write!(f, "Unable to parse into integer: {e}"),
|
||||
Self::LineMalformed(v) => write!(f, "Line is malformed: {v}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Area {
|
||||
x_min: isize,
|
||||
x_max: isize,
|
||||
y_min: isize,
|
||||
y_max: isize,
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Area {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
let components: Vec<_> = value.split(&[' ', ',']).collect();
|
||||
if components.len() == 5 {
|
||||
let x: Vec<_> = components[2].split(&['.', '=']).collect();
|
||||
let y: Vec<_> = components[4].split(&['.', '=']).collect();
|
||||
if x.len() == 4 && y.len() == 4 {
|
||||
Ok(Self {
|
||||
x_min: x[1].parse()?,
|
||||
x_max: x[3].parse()?,
|
||||
y_min: y[1].parse()?,
|
||||
y_max: y[3].parse()?,
|
||||
})
|
||||
} else {
|
||||
Err(Self::Error::LineMalformed(value.to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(Self::Error::LineMalformed(value.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(input: &str) -> Result<(isize, usize), ParseError> {
|
||||
let target = Area::try_from(input)?;
|
||||
let mut max_y = 0;
|
||||
let mut hits = 0;
|
||||
for y in target.y_min..-target.y_min {
|
||||
for x in 1..=target.x_max {
|
||||
let attempt = launch((0, 0), (x, y), &target, 0);
|
||||
if attempt.0 {
|
||||
max_y = max_y.max(attempt.1);
|
||||
hits += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
let first = max_y;
|
||||
let second = hits;
|
||||
Ok((first, second))
|
||||
}
|
||||
|
||||
fn launch((x, y): (isize, isize), (x_vel, y_vel): (isize, isize), target: &Area, max_y: isize) -> (bool, isize) {
|
||||
if (target.x_min..=target.x_max).contains(&x) && (target.y_min..=target.y_max).contains(&y) {
|
||||
(true, max_y)
|
||||
} else if x_vel >= 0 && target.x_max < x ||
|
||||
x_vel <= 0 && target.x_min > x ||
|
||||
y_vel <= 0 && target.y_min > y {
|
||||
(false, 0)
|
||||
} else if x_vel > 0 {
|
||||
launch((x+x_vel, y+y_vel), (x_vel-1, y_vel-1), target, max_y.max(y+y_vel))
|
||||
} else if x_vel < 0 {
|
||||
launch((x+x_vel, y+y_vel), (x_vel+1, y_vel-1), target, max_y.max(y+y_vel))
|
||||
} else {
|
||||
launch((x+x_vel, y+y_vel), (0, y_vel-1), target, max_y.max(y+y_vel))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fs::read_to_string;
|
||||
|
||||
fn read_file(name: &str) -> String {
|
||||
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sample() {
|
||||
let sample_input = read_file("tests/sample_input");
|
||||
let target = Area::try_from(&sample_input[..]).unwrap();
|
||||
let should_hit = [
|
||||
(7, 2),
|
||||
(6, 3),
|
||||
(9, 0),
|
||||
];
|
||||
let should_miss = [ (17, -4) ];
|
||||
for vel in should_hit {
|
||||
assert!(launch((0, 0), vel, &target, 0).0);
|
||||
}
|
||||
for vel in should_miss {
|
||||
assert!(!launch((0, 0), vel, &target, 0).0);
|
||||
}
|
||||
assert_eq!(run(&sample_input), Ok((45, 112)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_challenge() {
|
||||
let challenge_input = read_file("tests/challenge_input");
|
||||
assert_eq!(run(&challenge_input), Ok((6903, 2351)));
|
||||
}
|
||||
}
|
1
2021/day17_trick_shot/tests/challenge_input
Normal file
1
2021/day17_trick_shot/tests/challenge_input
Normal file
|
@ -0,0 +1 @@
|
|||
target area: x=235..259, y=-118..-62
|
1
2021/day17_trick_shot/tests/sample_input
Normal file
1
2021/day17_trick_shot/tests/sample_input
Normal file
|
@ -0,0 +1 @@
|
|||
target area: x=20..30, y=-10..-5
|
Loading…
Add table
Add a link
Reference in a new issue