From 1e1e22be250ff2c755d15e67a61b899c9c6654e9 Mon Sep 17 00:00:00 2001 From: Kevin Caffrey Date: Mon, 18 Dec 2023 10:47:02 -0500 Subject: [PATCH] day 18 --- README.md | 3 +- data/examples/18.txt | 14 +++++ src/bin/18.rs | 119 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 data/examples/18.txt create mode 100644 src/bin/18.rs diff --git a/README.md b/README.md index 9794559..466ba7a 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | [Day 15](./src/bin/15.rs) | `20.4µs` | `85.9µs` | | [Day 16](./src/bin/16.rs) | `58.3µs` | `1.7ms` | | [Day 17](./src/bin/17.rs) | `1.6ms` | `3.7ms` | +| [Day 18](./src/bin/18.rs) | `8.1µs` | `7.7µs` | -**Total: 14.07ms** +**Total: 14.09ms** --- diff --git a/data/examples/18.txt b/data/examples/18.txt new file mode 100644 index 0000000..fc7612e --- /dev/null +++ b/data/examples/18.txt @@ -0,0 +1,14 @@ +R 6 (#70c710) +D 5 (#0dc571) +L 2 (#5713f0) +D 2 (#d2c081) +R 2 (#59c680) +D 2 (#411b91) +L 5 (#8ceee2) +U 2 (#caa173) +L 1 (#1b58a2) +U 2 (#caa171) +R 2 (#7807d2) +U 3 (#a77fa3) +L 2 (#015232) +U 2 (#7a21e3) diff --git a/src/bin/18.rs b/src/bin/18.rs new file mode 100644 index 0000000..b17530d --- /dev/null +++ b/src/bin/18.rs @@ -0,0 +1,119 @@ +advent_of_code::solution!(18); + +pub fn part_one(input: &str) -> Option { + let mut border_points = 0; + let mut area = 0; + let mut prev = Point::origin(); + for line in input + .as_bytes() + .split(|&ch| ch == b'\n') + .filter(|line| !line.is_empty()) + { + let dir: Direction = line[0].try_into().expect("valid direction"); + let distance = line[2..] + .iter() + .copied() + .take_while(|&ch| ch != b' ') + .fold(0, |acc, ch| acc * 10 + i64::from(ch - b'0')); + let next = prev.move_in_dir(dir, distance); + area += prev.x * next.y - prev.y * next.x; + border_points += distance; + prev = next; + } + area = area.abs() / 2; + Some(area + border_points / 2 + 1) +} + +pub fn part_two(input: &str) -> Option { + let mut border_points = 0; + let mut area = 0; + let mut prev = Point::origin(); + for line in input + .as_bytes() + .split(|&ch| ch == b'\n') + .filter(|line| !line.is_empty()) + { + let hex = &line[line.len() - 7..line.len() - 1]; + let dir: Direction = hex[5].try_into().expect("valid direction"); + let distance = hex[..5] + .iter() + .copied() + .take_while(|&ch| ch != b' ') + .fold(0, |acc, ch| { + acc * 16 + char::from(ch).to_digit(16).unwrap() as i64 + }); + let next = prev.move_in_dir(dir, distance); + area += prev.x * next.y - prev.y * next.x; + border_points += distance; + prev = next; + } + area = area.abs() / 2; + Some(area + border_points / 2 + 1) +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Point { + x: i64, + y: i64, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum Direction { + North, + South, + East, + West, +} + +impl Point { + pub const fn new(x: i64, y: i64) -> Self { + Self { x, y } + } + + pub const fn origin() -> Self { + Self::new(0, 0) + } + + pub const fn move_in_dir(self, dir: Direction, distance: i64) -> Self { + match dir { + Direction::North => Point::new(self.x, self.y - distance), + Direction::South => Point::new(self.x, self.y + distance), + Direction::East => Point::new(self.x + distance, self.y), + Direction::West => Point::new(self.x - distance, self.y), + } + } +} + +#[derive(Debug)] +struct InvalidDirectionError(char); + +impl TryFrom for Direction { + type Error = InvalidDirectionError; + + fn try_from(value: u8) -> Result { + Ok(match value { + b'U' | b'3' => Self::North, + b'D' | b'1' => Self::South, + b'L' | b'2' => Self::West, + b'R' | b'0' => Self::East, + _ => return Err(InvalidDirectionError(char::from(value))), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(62)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(952408144115)); + } +}