day9: still not working but corner-based algorithm
This commit is contained in:
303
Cargo.lock
generated
303
Cargo.lock
generated
@@ -66,9 +66,12 @@ dependencies = [
|
||||
"aoc-runner-derive",
|
||||
"cached",
|
||||
"grid",
|
||||
"indicatif",
|
||||
"itertools",
|
||||
"misc",
|
||||
"rayon",
|
||||
"regex",
|
||||
"rstest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -92,7 +95,7 @@ dependencies = [
|
||||
"ahash",
|
||||
"cached_proc_macro",
|
||||
"cached_proc_macro_types",
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.5",
|
||||
"once_cell",
|
||||
"thiserror",
|
||||
"web-time",
|
||||
@@ -122,6 +125,44 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
@@ -163,6 +204,12 @@ version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -181,6 +228,55 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "grid"
|
||||
version = "0.1.0"
|
||||
@@ -196,12 +292,42 @@ dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.18.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88"
|
||||
dependencies = [
|
||||
"console",
|
||||
"portable-atomic",
|
||||
"rayon",
|
||||
"unicode-width",
|
||||
"unit-prefix",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intrusive-collections"
|
||||
version = "0.9.7"
|
||||
@@ -236,6 +362,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.178"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
@@ -274,6 +406,33 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
@@ -292,6 +451,26 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.2"
|
||||
@@ -321,6 +500,50 @@ version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "relative-path"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
|
||||
|
||||
[[package]]
|
||||
name = "rstest"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49"
|
||||
dependencies = [
|
||||
"futures-timer",
|
||||
"futures-util",
|
||||
"rstest_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rstest_macros"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"glob",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"relative-path",
|
||||
"rustc_version",
|
||||
"syn 2.0.111",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
@@ -333,6 +556,12 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
@@ -375,6 +604,12 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
@@ -423,12 +658,54 @@ dependencies = [
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.23.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"toml_parser",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "unit-prefix"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
@@ -490,6 +767,30 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.31"
|
||||
|
||||
@@ -8,9 +8,12 @@ aoc-runner = "0.3.0"
|
||||
aoc-runner-derive = "0.3.0"
|
||||
cached = "0.56.0"
|
||||
grid = {version = "0.1.0", path = "utils/grid"}
|
||||
indicatif = { version = "0.18.3", features = ["rayon"] }
|
||||
itertools = "0.14.0"
|
||||
misc = {path = "utils/misc"}
|
||||
rayon = "1.11.0"
|
||||
regex = "1.11.1"
|
||||
rstest = "0.26.1"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
380
src/day9.rs
380
src/day9.rs
@@ -1,11 +1,24 @@
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
use grid::{AsCoord2d, Coord2d, Grid};
|
||||
use indicatif::{ParallelProgressIterator, ProgressIterator, ProgressStyle};
|
||||
use itertools::Itertools;
|
||||
use std::cmp::{max, min};
|
||||
use rayon::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::{
|
||||
cmp::{max, min},
|
||||
fmt::Display,
|
||||
};
|
||||
|
||||
#[aoc_generator(day9, part1)]
|
||||
#[aoc_generator(day9)]
|
||||
fn parse(input: &str) -> Vec<Coord2d> {
|
||||
input.lines().map(|l| l.parse().unwrap()).collect()
|
||||
input
|
||||
.lines()
|
||||
.map(|l| l.parse::<Coord2d>().unwrap())
|
||||
.map(|c| Coord2d {
|
||||
x: c.x + 1, // allow a buffer zone
|
||||
y: c.y + 1,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[aoc(day9, part1)]
|
||||
@@ -25,15 +38,13 @@ fn part1(input: &Vec<Coord2d>) -> u64 {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[aoc_generator(day9, part2)]
|
||||
fn parse2(input: &str) -> (Vec<Coord2d>, Grid<u8>) {
|
||||
let reds = parse(input);
|
||||
let width = reds.iter().map(|c| c.x()).max().unwrap() + 1;
|
||||
let height = reds.iter().map(|c| c.y()).max().unwrap() + 1;
|
||||
fn build_grid(reds: &Vec<Coord2d>) -> Grid<u8> {
|
||||
let width = reds.iter().map(|c| c.x()).max().unwrap() + 3;
|
||||
let height = reds.iter().map(|c| c.y()).max().unwrap() + 3;
|
||||
|
||||
let mut grid = Grid::with_shape(width as usize, height as usize, b'.');
|
||||
let mut prev = reds.last().unwrap();
|
||||
for c in &reds {
|
||||
for c in reds {
|
||||
// mark c filled
|
||||
grid.set(&c, b'#');
|
||||
// build a line of green between it and the previous
|
||||
@@ -52,33 +63,59 @@ fn parse2(input: &str) -> (Vec<Coord2d>, Grid<u8>) {
|
||||
}
|
||||
prev = c
|
||||
}
|
||||
println!("grid {}x{}", grid.width(), grid.height());
|
||||
(reds, grid)
|
||||
|
||||
grid
|
||||
}
|
||||
|
||||
fn build_hashgrid(reds: &Vec<Coord2d>) -> HashMap<Coord2d, u8> {
|
||||
let mut grid = HashMap::new();
|
||||
let mut prev = reds.last().unwrap();
|
||||
for c in reds {
|
||||
// mark c filled
|
||||
grid.insert(*c, b'#');
|
||||
// build a line of green between it and the previous
|
||||
if c.x() == prev.x() {
|
||||
// vertical
|
||||
for y in (min(c.y(), prev.y()) + 1)..max(c.y(), prev.y()) {
|
||||
grid.insert(Coord2d { x: c.x(), y }, b'X');
|
||||
}
|
||||
} else if c.y() == prev.y() {
|
||||
// horiztonal
|
||||
for x in (min(c.x(), prev.x()) + 1)..max(c.x(), prev.x()) {
|
||||
grid.insert(Coord2d { x, y: c.y() }, b'X');
|
||||
}
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
prev = c
|
||||
}
|
||||
|
||||
grid
|
||||
}
|
||||
|
||||
// FIXME: TOTALLY BROKEN
|
||||
fn flood_fill(grid: &mut Grid<u8>) {
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum State {
|
||||
OffLine(bool), // Off a line(true=inside)
|
||||
OnLine(bool), // On a line(previous state)
|
||||
}
|
||||
for y in 1..grid.height() - 1 {
|
||||
let mut state = match grid.get(&(0, y)) {
|
||||
Some(b'.') => State::OffLine(false), //noop
|
||||
Some(b'#') | Some(b'X') => State::OnLine(true),
|
||||
s => panic!("Unexpected state: {s:?}"),
|
||||
}; // if the row starts with a ., we start outside
|
||||
for x in 1..grid.width() - 1 {
|
||||
for y in 0..grid.height() {
|
||||
let mut state = State::OffLine(false);
|
||||
for x in 0..grid.width() {
|
||||
match grid.get(&(x, y)) {
|
||||
Some(b'.') => {
|
||||
if state == State::OffLine(true) || state == State::OnLine(false) {
|
||||
grid.set(&(x, y), b'X');
|
||||
state = State::OffLine(true)
|
||||
} else {
|
||||
state = State::OffLine(false)
|
||||
}
|
||||
}
|
||||
Some(b'#') | Some(b'X') => {
|
||||
state = State::OnLine(match state {
|
||||
State::OnLine(s) | State::OffLine(s) => s,
|
||||
State::OnLine(s) => s,
|
||||
State::OffLine(s) => s,
|
||||
})
|
||||
}
|
||||
None => panic!("overran the grid"),
|
||||
@@ -88,30 +125,219 @@ fn flood_fill(grid: &mut Grid<u8>) {
|
||||
}
|
||||
}
|
||||
|
||||
#[aoc(day9, part2)]
|
||||
fn part2((reds, grid): &(Vec<Coord2d>, Grid<u8>)) -> u64 {
|
||||
let mut grid = grid.clone();
|
||||
// #[aoc(day9, part2, Brute)]
|
||||
fn part2(reds: &Vec<Coord2d>) -> u64 {
|
||||
let mut grid = build_grid(reds);
|
||||
flood_fill(&mut grid);
|
||||
println!("{grid}");
|
||||
|
||||
'outer: for (a, b) in reds
|
||||
let pairs = reds
|
||||
.iter()
|
||||
.tuple_combinations()
|
||||
.sorted_unstable_by_key(|(a, b)| (a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1))
|
||||
.rev()
|
||||
{
|
||||
println!(
|
||||
"{a} vs {b} = {}",
|
||||
a.x().abs_diff(b.x()) * a.y().abs_diff(b.y())
|
||||
);
|
||||
.progress()
|
||||
.collect_vec();
|
||||
|
||||
let (a, b) = pairs
|
||||
.par_iter()
|
||||
.progress_with_style(
|
||||
ProgressStyle::with_template(
|
||||
"[{elapsed_precise}/{eta_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {per_sec}",
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.filter(|(a, b)| (a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1) < 2972065369) // FIXME: PROGRESS CAPTURE
|
||||
.map(|(a, b)| {
|
||||
for y in (min(a.y(), b.y()))..=max(a.y(), b.y()) {
|
||||
for x in (min(a.x(), b.x()))..=max(a.x(), b.y()) {
|
||||
if *grid.get(&(x, y)).unwrap() == b'.' {
|
||||
continue 'outer;
|
||||
return (false, a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1);
|
||||
(true, a, b)
|
||||
})
|
||||
.find_map_first(|(good, a, b)| if good { Some((a, b)) } else { None })
|
||||
.unwrap();
|
||||
println!("win: {a} {b}");
|
||||
(a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1)
|
||||
}
|
||||
|
||||
fn line_square_intersection<LT: AsCoord2d, ST: AsCoord2d>(
|
||||
&(l1, l2): &(<, <),
|
||||
&(sq1, sq2): &(&ST, &ST),
|
||||
) -> bool
|
||||
where
|
||||
LT: Clone + Display,
|
||||
ST: Clone + Display,
|
||||
{
|
||||
let min_x = min(sq1.x(), sq2.x());
|
||||
let max_x = max(sq1.x(), sq2.x());
|
||||
let min_y = min(sq1.y(), sq2.y());
|
||||
let max_y = max(sq1.y(), sq2.y());
|
||||
|
||||
// println!("({},{}) X [{},{}]", l1, l2, sq1, sq2);
|
||||
// line is horizontal
|
||||
if l1.y() == l2.y() {
|
||||
// println!(" horizontal at y={}", l1.y());
|
||||
// above, below, or touching square
|
||||
if l1.y() <= min_y || l1.y() >= max_y {
|
||||
// println!(" y out of range or touching");
|
||||
false
|
||||
// start inside
|
||||
} else if min(l1.x(), l2.x()) >= min_x && min(l1.x(), l2.x()) <= max_x {
|
||||
// println!(" start inside");
|
||||
true
|
||||
//end inside
|
||||
} else if max(l1.x(), l2.x()) >= min_x && max(l1.x(), l2.x()) <= max_x {
|
||||
// println!(" end inside");
|
||||
true
|
||||
} else {
|
||||
// println!(" no overlap on x");
|
||||
false
|
||||
}
|
||||
// line is vertical
|
||||
} else {
|
||||
// println!(" vertical at x={}", l1.x());
|
||||
if l1.x() <= min_x || l1.x() >= max_x {
|
||||
// println!(" x out of range or touching");
|
||||
false
|
||||
// start inside
|
||||
} else if min(l1.y(), l2.y()) >= min_y && min(l1.y(), l2.y()) <= max_y {
|
||||
// println!(" start inside");
|
||||
true
|
||||
//end inside
|
||||
} else if max(l1.y(), l2.y()) >= min_y && max(l1.y(), l2.y()) <= max_y {
|
||||
// println!(" end inside");
|
||||
true
|
||||
} else {
|
||||
// println!(" no overlap on y");
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Rectangle {
|
||||
fn top_left(&self) -> Coord2d;
|
||||
fn bottom_right(&self) -> Coord2d;
|
||||
fn in_bounds<T: AsCoord2d>(&self, b: &T) -> bool {
|
||||
b.x() >= self.top_left().x
|
||||
&& b.x() <= self.bottom_right().x()
|
||||
&& b.y() >= self.top_left().y()
|
||||
&& b.y() <= self.bottom_right().y()
|
||||
}
|
||||
fn area(&self) -> u64 {
|
||||
let a = self.top_left();
|
||||
let b = self.bottom_right();
|
||||
(a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rectangle for (&Coord2d, &Coord2d) {
|
||||
fn top_left(&self) -> Coord2d {
|
||||
Coord2d {
|
||||
x: min(self.0.x, self.1.x),
|
||||
y: min(self.0.y, self.1.y),
|
||||
}
|
||||
}
|
||||
fn bottom_right(&self) -> Coord2d {
|
||||
Coord2d {
|
||||
x: max(self.0.x, self.1.x),
|
||||
y: max(self.0.y, self.1.y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// true = clockwise
|
||||
fn outside_points(prev: &Coord2d, cur: &Coord2d, next: &Coord2d) -> Vec<Coord2d> {
|
||||
let l1_diff = ((cur.x - prev.x).signum(), (cur.y - prev.y).signum());
|
||||
let l2_diff = ((next.x - cur.x).signum(), (next.y - cur.y).signum());
|
||||
|
||||
match (l1_diff, l2_diff) {
|
||||
// CW
|
||||
((1, 0), (0, 1)) => vec![cur + (0, -1), cur + (1, -1), cur + (1, 0)], // x^ y^
|
||||
((0, 1), (-1, 0)) => vec![cur + (1, 0), cur + (1, 1), cur + (0, -1)], // y^ xv
|
||||
((-1, 0), (0, -1)) => vec![cur + (0, 1), cur + (-1, 1), cur + (-1, 0)], // xv yv
|
||||
((0, -1), (1, 0)) => vec![cur + (-1, 0), cur + (-1, -1), cur + (0, -1)], // yv x^
|
||||
// CCW
|
||||
((0, 1), (1, 0)) => vec![cur + (1, -1)],
|
||||
((1, 0), (0, -1)) => vec![cur + (-1, -1)],
|
||||
((0, -1), (-1, 0)) => vec![cur + (-1, 1)],
|
||||
((-1, 0), (0, 1)) => vec![cur + (1, 1)],
|
||||
((0, _), (0, _)) | ((_, 0), (_, 0)) => vec![], // colinear
|
||||
_ => panic!(
|
||||
"unexpected line arrangement {:?} {:?} @ [({},{}), ({},{}), ({},{})",
|
||||
l1_diff, l2_diff, prev.x, prev.y, cur.x, cur.y, next.x, next.y
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[aoc(day9, part2, Lines)]
|
||||
fn part2_lines(reds: &Vec<Coord2d>) -> u64 {
|
||||
// let mut grid = build_hashgrid(reds);
|
||||
let mut grid = build_grid(reds);
|
||||
println!("{grid}");
|
||||
let outside_points: HashMap<&Coord2d, Vec<Coord2d>> = reds
|
||||
.iter()
|
||||
.circular_tuple_windows()
|
||||
.map(|(a, b, c)| (b, outside_points(a, b, c)))
|
||||
.collect();
|
||||
// for corner in reds {
|
||||
// for p in &outside_points[corner] {
|
||||
// if *grid.get(p).unwrap() == b'.' {
|
||||
// grid.set(p, b'O');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// println!("{grid}");
|
||||
|
||||
// still iterate over the possible rectangles in size order
|
||||
for rect in reds
|
||||
.iter()
|
||||
.tuple_combinations()
|
||||
.sorted_unstable_by_key(|rect: &(&Coord2d, &Coord2d)| rect.area())
|
||||
.rev()
|
||||
.progress_with_style(
|
||||
ProgressStyle::with_template(
|
||||
"[{elapsed_precise}/{eta_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {per_sec}",
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
{
|
||||
println!(
|
||||
"[{},{}] = {}",
|
||||
rect.top_left(),
|
||||
rect.bottom_right(),
|
||||
rect.area()
|
||||
);
|
||||
// then for each corner, check if any of its outside edges are inside and not part of another line
|
||||
if reds
|
||||
.iter()
|
||||
.filter(|corner| rect.in_bounds(corner))
|
||||
.inspect(|c| println!(" corner: {c}"))
|
||||
.any(|corner| {
|
||||
outside_points[corner]
|
||||
.iter()
|
||||
.inspect(|p| println!(" {} = {}", p, *grid.get(p).unwrap() as char))
|
||||
.any(|p| rect.in_bounds(p) && *grid.get(p).unwrap() == b'.')
|
||||
})
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
println!(
|
||||
"win! {},{} = {}",
|
||||
rect.top_left(),
|
||||
rect.bottom_right(),
|
||||
rect.area()
|
||||
);
|
||||
grid.set(&rect.top_left(), b'*');
|
||||
grid.set(&rect.bottom_right(), b'*');
|
||||
|
||||
println!("{grid}");
|
||||
return rect.area();
|
||||
}
|
||||
panic!()
|
||||
}
|
||||
@@ -119,6 +345,7 @@ fn part2((reds, grid): &(Vec<Coord2d>, Grid<u8>)) -> u64 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rstest::rstest;
|
||||
|
||||
const EXAMPLE: &str = "7,1
|
||||
11,1
|
||||
@@ -136,6 +363,97 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
assert_eq!(part2(&parse2(EXAMPLE)), 24);
|
||||
assert_eq!(part2(&parse(EXAMPLE)), 24);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(
|
||||
"7,1
|
||||
11,1
|
||||
11,7
|
||||
9,7
|
||||
9,5
|
||||
2,5
|
||||
2,3
|
||||
7,3",
|
||||
24
|
||||
)]
|
||||
#[case(
|
||||
"4,2
|
||||
13,2
|
||||
13,4
|
||||
8,4
|
||||
8,6
|
||||
11,6
|
||||
11,10
|
||||
4,10",
|
||||
40
|
||||
)]
|
||||
#[case(
|
||||
"3,2
|
||||
17,2
|
||||
17,13
|
||||
13,13
|
||||
13,11
|
||||
15,11
|
||||
15,8
|
||||
11,8
|
||||
11,15
|
||||
18,15
|
||||
18,17
|
||||
4,17
|
||||
4,12
|
||||
6,12
|
||||
6,5
|
||||
3,5",
|
||||
66
|
||||
)]
|
||||
#[case(
|
||||
"2,2
|
||||
8,2
|
||||
8,6
|
||||
5,6
|
||||
5,4
|
||||
2,4",
|
||||
21
|
||||
)]
|
||||
#[case(
|
||||
"3,1
|
||||
12,1
|
||||
12,4
|
||||
9,4
|
||||
9,8
|
||||
3,8",
|
||||
56
|
||||
)]
|
||||
#[case(
|
||||
"7,1
|
||||
11,1
|
||||
11,3
|
||||
13,3
|
||||
13,5
|
||||
11,5
|
||||
11,7
|
||||
9,7
|
||||
9,5
|
||||
2,5
|
||||
2,3
|
||||
7,3",
|
||||
36
|
||||
)]
|
||||
#[case(
|
||||
"1,2
|
||||
8,2
|
||||
8,4
|
||||
6,4
|
||||
6,5
|
||||
9,5
|
||||
9,8
|
||||
1,8",
|
||||
56
|
||||
)]
|
||||
|
||||
fn part2_lines_example(#[case] input: &str, #[case] answer: u64) {
|
||||
assert_eq!(part2_lines(&parse(input)), answer);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user