optimize 2023/18

This commit is contained in:
kageru 2023-12-18 14:57:40 +01:00
parent 9779f22040
commit 808360a58f

View File

@ -6,8 +6,8 @@ use aoc2023::{
direction::Direction::{self, *}, direction::Direction::{self, *},
position::{Position2D, PositionND}, position::{Position2D, PositionND},
}; };
use fnv::FnvHashSet as HashSet; use itertools::Itertools;
use itertools::{Itertools, MinMaxResult}; use std::ops::Div;
const DAY: usize = 18; const DAY: usize = 18;
type I = isize; type I = isize;
@ -30,50 +30,26 @@ fn parse_input(raw: &str) -> Parsed {
.collect() .collect()
} }
fn part1(instructions: &Parsed) -> usize { fn part1(instructions: &Parsed) -> isize {
let mut edges = Vec::new(); let n_points: I = instructions.iter().map(|(_, len, _)| len).sum();
let mut points = HashSet::default(); let points: Vec<_> = instructions
let mut pos = PositionND([0, 0]); .iter()
points.insert(pos); .scan(PositionND([0, 0]), |pos, &(dir, len, _)| {
edges.push(pos); let movement = PositionND(match dir {
for &(dir, len, _) in instructions { Up => [len, 0],
let movement = PositionND(match dir { Down => [-len, 0],
Up => [1, 0], Right => [0, len],
Down => [-1, 0], Left => [0, -len],
Right => [0, 1], });
Left => [0, -1], *pos += movement;
}); Some(*pos)
for _ in 0..len { })
pos += movement; .collect();
points.insert(pos); (2 * area(&points) - n_points + 2) / 2 + n_points
}
edges.push(pos);
}
let MinMaxResult::MinMax(xmin, xmax) = edges.iter().map(|p| p[0]).minmax() else { unreachable!() };
let MinMaxResult::MinMax(ymin, ymax) = edges.iter().map(|p| p[1]).minmax() else { unreachable!() };
let mut count = 0;
for x in xmin..=xmax {
for y in ymin..=ymax {
let p = PositionND([x, y]);
if points.contains(&p) || is_inside(&p, &edges) {
count += 1;
}
}
}
count
} }
// copied from day 10 fn area(polygon: &[Pos]) -> isize {
fn is_inside(p: &Pos, polygon: &[Pos]) -> bool { polygon.iter().zip(polygon.iter().cycle().skip(1)).map(|(p1, p2)| p1[0] * p2[1] - p1[1] * p2[0]).sum::<I>().abs().div(2)
// Zip with next and wrap for the last element
polygon
.iter()
.zip(polygon.iter().cycle().skip(1))
.filter(|(p1, p2)| p[1] > p1[1].min(p2[1]) && p[1] <= p1[1].max(p2[1]) && p[0] <= p1[0].max(p2[0]) && p1[1] != p2[1])
.filter(|(p1, p2)| p1[0] == p2[0] || p[0] <= (p[1] - p1[1]) * (p2[0] - p1[0]) / (p2[1] - p1[1]) + p1[0])
.count()
& 1
== 1
} }
fn part2(parsed: &Parsed) -> usize { fn part2(parsed: &Parsed) -> usize {
@ -100,6 +76,16 @@ U 2 (#7a21e3)"
part1: { TEST_INPUT => 62 }, part1: { TEST_INPUT => 62 },
part2: { TEST_INPUT => 0 }, part2: { TEST_INPUT => 0 },
}, },
unittests: {
area: {
&[
PositionND([0, 0]),
PositionND([0, 2]),
PositionND([2, 2]),
PositionND([2, 0]),
] => 4
}
},
bench1 == 35991, bench1 == 35991,
bench2 == 0, bench2 == 0,
bench_parse: Vec::len => 602, bench_parse: Vec::len => 602,