generated from janezicmatej/aoc-template
solution: day 18
This commit is contained in:
parent
0000033086
commit
0000034077
|
@ -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)
|
|
@ -0,0 +1,126 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ParseDirectionError;
|
||||
|
||||
impl FromStr for Direction {
|
||||
type Err = ParseDirectionError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
use Direction::*;
|
||||
|
||||
Ok(match s {
|
||||
"U" | "3" => Up,
|
||||
"D" | "1" => Down,
|
||||
"L" | "2" => Left,
|
||||
"R" | "0" => Right,
|
||||
_ => return Err(ParseDirectionError),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Direction> for (isize, isize) {
|
||||
fn from(value: Direction) -> Self {
|
||||
use Direction::*;
|
||||
match value {
|
||||
Up => (-1, 0),
|
||||
Down => (1, 0),
|
||||
Left => (0, -1),
|
||||
Right => (0, 1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_area(border: &[(isize, isize)], border_length: isize) -> isize {
|
||||
// get area with shoelace formula (trapezoid variant)
|
||||
// https://en.wikipedia.org/wiki/Shoelace_formula
|
||||
let mut shoelace: isize = 0;
|
||||
for n in 0..border.len() {
|
||||
let (y1, x1) = border[n];
|
||||
let (y2, x2) = border[(n + 1) % border.len()];
|
||||
shoelace += (y1 + y2) * (x1 - x2);
|
||||
}
|
||||
let area = shoelace / 2;
|
||||
|
||||
// get interior by inverting pick's theorem formula
|
||||
// https://en.wikipedia.org/wiki/Pick%27s_theorem
|
||||
let interior = area + 1 - border_length / 2;
|
||||
interior + border_length
|
||||
}
|
||||
|
||||
fn get_border(instructions: &[(Direction, isize)]) -> (Vec<(isize, isize)>, isize) {
|
||||
let mut border = Vec::new();
|
||||
let mut border_length = 0;
|
||||
let (mut sy, mut sx) = (0, 0);
|
||||
border.push((sy, sx));
|
||||
|
||||
for (d, l) in instructions.iter().copied() {
|
||||
let (dy, dx) = d.into();
|
||||
(sy, sx) = (sy + l * dy, sx + l * dx);
|
||||
border.push((sy, sx));
|
||||
border_length += l;
|
||||
}
|
||||
|
||||
border.pop();
|
||||
|
||||
(border, border_length)
|
||||
}
|
||||
|
||||
pub fn part_one(input: &str) -> Option<isize> {
|
||||
let instructions: Vec<(Direction, isize)> = input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let [d, l, _] = line.splitn(3, ' ').collect::<Vec<_>>().try_into().unwrap();
|
||||
(d.parse().unwrap(), l.parse::<isize>().unwrap())
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (border, border_length) = get_border(&instructions);
|
||||
Some(get_area(&border, border_length))
|
||||
}
|
||||
|
||||
fn join_option_tuple<T, U>((a, b): (Option<T>, Option<U>)) -> Option<(T, U)> {
|
||||
Some((a?, b?))
|
||||
}
|
||||
|
||||
pub fn part_two(input: &str) -> Option<isize> {
|
||||
let instructions: Vec<(Direction, isize)> = input
|
||||
.lines()
|
||||
.filter_map(|line| line.split_once(" (#"))
|
||||
.filter_map(|(_, h)| h.strip_suffix(')'))
|
||||
.map(|h| h.split_at(h.len() - 1))
|
||||
.map(|(hex, dir)| (dir.parse().ok(), isize::from_str_radix(hex, 16).ok()))
|
||||
.filter_map(join_option_tuple)
|
||||
.collect();
|
||||
|
||||
let (border, border_length) = get_border(&instructions);
|
||||
Some(get_area(&border, border_length))
|
||||
}
|
||||
|
||||
aoc::solution!(18);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_part_one() {
|
||||
assert_eq!(
|
||||
part_one(&aoc::template::read_file("examples", 18)),
|
||||
Some(62)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_part_two() {
|
||||
assert_eq!(
|
||||
part_two(&aoc::template::read_file("examples", 18)),
|
||||
Some(952408144115)
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue