optimize 2023/18
This commit is contained in:
parent
9779f22040
commit
808360a58f
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user