day9: part1 and bruteforce part 2 (some cleanups and clippies)
This commit is contained in:
BIN
.aoc_tiles/tiles/2025/09.png
Normal file
BIN
.aoc_tiles/tiles/2025/09.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -1,6 +1,6 @@
|
||||
<!-- AOC TILES BEGIN -->
|
||||
<h1 align="center">
|
||||
2025 - 16 ⭐ - Rust
|
||||
2025 - 17 ⭐ - Rust
|
||||
</h1>
|
||||
<a href="src/day1.rs">
|
||||
<img src=".aoc_tiles/tiles/2025/01.png" width="161px">
|
||||
@@ -26,4 +26,7 @@
|
||||
<a href="src/day8.rs">
|
||||
<img src=".aoc_tiles/tiles/2025/08.png" width="161px">
|
||||
</a>
|
||||
<a href="src/day9.rs">
|
||||
<img src=".aoc_tiles/tiles/2025/09.png" width="161px">
|
||||
</a>
|
||||
<!-- AOC TILES END -->
|
||||
|
||||
@@ -9,13 +9,13 @@ struct Junction {
|
||||
}
|
||||
|
||||
fn squared_distance(a: &Junction, b: &Junction) -> u64 {
|
||||
if a.pos == b.pos {
|
||||
0
|
||||
} else {
|
||||
// if a.pos == b.pos {
|
||||
// 0
|
||||
// } else {
|
||||
(a.pos.0 - b.pos.0).pow(2) as u64
|
||||
+ (a.pos.1 - b.pos.1).pow(2) as u64
|
||||
+ (a.pos.2 - b.pos.2).pow(2) as u64
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
impl Junction {
|
||||
@@ -144,6 +144,7 @@ struct JunctionPair {
|
||||
a: usize,
|
||||
b: usize,
|
||||
}
|
||||
|
||||
fn make_heap(circuits: &Circuits) -> BinaryHeap<Reverse<JunctionPair>> {
|
||||
BinaryHeap::from_iter(
|
||||
circuits
|
||||
|
||||
141
src/day9.rs
Normal file
141
src/day9.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
use grid::{AsCoord2d, Coord2d, Grid};
|
||||
use itertools::Itertools;
|
||||
use std::cmp::{max, min};
|
||||
|
||||
#[aoc_generator(day9, part1)]
|
||||
fn parse(input: &str) -> Vec<Coord2d> {
|
||||
input.lines().map(|l| l.parse().unwrap()).collect()
|
||||
}
|
||||
|
||||
#[aoc(day9, part1)]
|
||||
fn part1(input: &Vec<Coord2d>) -> u64 {
|
||||
input
|
||||
.iter()
|
||||
.tuple_combinations()
|
||||
.inspect(|(a, b)| {
|
||||
println!(
|
||||
"{a} vs {b} = {}",
|
||||
a.x().abs_diff(b.x()) * a.y().abs_diff(b.y())
|
||||
)
|
||||
})
|
||||
.map(|(a, b)| (a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1))
|
||||
.sorted_unstable()
|
||||
.next_back()
|
||||
.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;
|
||||
|
||||
let mut grid = Grid::with_shape(width as usize, height as usize, b'.');
|
||||
let mut prev = reds.last().unwrap();
|
||||
for c in &reds {
|
||||
// mark c filled
|
||||
grid.set(&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.set(&(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.set(&(x, c.y()), b'X');
|
||||
}
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
prev = c
|
||||
}
|
||||
println!("grid {}x{}", grid.width(), grid.height());
|
||||
(reds, grid)
|
||||
}
|
||||
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
Some(b'#') | Some(b'X') => {
|
||||
state = State::OnLine(match state {
|
||||
State::OnLine(s) | State::OffLine(s) => s,
|
||||
})
|
||||
}
|
||||
None => panic!("overran the grid"),
|
||||
Some(c) => panic!("unexpected value {c}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[aoc(day9, part2)]
|
||||
fn part2((reds, grid): &(Vec<Coord2d>, Grid<u8>)) -> u64 {
|
||||
let mut grid = grid.clone();
|
||||
flood_fill(&mut grid);
|
||||
|
||||
'outer: for (a, b) in 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())
|
||||
);
|
||||
|
||||
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 (a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1);
|
||||
}
|
||||
panic!()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const EXAMPLE: &str = "7,1
|
||||
11,1
|
||||
11,7
|
||||
9,7
|
||||
9,5
|
||||
2,5
|
||||
2,3
|
||||
7,3";
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
assert_eq!(part1(&parse(EXAMPLE)), 50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
assert_eq!(part2(&parse2(EXAMPLE)), 24);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ mod day5;
|
||||
mod day6;
|
||||
mod day7;
|
||||
mod day8;
|
||||
mod day9;
|
||||
|
||||
use aoc_runner_derive::aoc_lib;
|
||||
|
||||
|
||||
@@ -22,22 +22,37 @@ pub const ADJACENT_OFFSETS: [&(i64, i64); 8] = [
|
||||
/// NESW
|
||||
pub const CARDINAL_OFFSETS: [&(i64, i64); 4] = [&(0, -1), &(-1, 0), &(1, 0), &(0, 1)];
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||
pub struct Coord2d {
|
||||
pub x: i64,
|
||||
pub y: i64,
|
||||
}
|
||||
|
||||
impl Debug for Coord2d {
|
||||
impl Display for Coord2d {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("({}, {})", self.x, self.y))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Coord2d {
|
||||
type Err = Box<dyn std::error::Error>;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let (l, r) = s.split_once(',').ok_or("Can't split on ,")?;
|
||||
Ok(Coord2d {
|
||||
x: l.parse()?,
|
||||
y: r.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AsCoord2d {
|
||||
fn to_coord(self) -> Coord2d;
|
||||
fn x(&self) -> i64;
|
||||
fn y(&self) -> i64;
|
||||
|
||||
fn manhattan<T: AsCoord2d>(&self, other: &T) -> u64 {
|
||||
self.x().abs_diff(other.x()) + self.y().abs_diff(other.y())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsCoord2d> Sub<T> for &Coord2d {
|
||||
|
||||
Reference in New Issue
Block a user