1
0
Fork 0

Compare commits

..

2 commits

Author SHA1 Message Date
f523a094c8
Solve 09.1 2025-12-09 07:55:00 +01:00
4e506cafe9
Clean up 08 2025-12-09 07:54:31 +01:00
4 changed files with 173 additions and 4 deletions

37
Cargo.lock generated
View file

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

View file

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

View file

@ -46,8 +46,8 @@ fn part2(input: &str) -> usize {
} }
fn connect(mut circuits: Vec<Circuit>, (a, b): (JBox, JBox)) -> Vec<Circuit> { fn connect(mut circuits: Vec<Circuit>, (a, b): (JBox, JBox)) -> Vec<Circuit> {
let with_a = circuits.iter_mut().position(|c| c.contains(&a)); let with_a = circuits.iter().position(|c| c.contains(&a));
let with_b = circuits.iter_mut().position(|c| c.contains(&b)); let with_b = circuits.iter().position(|c| c.contains(&b));
match (with_a, with_b) { match (with_a, with_b) {
(Some(with_a), Some(with_b)) => { (Some(with_a), Some(with_b)) => {
// Merge into with_a. with_b will be empty, but whatever. // Merge into with_a. with_b will be empty, but whatever.
@ -71,8 +71,7 @@ fn pairs(boxes: &[JBox]) -> impl Iterator<Item = (JBox, JBox)> + use<'_> {
boxes boxes
.iter() .iter()
.copied() .copied()
.combinations(2) .tuple_combinations()
.map(|v| (v[0], v[1]))
.sorted_by_key(|&(a, b)| distance(a, b)) .sorted_by_key(|&(a, b)| distance(a, b))
} }

132
src/bin/09.rs Normal file
View 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())
}