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 -->
|
<!-- AOC TILES BEGIN -->
|
||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
2025 - 16 ⭐ - Rust
|
2025 - 17 ⭐ - Rust
|
||||||
</h1>
|
</h1>
|
||||||
<a href="src/day1.rs">
|
<a href="src/day1.rs">
|
||||||
<img src=".aoc_tiles/tiles/2025/01.png" width="161px">
|
<img src=".aoc_tiles/tiles/2025/01.png" width="161px">
|
||||||
@@ -26,4 +26,7 @@
|
|||||||
<a href="src/day8.rs">
|
<a href="src/day8.rs">
|
||||||
<img src=".aoc_tiles/tiles/2025/08.png" width="161px">
|
<img src=".aoc_tiles/tiles/2025/08.png" width="161px">
|
||||||
</a>
|
</a>
|
||||||
|
<a href="src/day9.rs">
|
||||||
|
<img src=".aoc_tiles/tiles/2025/09.png" width="161px">
|
||||||
|
</a>
|
||||||
<!-- AOC TILES END -->
|
<!-- AOC TILES END -->
|
||||||
|
|||||||
15
src/day8.rs
15
src/day8.rs
@@ -9,13 +9,13 @@ struct Junction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn squared_distance(a: &Junction, b: &Junction) -> u64 {
|
fn squared_distance(a: &Junction, b: &Junction) -> u64 {
|
||||||
if a.pos == b.pos {
|
// if a.pos == b.pos {
|
||||||
0
|
// 0
|
||||||
} else {
|
// } else {
|
||||||
(a.pos.0 - b.pos.0).pow(2) as u64
|
(a.pos.0 - b.pos.0).pow(2) as u64
|
||||||
+ (a.pos.1 - b.pos.1).pow(2) as u64
|
+ (a.pos.1 - b.pos.1).pow(2) as u64
|
||||||
+ (a.pos.2 - b.pos.2).pow(2) as u64
|
+ (a.pos.2 - b.pos.2).pow(2) as u64
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Junction {
|
impl Junction {
|
||||||
@@ -144,6 +144,7 @@ struct JunctionPair {
|
|||||||
a: usize,
|
a: usize,
|
||||||
b: usize,
|
b: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_heap(circuits: &Circuits) -> BinaryHeap<Reverse<JunctionPair>> {
|
fn make_heap(circuits: &Circuits) -> BinaryHeap<Reverse<JunctionPair>> {
|
||||||
BinaryHeap::from_iter(
|
BinaryHeap::from_iter(
|
||||||
circuits
|
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 day6;
|
||||||
mod day7;
|
mod day7;
|
||||||
mod day8;
|
mod day8;
|
||||||
|
mod day9;
|
||||||
|
|
||||||
use aoc_runner_derive::aoc_lib;
|
use aoc_runner_derive::aoc_lib;
|
||||||
|
|
||||||
|
|||||||
@@ -22,22 +22,37 @@ pub const ADJACENT_OFFSETS: [&(i64, i64); 8] = [
|
|||||||
/// NESW
|
/// NESW
|
||||||
pub const CARDINAL_OFFSETS: [&(i64, i64); 4] = [&(0, -1), &(-1, 0), &(1, 0), &(0, 1)];
|
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 struct Coord2d {
|
||||||
pub x: i64,
|
pub x: i64,
|
||||||
pub y: i64,
|
pub y: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Coord2d {
|
impl Display for Coord2d {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_fmt(format_args!("({}, {})", self.x, self.y))
|
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 {
|
pub trait AsCoord2d {
|
||||||
fn to_coord(self) -> Coord2d;
|
fn to_coord(self) -> Coord2d;
|
||||||
fn x(&self) -> i64;
|
fn x(&self) -> i64;
|
||||||
fn y(&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 {
|
impl<T: AsCoord2d> Sub<T> for &Coord2d {
|
||||||
|
|||||||
Reference in New Issue
Block a user