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 day16;
|
||||
mod day17;
|
||||
mod day18;
|
||||
|
||||
aoc_lib! { year = 2023 }
|
||||
|
|
Loading…
Reference in New Issue