Skip to content

Commit

Permalink
Add 2023 Day 18 solution
Browse files Browse the repository at this point in the history
  • Loading branch information
rossmacarthur committed Dec 18, 2023
1 parent cf8ca73 commit aa03e4d
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 2 deletions.
112 changes: 112 additions & 0 deletions 2023/18.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use advent::prelude::*;

fn parse_input(input: &str) -> Vec<(Vector2, Vector2)> {
input
.lines()
.map(|line| {
let re = regex!(r"(?P<dir>[URDL]) (?P<val>\d+) \(#(?P<color>[0-9a-f]{6})\)");
let caps = re.captures(line).unwrap();

let dp1 = {
let d = match &caps["dir"] {
"U" => UP,
"R" => RIGHT,
"D" => DOWN,
"L" => LEFT,
_ => unreachable!(),
};
let v: i64 = caps["val"].parse().unwrap();
d * v
};

let dp2 = {
let color = i64::from_str_radix(&caps["color"], 16).unwrap();
let d = match color % 16 {
0 => RIGHT,
1 => DOWN,
2 => LEFT,
3 => UP,
d => panic!("invalid direction `{d}`"),
};
let v = color / 16;
d * v
};

(dp1, dp2)
})
.collect()
}

fn default_input() -> Vec<(Vector2, Vector2)> {
parse_input(include_input!(2023 / 18))
}

const UP: Vector2 = vector![0, 1];
const RIGHT: Vector2 = vector![1, 0];
const DOWN: Vector2 = vector![0, -1];
const LEFT: Vector2 = vector![-1, 0];

fn solve<I>(plan: I) -> i64
where
I: Iterator<Item = Vector2>,
{
let vertices: Vec<_> = plan
.into_iter()
.scan(vector![0, 0], |p, dp| {
*p += dp;
Some(*p)
})
.collect();

let mut area2 = 0;
let mut perimeter = 0;
for [a, b] in vertices.iter().circular_array_windows() {
area2 += a.x * b.y - a.y * b.x;
perimeter += (b - a).l1_norm();
}

area2.abs() / 2 + (perimeter / 2) + 1
}

fn part1(plan: Vec<(Vector2, Vector2)>) -> i64 {
solve(plan.into_iter().map(|(dp, _)| dp))
}

fn part2(plan: Vec<(Vector2, Vector2)>) -> i64 {
solve(plan.into_iter().map(|(_, dp)| dp))
}

fn main() {
let solution = advent::new(default_input).part(part1).part(part2).build();
solution.cli()
}

#[test]
fn example() {
let input = parse_input(
"\
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)",
);
assert_eq!(part1(input.clone()), 62);
assert_eq!(part2(input), 952408144115);
}

#[test]
fn default() {
let input = default_input();
assert_eq!(part1(input.clone()), 48503);
assert_eq!(part2(input), 148442153147147);
}
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -610,3 +610,7 @@ path = "2023/16.rs"
[[bin]]
name = "202317"
path = "2023/17.rs"

[[bin]]
name = "202318"
path = "2023/18.rs"
4 changes: 2 additions & 2 deletions crates/prelude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ pub use ahash::{HashMap, HashMapExt as _, HashSet, HashSetExt as _};
pub use either::Either;
pub use itermore::{
cartesian_product, IterArrayChunks as _, IterArrayCombinations as _, IterArrayWindows as _,
IterCartesianProduct as _, IterCollectArray as _, IterMinMax as _, IterNextChunk as _,
IterSorted as _,
IterCartesianProduct as _, IterCircularArrayWindows as _, IterCollectArray as _,
IterMinMax as _, IterNextChunk as _, IterSorted as _,
};
pub use itertools_shim::ItertoolsShim;
pub use regex_macro::regex;
Expand Down

0 comments on commit aa03e4d

Please sign in to comment.