Skip to content

Commit

Permalink
day 18
Browse files Browse the repository at this point in the history
  • Loading branch information
kcaffrey committed Dec 18, 2023
1 parent 80e8e19 commit 1e1e22b
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**
<!--- benchmarking table --->

---
Expand Down
14 changes: 14 additions & 0 deletions data/examples/18.txt
Original file line number Diff line number Diff line change
@@ -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)
119 changes: 119 additions & 0 deletions src/bin/18.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
advent_of_code::solution!(18);

pub fn part_one(input: &str) -> Option<i64> {
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<i64> {
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<u8> for Direction {
type Error = InvalidDirectionError;

fn try_from(value: u8) -> Result<Self, Self::Error> {
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));
}
}

0 comments on commit 1e1e22b

Please sign in to comment.