day 18 solution
parent
e39af55e73
commit
86f39513b0
|
@ -0,0 +1,123 @@
|
||||||
|
use aoc_parse::{parser, prelude::*};
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use std::ops::{Add, Div};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum Dir {
|
||||||
|
N,
|
||||||
|
E,
|
||||||
|
S,
|
||||||
|
W,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Move {
|
||||||
|
dir: Dir,
|
||||||
|
count: usize,
|
||||||
|
color: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc_generator(day18)]
|
||||||
|
fn parse(input: &str) -> Vec<Move> {
|
||||||
|
let p = parser!(lines({ "U" => Dir::N, "R" => Dir::E, "D" => Dir::S, "L" => Dir::W } " " usize " (#" string(digit_hex+) ")"));
|
||||||
|
p.parse(input)
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|e| Move {
|
||||||
|
dir: e.0,
|
||||||
|
count: e.1,
|
||||||
|
color: e.2.clone(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_perimeter(moves: &[Move]) -> Vec<(isize, isize)> {
|
||||||
|
let mut c: (isize, isize) = (0, 0);
|
||||||
|
let mut r: Vec<(isize, isize)> = vec![];
|
||||||
|
r.push(c);
|
||||||
|
for m in moves.iter() {
|
||||||
|
match m.dir {
|
||||||
|
Dir::N => c.0 -= m.count as isize,
|
||||||
|
Dir::E => c.1 += m.count as isize,
|
||||||
|
Dir::S => c.0 += m.count as isize,
|
||||||
|
Dir::W => c.1 -= m.count as isize,
|
||||||
|
};
|
||||||
|
r.push(c);
|
||||||
|
}
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
fn distance(s: &(isize, isize), d: &(isize, isize)) -> usize {
|
||||||
|
s.0.abs_diff(d.0) + s.1.abs_diff(d.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shoelace(coords: &[(isize, isize)]) -> isize {
|
||||||
|
let len = coords.len();
|
||||||
|
let (area, perimeter) =
|
||||||
|
coords
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.fold((0isize, 0isize), |(sum, perimeter), (index, c)| {
|
||||||
|
let c2 = coords[(index + 1) % len];
|
||||||
|
let next_perimeter = perimeter + distance(c, &c2) as isize;
|
||||||
|
let next_area = sum + (c.1 * c2.0) - (c.0 * c2.1);
|
||||||
|
(next_area, next_perimeter)
|
||||||
|
});
|
||||||
|
|
||||||
|
area.abs().add(perimeter).div(2).add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day18, part1)]
|
||||||
|
fn part1(input: &[Move]) -> isize {
|
||||||
|
shoelace(&get_perimeter(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day18, part2)]
|
||||||
|
fn part2(input: &[Move]) -> isize {
|
||||||
|
let moves = input
|
||||||
|
.iter()
|
||||||
|
.map(|m| {
|
||||||
|
let mut s = m.color.clone();
|
||||||
|
let dir = match s.remove(s.len() - 1) {
|
||||||
|
'0' => Dir::E,
|
||||||
|
'1' => Dir::S,
|
||||||
|
'2' => Dir::W,
|
||||||
|
'3' => Dir::N,
|
||||||
|
n @ _ => panic!("parsed wrong number {}", n),
|
||||||
|
};
|
||||||
|
let count = usize::from_str_radix(&s, 16).unwrap();
|
||||||
|
Move {
|
||||||
|
dir,
|
||||||
|
count,
|
||||||
|
color: s,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
shoelace(&get_perimeter(&moves))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SAMPLE_DATA: &'static str = r#"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)"#;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_data() {
|
||||||
|
let input = parse(&SAMPLE_DATA);
|
||||||
|
assert_eq!(part1(&input), 62);
|
||||||
|
assert_eq!(part2(&input), 952408144115);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,5 +17,6 @@ mod day14;
|
||||||
mod day15;
|
mod day15;
|
||||||
mod day16;
|
mod day16;
|
||||||
mod day17;
|
mod day17;
|
||||||
|
mod day18;
|
||||||
|
|
||||||
aoc_lib! { year = 2023 }
|
aoc_lib! { year = 2023 }
|
||||||
|
|
Loading…
Reference in New Issue