Solve 09.1
This commit is contained in:
parent
4e506cafe9
commit
f523a094c8
3 changed files with 170 additions and 0 deletions
37
Cargo.lock
generated
37
Cargo.lock
generated
|
|
@ -32,6 +32,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cached",
|
"cached",
|
||||||
|
"derive_more",
|
||||||
"glam",
|
"glam",
|
||||||
"itertools",
|
"itertools",
|
||||||
]
|
]
|
||||||
|
|
@ -116,6 +117,27 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
|
||||||
|
dependencies = [
|
||||||
|
"derive_more-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more-impl"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
|
@ -206,12 +228,27 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.22"
|
version = "1.0.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,6 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.100"
|
anyhow = "1.0.100"
|
||||||
cached = "0.56.0"
|
cached = "0.56.0"
|
||||||
|
derive_more = { version = "2.1.0", features = ["deref"] }
|
||||||
glam = "0.30.9"
|
glam = "0.30.9"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
|
|
|
||||||
132
src/bin/09.rs
Normal file
132
src/bin/09.rs
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
use aoc::*;
|
||||||
|
use derive_more::Deref;
|
||||||
|
use glam::U64Vec2;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../../input/09");
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Part 1: {}", part1(INPUT));
|
||||||
|
println!("Part 2: {}", part2(INPUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example() {
|
||||||
|
assert_example!(part1, "09-test", 50);
|
||||||
|
assert!(Line(U64Vec2::new(0, 10), U64Vec2::ZERO).contains(U64Vec2::new(0, 0)));
|
||||||
|
assert!(Line(U64Vec2::new(0, 10), U64Vec2::ZERO).contains(U64Vec2::new(0, 10)));
|
||||||
|
assert!(!Line(U64Vec2::new(0, 10), U64Vec2::ZERO).contains(U64Vec2::new(0, 11)));
|
||||||
|
assert!(!Line(U64Vec2::new(0, 10), U64Vec2::ZERO).contains(U64Vec2::new(1, 10)));
|
||||||
|
assert_example!(part2, "09-test", 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> u64 {
|
||||||
|
Polygon::parse(input)
|
||||||
|
.0
|
||||||
|
.into_iter()
|
||||||
|
.tuple_combinations()
|
||||||
|
.map(Rect::from)
|
||||||
|
.map(Rect::area)
|
||||||
|
.max()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str) -> u64 {
|
||||||
|
let polygon = Polygon::parse(input);
|
||||||
|
polygon
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.tuple_combinations()
|
||||||
|
.map(Rect::from)
|
||||||
|
.filter(|&r| polygon.contains_rect(r))
|
||||||
|
.map(Rect::area)
|
||||||
|
.max()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deref)]
|
||||||
|
struct Polygon(Vec<U64Vec2>);
|
||||||
|
|
||||||
|
impl Polygon {
|
||||||
|
fn parse(input: &str) -> Self {
|
||||||
|
Self(input.lines().map(parse_line).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains_rect(&self, r: Rect) -> bool {
|
||||||
|
r.all_points().into_iter().all(|p| self.contains_point(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raycast from left to right and check intersections with lines.
|
||||||
|
fn contains_point(&self, p: U64Vec2) -> bool {
|
||||||
|
let lines = self.lines();
|
||||||
|
let is_on_line = |p| lines.iter().any(|line| line.contains(p));
|
||||||
|
|
||||||
|
let mut inside = false;
|
||||||
|
let mut was_on_line = false;
|
||||||
|
|
||||||
|
for x in 0..=p.x {
|
||||||
|
let check = U64Vec2::new(x, p.y);
|
||||||
|
let is_on_line = is_on_line(check);
|
||||||
|
let crossed = !is_on_line && was_on_line;
|
||||||
|
if crossed {
|
||||||
|
inside ^= true;
|
||||||
|
}
|
||||||
|
was_on_line = is_on_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
inside || was_on_line
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lines(&self) -> Vec<Line> {
|
||||||
|
self.iter()
|
||||||
|
.chain(self.first()) // close the loop
|
||||||
|
.copied()
|
||||||
|
.tuple_combinations()
|
||||||
|
.map(|(a, b)| Line(a, b))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Line(U64Vec2, U64Vec2);
|
||||||
|
|
||||||
|
impl Line {
|
||||||
|
/// true if p on Line(a, b)
|
||||||
|
fn contains(&self, p: U64Vec2) -> bool {
|
||||||
|
let a = self.0.sub(p).length_squared();
|
||||||
|
let b = self.1.sub(p).length_squared();
|
||||||
|
let c = self.0.sub(self.1).length_squared();
|
||||||
|
a + b == c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct Rect(U64Vec2, U64Vec2);
|
||||||
|
|
||||||
|
impl Rect {
|
||||||
|
fn area(self) -> u64 {
|
||||||
|
(self.0.x.abs_diff(self.1.x) + 1) * (self.0.y.abs_diff(self.1.y) + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from((a, b): (U64Vec2, U64Vec2)) -> Self {
|
||||||
|
Self(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_points(self) -> Vec<U64Vec2> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
for x in self.0.x.min(self.1.x)..=self.0.x.max(self.1.x) {
|
||||||
|
for y in self.0.y.min(self.1.y)..=self.0.y.max(self.1.y) {
|
||||||
|
result.push(U64Vec2::new(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_line(line: &str) -> U64Vec2 {
|
||||||
|
let (x, y) = line.split_once(',').unwrap();
|
||||||
|
U64Vec2::new(x.parse().unwrap(), y.parse().unwrap())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue