2023 - Day 22
This commit is contained in:
parent
295bfed6b4
commit
e1d2a785f5
1446
2023/input/22/input
Normal file
1446
2023/input/22/input
Normal file
File diff suppressed because it is too large
Load Diff
7
2023/input/22/test-1
Normal file
7
2023/input/22/test-1
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
1,0,1~1,2,1
|
||||||
|
0,0,2~2,0,2
|
||||||
|
0,2,3~2,2,3
|
||||||
|
0,0,4~0,2,4
|
||||||
|
2,0,5~2,2,5
|
||||||
|
0,1,6~2,1,6
|
||||||
|
1,1,8~1,1,9
|
229
2023/src/bin/day22.rs
Normal file
229
2023/src/bin/day22.rs
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
#![feature(test)]
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use aoc::Solver;
|
||||||
|
|
||||||
|
// -- Runners --
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
Day::solve()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_test1() -> Result<()> {
|
||||||
|
Day::test(Day::part1, "test-1", 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_solution() -> Result<()> {
|
||||||
|
Day::test(Day::part1, "input", 488)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_test1() -> Result<()> {
|
||||||
|
Day::test(Day::part2, "test-1", 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_solution() -> Result<()> {
|
||||||
|
Day::test(Day::part2, "input", 79465)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmarks
|
||||||
|
extern crate test;
|
||||||
|
#[bench]
|
||||||
|
#[ignore]
|
||||||
|
fn part1_bench(b: &mut test::Bencher) {
|
||||||
|
Day::benchmark(Day::part1, b)
|
||||||
|
}
|
||||||
|
#[bench]
|
||||||
|
#[ignore]
|
||||||
|
fn part2_bench(b: &mut test::Bencher) {
|
||||||
|
Day::benchmark(Day::part2, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
|
||||||
|
struct Brick {
|
||||||
|
start: (isize, isize, isize),
|
||||||
|
end: (isize, isize, isize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Brick {
|
||||||
|
fn fall(
|
||||||
|
&self,
|
||||||
|
index: usize,
|
||||||
|
grid: &mut HashMap<(isize, isize, isize), usize>,
|
||||||
|
) -> HashSet<usize> {
|
||||||
|
let mut down = 0;
|
||||||
|
// Keep track of all the unique bricks supporting the current brick
|
||||||
|
let mut supports = HashSet::new();
|
||||||
|
for o in 1..self.start.2 {
|
||||||
|
for x in self.start.0..=self.end.0 {
|
||||||
|
for y in self.start.1..=self.end.1 {
|
||||||
|
for z in self.start.2..=self.end.2 {
|
||||||
|
if let Some(&support) = grid.get(&(x, y, z - o)) {
|
||||||
|
supports.insert(support);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have landed on a support
|
||||||
|
if !supports.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
down += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Occupy the space in the grid
|
||||||
|
for x in self.start.0..=self.end.0 {
|
||||||
|
for y in self.start.1..=self.end.1 {
|
||||||
|
for z in self.start.2..=self.end.2 {
|
||||||
|
grid.insert((x, y, z - down), index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return all the unique supports
|
||||||
|
supports
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Solution --
|
||||||
|
pub struct Day;
|
||||||
|
impl aoc::Solver for Day {
|
||||||
|
type Output1 = usize;
|
||||||
|
type Output2 = usize;
|
||||||
|
|
||||||
|
fn day() -> u8 {
|
||||||
|
22
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> Self::Output1 {
|
||||||
|
let mut bricks: Vec<_> = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
let (start, end) = line.split_once('~').unwrap();
|
||||||
|
|
||||||
|
let start: Vec<_> = start
|
||||||
|
.splitn(3, ',')
|
||||||
|
.map(|num| num.parse::<isize>().unwrap())
|
||||||
|
.collect();
|
||||||
|
let start = (start[0], start[1], start[2]);
|
||||||
|
|
||||||
|
let end: Vec<_> = end
|
||||||
|
.splitn(3, ',')
|
||||||
|
.map(|num| num.parse::<isize>().unwrap())
|
||||||
|
.collect();
|
||||||
|
let end = (end[0], end[1], end[2]);
|
||||||
|
|
||||||
|
Brick { start, end }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Sort the bricks from top to bottom
|
||||||
|
bricks.sort_by(|a, b| a.start.2.cmp(&b.start.2));
|
||||||
|
|
||||||
|
// Figure out which bricks are essential and can not be disintegrated
|
||||||
|
let mut grid = HashMap::new();
|
||||||
|
let essential_bricks: HashSet<_> = bricks
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
// Drop down each brick and get all the supporting bricks
|
||||||
|
.map(|(index, brick)| brick.fall(index, &mut grid))
|
||||||
|
// Only keep bricks that are supported by one other brick
|
||||||
|
// If that other brick is disintegrated this brick will fall
|
||||||
|
.filter(|supports| supports.len() == 1)
|
||||||
|
// Flatten out and collect to take out duplicate entries
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
bricks.len() - essential_bricks.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str) -> Self::Output2 {
|
||||||
|
let mut bricks: Vec<_> = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
let (start, end) = line.split_once('~').unwrap();
|
||||||
|
|
||||||
|
let start: Vec<_> = start
|
||||||
|
.splitn(3, ',')
|
||||||
|
.map(|num| num.parse::<isize>().unwrap())
|
||||||
|
.collect();
|
||||||
|
let start = (start[0], start[1], start[2]);
|
||||||
|
|
||||||
|
let end: Vec<_> = end
|
||||||
|
.splitn(3, ',')
|
||||||
|
.map(|num| num.parse::<isize>().unwrap())
|
||||||
|
.collect();
|
||||||
|
let end = (end[0], end[1], end[2]);
|
||||||
|
|
||||||
|
Brick { start, end }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Sort the bricks from top to bottom
|
||||||
|
bricks.sort_by(|a, b| a.start.2.cmp(&b.start.2));
|
||||||
|
|
||||||
|
// Figure out which bricks are essential and can not be disintegrated
|
||||||
|
let mut grid = HashMap::new();
|
||||||
|
let supports: Vec<_> = bricks
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
// Drop down each brick and get all the supporting bricks
|
||||||
|
.map(|(index, brick)| brick.fall(index, &mut grid))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let essential_bricks: HashSet<_> = supports
|
||||||
|
.iter()
|
||||||
|
.filter(|supports| supports.len() == 1)
|
||||||
|
// Flatten out and collect to take out duplicate entries
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut sum = 0;
|
||||||
|
for eliminate in essential_bricks {
|
||||||
|
let mut falling = HashSet::new();
|
||||||
|
falling.insert(*eliminate);
|
||||||
|
let mut previous = 0;
|
||||||
|
|
||||||
|
while previous != falling.len() {
|
||||||
|
previous = falling.len();
|
||||||
|
|
||||||
|
let new: HashSet<_> = supports
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, supports)| {
|
||||||
|
if supports.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for support in *supports {
|
||||||
|
if !falling.contains(support) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
})
|
||||||
|
.map(|(index, _)| index)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
falling.extend(new);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !falling.is_empty() {
|
||||||
|
sum += falling.len() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user