diff --git a/.gitignore b/.gitignore index 8b76079..3a5b5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ day00 **/dbg.log **/2 **/.vimdid +**/rust-analyzer.core diff --git a/2020/day12_rain_risk/Cargo.toml b/2020/day12_rain_risk/Cargo.toml new file mode 100644 index 0000000..664bb1b --- /dev/null +++ b/2020/day12_rain_risk/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "day12_rain_risk" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/2020/day12_rain_risk/challenge.txt b/2020/day12_rain_risk/challenge.txt new file mode 100644 index 0000000..17e8a7c --- /dev/null +++ b/2020/day12_rain_risk/challenge.txt @@ -0,0 +1,77 @@ +Your ferry made decent progress toward the island, but the storm came in faster than anyone expected. The ferry needs to take *evasive actions*! + +Unfortunately, the ship's navigation computer seems to be malfunctioning; rather than giving a route directly to safety, it produced extremely circuitous instructions. When the captain uses the [PA system](https://en.wikipedia.org/wiki/Public_address_system) to ask if anyone can help, you quickly volunteer. + +The navigation instructions (your puzzle input) consists of a sequence of single-character *actions* paired with integer input *values*. After staring at them for a few minutes, you work out what they probably mean: + +* Action *`N`* means to move *north* by the given value. +* Action *`S`* means to move *south* by the given value. +* Action *`E`* means to move *east* by the given value. +* Action *`W`* means to move *west* by the given value. +* Action *`L`* means to turn *left* the given number of degrees. +* Action *`R`* means to turn *right* the given number of degrees. +* Action *`F`* means to move *forward* by the given value in the direction the ship is currently facing. + +The ship starts by facing *east*. Only the `L` and `R` actions change the direction the ship is facing. (That is, if the ship is facing east and the next instruction is `N10`, the ship would move north 10 units, but would still move east if the following action were `F`.) + +For example: + +``` +F10 +N3 +F7 +R90 +F11 + +``` + +These instructions would be handled as follows: + +* `F10` would move the ship 10 units east (because the ship starts by facing east) to *east 10, north 0*. +* `N3` would move the ship 3 units north to *east 10, north 3*. +* `F7` would move the ship another 7 units east (because the ship is still facing east) to *east 17, north 3*. +* `R90` would cause the ship to turn right by 90 degrees and face *south*; it remains at *east 17, north 3*. +* `F11` would move the ship 11 units south to *east 17, south 8*. + +At the end of these instructions, the ship's [Manhattan distance](https://en.wikipedia.org/wiki/Manhattan_distance) (sum of the absolute values of its east/west position and its north/south position) from its starting position is `17 + 8` = *`25`*. + +Figure out where the navigation instructions lead. *What is the Manhattan distance between that location and the ship's starting position?* + +Your puzzle answer was `1032`. + +\--- Part Two --- +---------- + +Before you can give the destination to the captain, you realize that the actual action meanings were printed on the back of the instructions the whole time. + +Almost all of the actions indicate how to move a *waypoint* which is relative to the ship's position: + +* Action *`N`* means to move the waypoint *north* by the given value. +* Action *`S`* means to move the waypoint *south* by the given value. +* Action *`E`* means to move the waypoint *east* by the given value. +* Action *`W`* means to move the waypoint *west* by the given value. +* Action *`L`* means to rotate the waypoint around the ship *left* (*counter-clockwise*) the given number of degrees. +* Action *`R`* means to rotate the waypoint around the ship *right* (*clockwise*) the given number of degrees. +* Action *`F`* means to move *forward* to the waypoint a number of times equal to the given value. + +The waypoint starts *10 units east and 1 unit north* relative to the ship. The waypoint is relative to the ship; that is, if the ship moves, the waypoint moves with it. + +For example, using the same instructions as above: + +* `F10` moves the ship to the waypoint 10 times (a total of *100 units east and 10 units north*), leaving the ship at *east 100, north 10*. The waypoint stays 10 units east and 1 unit north of the ship. +* `N3` moves the waypoint 3 units north to *10 units east and 4 units north of the ship*. The ship remains at *east 100, north 10*. +* `F7` moves the ship to the waypoint 7 times (a total of *70 units east and 28 units north*), leaving the ship at *east 170, north 38*. The waypoint stays 10 units east and 4 units north of the ship. +* `R90` rotates the waypoint around the ship clockwise 90 degrees, moving it to *4 units east and 10 units south of the ship*. The ship remains at *east 170, north 38*. +* `F11` moves the ship to the waypoint 11 times (a total of *44 units east and 110 units south*), leaving the ship at *east 214, south 72*. The waypoint stays 4 units east and 10 units south of the ship. + +After these operations, the ship's Manhattan distance from its starting position is `214 + 72` = *`286`*. + +Figure out where the navigation instructions actually lead. *What is the Manhattan distance between that location and the ship's starting position?* + +Your puzzle answer was `156735`. + +Both parts of this puzzle are complete! They provide two gold stars: \*\* + +At this point, you should [return to your Advent calendar](/2020) and try another puzzle. + +If you still want to see it, you can [get your puzzle input](12/input). \ No newline at end of file diff --git a/2020/day12_rain_risk/day12_rain_risk-673.core b/2020/day12_rain_risk/day12_rain_risk-673.core new file mode 100644 index 0000000..4d997e6 Binary files /dev/null and b/2020/day12_rain_risk/day12_rain_risk-673.core differ diff --git a/2020/day12_rain_risk/src/lib.rs b/2020/day12_rain_risk/src/lib.rs new file mode 100644 index 0000000..dce3b39 --- /dev/null +++ b/2020/day12_rain_risk/src/lib.rs @@ -0,0 +1,166 @@ +use core::fmt::Display; +use std::num::ParseIntError; + +#[derive(Debug, PartialEq, Eq)] +pub enum ParseError { + ParseIntError(std::num::ParseIntError), + LineMalformed(String), +} + +impl From 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 Action { + North(isize), + South(isize), + East(isize), + West(isize), + Left(isize), + Right(isize), + Forwd(isize), +} + +impl TryFrom<&str> for Action { + type Error = ParseError; + + fn try_from(value: &str) -> Result { + match value.chars().next() { + Some('N') => Ok(Self::North(value[1..].parse()?)), + Some('S') => Ok(Self::South(value[1..].parse()?)), + Some('E') => Ok(Self::East(value[1..].parse()?)), + Some('W') => Ok(Self::West(value[1..].parse()?)), + Some('L') => Ok(Self::Left(value[1..].parse()?)), + Some('R') => Ok(Self::Right(value[1..].parse()?)), + Some('F') => Ok(Self::Forwd(value[1..].parse()?)), + _ => Err(Self::Error::LineMalformed(value.to_string())), + } + } +} + +struct Ferry { + pos: (isize, isize), + dir: isize, + waypoint: (isize, isize), +} + +impl Default for Ferry { + fn default() -> Self { + Self { + pos: (0, 0), + dir: 0, + waypoint: (10, -1), + } + } +} + +impl Ferry { + fn perform_action(&mut self, action: &Action) { + match action { + Action::North(i) => self.pos.1 -= i, + Action::South(i) => self.pos.1 += i, + Action::East(i) => self.pos.0 += i, + Action::West(i) => self.pos.0 -= i, + Action::Left(i) => self.dir = (self.dir-i) % 360, + Action::Right(i) => self.dir = (self.dir+i) % 360, + Action::Forwd(i) => match self.dir { + -90 | 270 => self.pos.1 -= i, + 90 | -270 => self.pos.1 += i, + 0 => self.pos.0 += i, + 180 | -180 => self.pos.0 -= i, + _ => panic!("Trying to move in unknown direction {}", self.dir), + }, + } + } + + fn perform_waypoint_action(&mut self, action: &Action) { + match action { + Action::North(i) => self.waypoint.1 -= i, + Action::South(i) => self.waypoint.1 += i, + Action::East(i) => self.waypoint.0 += i, + Action::West(i) => self.waypoint.0 -= i, + Action::Left(i) => match i { + 90 => { + let x = self.waypoint.0; + self.waypoint.0 = self.waypoint.1; + self.waypoint.1 = -x; + }, + 180 => { + self.waypoint.0 *= -1; + self.waypoint.1 *= -1; + }, + 270 => { + let x = self.waypoint.0; + self.waypoint.0 = -self.waypoint.1; + self.waypoint.1 = x; + }, + _ => panic!("Trying to turn left by unknown amount {i}"), + }, + Action::Right(i) => match i { + 90 => { + let x = self.waypoint.0; + self.waypoint.0 = -self.waypoint.1; + self.waypoint.1 = x; + }, + 180 => { + self.waypoint.0 *= -1; + self.waypoint.1 *= -1; + }, + 270 => { + let x = self.waypoint.0; + self.waypoint.0 = self.waypoint.1; + self.waypoint.1 = -x; + }, + _ => panic!("Trying to turn right by unknown amount {i}"), + }, + Action::Forwd(i) => { + self.pos.0 += i*self.waypoint.0; + self.pos.1 += i*self.waypoint.1; + }, + } + } +} + +pub fn run(input: &str) -> Result<(usize, usize), ParseError> { + let mut ferry = Ferry::default(); + let actions: Vec<_> = input.lines().map(Action::try_from).collect::, _>>()?; + actions.iter().for_each(|a| ferry.perform_action(a)); + let first = ferry.pos.0.unsigned_abs() + ferry.pos.1.unsigned_abs(); + ferry = Ferry::default(); + actions.iter().for_each(|a| ferry.perform_waypoint_action(a)); + let second = ferry.pos.0.unsigned_abs() + ferry.pos.1.unsigned_abs(); + 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((25, 286))); + } + + #[test] + fn test_challenge() { + let challenge_input = read_file("tests/challenge_input"); + assert_eq!(run(&challenge_input), Ok((1032, 156735))); + } +} diff --git a/2020/day12_rain_risk/tests/challenge_input b/2020/day12_rain_risk/tests/challenge_input new file mode 100644 index 0000000..9ec324e --- /dev/null +++ b/2020/day12_rain_risk/tests/challenge_input @@ -0,0 +1,796 @@ +W1 +L90 +F26 +S3 +W2 +N5 +L180 +S4 +F41 +W1 +F48 +W3 +F44 +F63 +W5 +N3 +E5 +F7 +R180 +W1 +N3 +W3 +R180 +F38 +N1 +E3 +L90 +F49 +S5 +F11 +E1 +R90 +W3 +N4 +E3 +R180 +W5 +F93 +S1 +F67 +L180 +W3 +S5 +N3 +L180 +E1 +N2 +F90 +S3 +W3 +N3 +E1 +F77 +W3 +N3 +L180 +E2 +F25 +N1 +W1 +S1 +E5 +S4 +R180 +W1 +F13 +L90 +W4 +S5 +F13 +N2 +R90 +F89 +R90 +W3 +L90 +W5 +N5 +E4 +S4 +F26 +N1 +R270 +N5 +E5 +L180 +R180 +W4 +R90 +W5 +F49 +S2 +F53 +W5 +L180 +F54 +L90 +N3 +F3 +W5 +R180 +S4 +L90 +F49 +W4 +S5 +F73 +L270 +W1 +S4 +F46 +S4 +W2 +S5 +E4 +N4 +F6 +E4 +S4 +F38 +F4 +E4 +R90 +N1 +W2 +F20 +N3 +F64 +R90 +S3 +W5 +N1 +W4 +N3 +F17 +R90 +F62 +E4 +E2 +F47 +R90 +W1 +N3 +R90 +N2 +R90 +F57 +L270 +N2 +W3 +S5 +W4 +E2 +S5 +F93 +F57 +S1 +L90 +F50 +N2 +F4 +N1 +L90 +F34 +N2 +L90 +N4 +W3 +N5 +R180 +S3 +L90 +W3 +S3 +L90 +F70 +L90 +E1 +F92 +N1 +F96 +F85 +S5 +L90 +W1 +L90 +W1 +F23 +L90 +S1 +R90 +W5 +S5 +F66 +W3 +L180 +W2 +L90 +N2 +E3 +R270 +R270 +N3 +W5 +R90 +S3 +E1 +R90 +F78 +E1 +S1 +R90 +S3 +F52 +S4 +F9 +L90 +W1 +N2 +F8 +R90 +N1 +F63 +E5 +F18 +E3 +F43 +E2 +F10 +R90 +F96 +S5 +F22 +W2 +S5 +F39 +R90 +F38 +S5 +R90 +E3 +L90 +W3 +N2 +F14 +L270 +S4 +F78 +F85 +L90 +N3 +E3 +S3 +F98 +E2 +S2 +F100 +S3 +S3 +W5 +W3 +S5 +F67 +L180 +S2 +E5 +S1 +L90 +N5 +E2 +W2 +R90 +E1 +N2 +L90 +F77 +W1 +F84 +L90 +S2 +E4 +R90 +E1 +R90 +S3 +S4 +F89 +R90 +N1 +E4 +R90 +N1 +F97 +L90 +S1 +W3 +R180 +F70 +S5 +E1 +L180 +W5 +F86 +S3 +F20 +R90 +S1 +W4 +R90 +W1 +F3 +S3 +R90 +F43 +L180 +F81 +E2 +N3 +F16 +L90 +S2 +F17 +E3 +F1 +E4 +F17 +W3 +N3 +W5 +S3 +W4 +F60 +E3 +E1 +S5 +L90 +E2 +S5 +F19 +E2 +R90 +F20 +R180 +S4 +F9 +R90 +N5 +W5 +F56 +N2 +L180 +N1 +E5 +L90 +F15 +W4 +F26 +R90 +W2 +F19 +S3 +W1 +R90 +W5 +R180 +W4 +N2 +F86 +N5 +E3 +W3 +N3 +L270 +W3 +F42 +N5 +W2 +R180 +W2 +R180 +S4 +R90 +F55 +S3 +R90 +S3 +E3 +R90 +F11 +S4 +F38 +W1 +L90 +F8 +R90 +E5 +R90 +W1 +W5 +S2 +F2 +F92 +S3 +F77 +S5 +R90 +F24 +E3 +R90 +N3 +F16 +L270 +W3 +F83 +L270 +E2 +F98 +L180 +F89 +E5 +F98 +S4 +E2 +L90 +N4 +L180 +F57 +S5 +R90 +L90 +S4 +W4 +S5 +S4 +W4 +F43 +N2 +F29 +W3 +R90 +F41 +R90 +N2 +F78 +R90 +E5 +N1 +W2 +F6 +L270 +W5 +F91 +W5 +N1 +S4 +F41 +W4 +F74 +E1 +R90 +N4 +F76 +W4 +S2 +L180 +N2 +R180 +W4 +F79 +R270 +W1 +F92 +W1 +L90 +F71 +N4 +L180 +W4 +F16 +W5 +F84 +S5 +F35 +W4 +R90 +F25 +L180 +N1 +E3 +F15 +S4 +R180 +F46 +S1 +W1 +R180 +E4 +N5 +R90 +S1 +W3 +S3 +L270 +F94 +R180 +N1 +W4 +N5 +W2 +S2 +W3 +F53 +L180 +S3 +F19 +N3 +F54 +L180 +S5 +F8 +S1 +N5 +L90 +E4 +N3 +F28 +R180 +F23 +E1 +L90 +E3 +F6 +W4 +R90 +N1 +F89 +S1 +W2 +S5 +F8 +N3 +F23 +N4 +F5 +L90 +N3 +R90 +W4 +L180 +S3 +F7 +N2 +W3 +R180 +E1 +L180 +S4 +R90 +S1 +F99 +N3 +F96 +W3 +R90 +F73 +W5 +F71 +R180 +S2 +F84 +N4 +F4 +W4 +R90 +F34 +E2 +W2 +F53 +N4 +R90 +N5 +E5 +R90 +F60 +N4 +F28 +S2 +W1 +N4 +F54 +R270 +F45 +S5 +F93 +L90 +F66 +R180 +F92 +N4 +F97 +R90 +W5 +S1 +W5 +F68 +S3 +L90 +E3 +F94 +S4 +F64 +R180 +F18 +N1 +S4 +E5 +E2 +F81 +N1 +L90 +F3 +R90 +F81 +W4 +S4 +E5 +N5 +R270 +E3 +S2 +W1 +L180 +S1 +F84 +W2 +L270 +F6 +N1 +R180 +E5 +F7 +E2 +L180 +E2 +F80 +N1 +L90 +F88 +R90 +W5 +N1 +F71 +R180 +N2 +E2 +R90 +N1 +W1 +L90 +E4 +S4 +L180 +F27 +L90 +F57 +F38 +W5 +L180 +S5 +R90 +S4 +W1 +S3 +L90 +F36 +S1 +W5 +R90 +F65 +R90 +E1 +N4 +E1 +F14 +L90 +F44 +R90 +F34 +S2 +L90 +R180 +F87 +W3 +L90 +F9 +R90 +W3 +L90 +S5 +F69 +S3 +W4 +N4 +F30 +W5 +F15 +R90 +L180 +W4 +F5 +R180 +E1 +F6 +R180 +S1 +F20 +E1 +S2 +E5 +F13 +N5 +F83 +W2 +L270 +E2 +R90 +S5 +F62 +R270 +N4 +R90 +F20 +L90 +N2 +E3 +L90 +F37 +N2 +N2 +F82 +L90 +F23 +E3 +F63 +R180 +F1 +N2 +R90 +F68 +E5 +F75 +R90 +W3 +R180 +E4 +E1 +N3 +R90 +N3 +L180 +F92 +R90 +S4 +F27 +R180 +S4 +L180 +W5 +F70 +S5 +L180 +F89 +R90 +W2 +N3 +F64 +L90 +E1 +L90 +F77 +E4 +F55 +E2 +L90 +W2 +F46 +N2 +R90 +F94 +S5 +R180 +F9 +L180 +S4 +L90 +F25 diff --git a/2020/day12_rain_risk/tests/sample_input b/2020/day12_rain_risk/tests/sample_input new file mode 100644 index 0000000..d382291 --- /dev/null +++ b/2020/day12_rain_risk/tests/sample_input @@ -0,0 +1,5 @@ +F10 +N3 +F7 +R90 +F11