Added Solution for 2021 day 02
This commit is contained in:
parent
19759955b2
commit
028b30f131
5 changed files with 1176 additions and 0 deletions
8
2021/day02_dive/Cargo.toml
Normal file
8
2021/day02_dive/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "day02_dive"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
72
2021/day02_dive/challenge.txt
Normal file
72
2021/day02_dive/challenge.txt
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
Now, you need to figure out how to pilot this thing.
|
||||||
|
|
||||||
|
It seems like the submarine can take a series of commands like `forward 1`, `down 2`, or `up 3`:
|
||||||
|
|
||||||
|
* `forward X` increases the horizontal position by `X` units.
|
||||||
|
* `down X` *increases* the depth by `X` units.
|
||||||
|
* `up X` *decreases* the depth by `X` units.
|
||||||
|
|
||||||
|
Note that since you're on a submarine, `down` and `up` affect your *depth*, and so they have the opposite result of what you might expect.
|
||||||
|
|
||||||
|
The submarine seems to already have a planned course (your puzzle input). You should probably figure out where it's going. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
forward 5
|
||||||
|
down 5
|
||||||
|
forward 8
|
||||||
|
up 3
|
||||||
|
down 8
|
||||||
|
forward 2
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Your horizontal position and depth both start at `0`. The steps above would then modify them as follows:
|
||||||
|
|
||||||
|
* `forward 5` adds `5` to your horizontal position, a total of `5`.
|
||||||
|
* `down 5` adds `5` to your depth, resulting in a value of `5`.
|
||||||
|
* `forward 8` adds `8` to your horizontal position, a total of `13`.
|
||||||
|
* `up 3` decreases your depth by `3`, resulting in a value of `2`.
|
||||||
|
* `down 8` adds `8` to your depth, resulting in a value of `10`.
|
||||||
|
* `forward 2` adds `2` to your horizontal position, a total of `15`.
|
||||||
|
|
||||||
|
After following these instructions, you would have a horizontal position of `15` and a depth of `10`. (Multiplying these together produces `*150*`.)
|
||||||
|
|
||||||
|
Calculate the horizontal position and depth you would have after following the planned course. *What do you get if you multiply your final horizontal position by your final depth?*
|
||||||
|
|
||||||
|
Your puzzle answer was `1714950`.
|
||||||
|
|
||||||
|
\--- Part Two ---
|
||||||
|
----------
|
||||||
|
|
||||||
|
Based on your calculations, the planned course doesn't seem to make any sense. You find the submarine manual and discover that the process is actually slightly more complicated.
|
||||||
|
|
||||||
|
In addition to horizontal position and depth, you'll also need to track a third value, *aim*, which also starts at `0`. The commands also mean something entirely different than you first thought:
|
||||||
|
|
||||||
|
* `down X` *increases* your aim by `X` units.
|
||||||
|
* `up X` *decreases* your aim by `X` units.
|
||||||
|
* `forward X` does two things:
|
||||||
|
* It increases your horizontal position by `X` units.
|
||||||
|
* It increases your depth by your aim *multiplied by* `X`.
|
||||||
|
|
||||||
|
Again note that since you're on a submarine, `down` and `up` do the opposite of what you might expect: "down" means aiming in the positive direction.
|
||||||
|
|
||||||
|
Now, the above example does something different:
|
||||||
|
|
||||||
|
* `forward 5` adds `5` to your horizontal position, a total of `5`. Because your aim is `0`, your depth does not change.
|
||||||
|
* `down 5` adds `5` to your aim, resulting in a value of `5`.
|
||||||
|
* `forward 8` adds `8` to your horizontal position, a total of `13`. Because your aim is `5`, your depth increases by `8*5=40`.
|
||||||
|
* `up 3` decreases your aim by `3`, resulting in a value of `2`.
|
||||||
|
* `down 8` adds `8` to your aim, resulting in a value of `10`.
|
||||||
|
* `forward 2` adds `2` to your horizontal position, a total of `15`. Because your aim is `10`, your depth increases by `2*10=20` to a total of `60`.
|
||||||
|
|
||||||
|
After following these new instructions, you would have a horizontal position of `15` and a depth of `60`. (Multiplying these produces `*900*`.)
|
||||||
|
|
||||||
|
Using this new interpretation of the commands, calculate the horizontal position and depth you would have after following the planned course. *What do you get if you multiply your final horizontal position by your final depth?*
|
||||||
|
|
||||||
|
Your puzzle answer was `1281977850`.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars: \*\*
|
||||||
|
|
||||||
|
At this point, you should [return to your Advent calendar](/2021) and try another puzzle.
|
||||||
|
|
||||||
|
If you still want to see it, you can [get your puzzle input](2/input).
|
90
2021/day02_dive/src/lib.rs
Normal file
90
2021/day02_dive/src/lib.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
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}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Movement {
|
||||||
|
Forward(isize),
|
||||||
|
Down(isize),
|
||||||
|
Up(isize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for Movement {
|
||||||
|
type Error = ParseError;
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
let words: Vec<_> = value.split_whitespace().collect();
|
||||||
|
if words.len() != 2 {
|
||||||
|
Err(Self::Error::LineMalformed(value.to_string()))
|
||||||
|
} else {
|
||||||
|
match words[0] {
|
||||||
|
"forward" => Ok(Self::Forward(words[1].parse()?)),
|
||||||
|
"down" => Ok(Self::Down(words[1].parse()?)),
|
||||||
|
"up" => Ok(Self::Up(words[1].parse()?)),
|
||||||
|
_ => Err(Self::Error::LineMalformed(value.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(input: &str) -> Result<(isize, isize), ParseError> {
|
||||||
|
let course: Vec<_> = input.lines().map(Movement::try_from).collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
// Fold the movements into (horizontal, depth)
|
||||||
|
let target_1 = course.iter().fold((0, 0), |pos, movement| match movement {
|
||||||
|
Movement::Forward(x) => (pos.0 + x, pos.1),
|
||||||
|
Movement::Down(x) => (pos.0, pos.1 + x),
|
||||||
|
Movement::Up(x) => (pos.0, pos.1 - x),
|
||||||
|
});
|
||||||
|
let first = target_1.0 * target_1.1;
|
||||||
|
|
||||||
|
// Now fold into (horizontal, depth, aim)
|
||||||
|
let target_2 = course.iter().fold((0, 0, 0), |pos, movement| match movement {
|
||||||
|
Movement::Forward(x) => (pos.0 + x, pos.1 + pos.2*x, pos.2),
|
||||||
|
Movement::Down(x) => (pos.0, pos.1, pos.2 + x),
|
||||||
|
Movement::Up(x) => (pos.0, pos.1, pos.2 - x),
|
||||||
|
});
|
||||||
|
let second = target_2.0 * target_2.1;
|
||||||
|
Ok((first, second))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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");
|
||||||
|
assert_eq!(run(&sample_input), Ok((150, 900)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_challenge() {
|
||||||
|
let challenge_input = read_file("tests/challenge_input");
|
||||||
|
assert_eq!(run(&challenge_input), Ok((1714950, 1281977850)));
|
||||||
|
}
|
||||||
|
}
|
1000
2021/day02_dive/tests/challenge_input
Normal file
1000
2021/day02_dive/tests/challenge_input
Normal file
File diff suppressed because it is too large
Load diff
6
2021/day02_dive/tests/sample_input
Normal file
6
2021/day02_dive/tests/sample_input
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
forward 5
|
||||||
|
down 5
|
||||||
|
forward 8
|
||||||
|
up 3
|
||||||
|
down 8
|
||||||
|
forward 2
|
Loading…
Add table
Add a link
Reference in a new issue