1
0
Fork 0

day 18 solution

main
Andrew Coleman 2024-01-04 16:08:19 -05:00
parent e39af55e73
commit 86f39513b0
2 changed files with 124 additions and 0 deletions

123
2023/src/day18.rs Normal file
View File

@ -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);
}
}

View File

@ -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 }