This commit is contained in:
Acvaxoort 2023-12-22 18:00:18 +01:00
parent fc5e45dcbf
commit 9324bc2ccc
4 changed files with 1619 additions and 0 deletions

7
day22/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "day22"
version = "0.1.0"

8
day22/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day22"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

1485
day22/input.txt Normal file

File diff suppressed because it is too large Load Diff

119
day22/src/main.rs Normal file
View File

@ -0,0 +1,119 @@
use std::cmp;
use std::fs::read_to_string;
use std::time::Instant;
struct Brick {
supports: Vec<u16>,
supported_by: Vec<u16>,
pos1: (u16, u16, u16),
pos2: (u16, u16, u16),
}
impl Brick {
fn new(pos1: (u16, u16, u16), pos2: (u16, u16, u16)) -> Brick {
Brick { supports: vec![], supported_by: vec![], pos1, pos2 }
}
}
// Part 1
fn can_be_taken_out(bricks: &Vec<Brick>, brick: &Brick) -> bool {
for &other_brick_id in &brick.supports {
let other_brick = &bricks[other_brick_id as usize];
if other_brick.supported_by.len() < 2 {
return false;
}
}
true
}
// Part 2
fn count_fallen(bricks: &Vec<Brick>, index: usize) -> u16 {
// Counting how many supports have been already removed from each brick
let mut taken_supports: Vec<u16> = vec![0; bricks.len()];
// Result counter
let mut taken_bricks = 0;
// Bricks that are going to disappear
let mut to_take: Vec<u16> = vec![index as u16];
loop {
if let Some(id) = to_take.pop() {
// Increase taken counter for each brick that is supported by current
// If taken supports is equal to amount of supports, that brick will fall too
let brick = &bricks[id as usize];
for &supported_id in &brick.supports {
let supported_brick = &bricks[supported_id as usize];
taken_supports[supported_id as usize] += 1;
if taken_supports[supported_id as usize] == supported_brick.supported_by.len() as u16 {
to_take.push(supported_id);
taken_bricks += 1;
}
}
} else {
break;
}
}
taken_bricks
}
fn main() {
let time_start = Instant::now();
let input_str = read_to_string("input.txt").unwrap();
let time_start_no_io = Instant::now();
let mut bricks: Vec<Brick> = vec![];
for line in input_str.lines() {
let mut split = line.split([',', '~']).map(|s| s.parse::<u16>().unwrap());
bricks.push(Brick::new((split.next().unwrap(), split.next().unwrap(), split.next().unwrap()),
(split.next().unwrap(), split.next().unwrap(), split.next().unwrap())));
}
// Sort by their vertical position so we can easily process them retaining falling precedence
bricks.sort_by(|a, b| a.pos1.2.cmp(&b.pos1.2));
// View from above containing id of the topmost brick on each x, y
let max_x = bricks.iter().fold(0, |acc, brick| cmp::max(acc, brick.pos2.0));
let max_y = bricks.iter().fold(0, |acc, brick| cmp::max(acc, brick.pos2.1));
let mut from_above = vec![vec![u16::MAX; (max_x + 1) as usize]; (max_y + 1) as usize];
// Make the bricks fall and create a support graph
for i in 0..bricks.len() {
let (below, rest) = bricks.split_at_mut(i);
let brick = &mut rest[0];
// Check how low the brick can go
let mut target_z = 0;
for y in brick.pos1.1..=brick.pos2.1 {
for x in brick.pos1.0..=brick.pos2.0 {
let &other_brick_id = &from_above[y as usize][x as usize];
if other_brick_id != u16::MAX {
let other_brick = &below[other_brick_id as usize];
target_z = cmp::max(target_z, other_brick.pos2.2 + 1);
}
}
}
// Shift it below
let z_drop = brick.pos1.2 - target_z;
brick.pos1.2 -= z_drop;
brick.pos2.2 -= z_drop;
// Create support graph connections in bricks, update view from above
for y in brick.pos1.1..=brick.pos2.1 {
for x in brick.pos1.0..=brick.pos2.0 {
let &other_brick_id = &from_above[y as usize][x as usize];
if other_brick_id != u16::MAX {
let other_brick = &mut below[other_brick_id as usize];
if other_brick.pos2.2 + 1 == target_z {
if !brick.supported_by.contains(&other_brick_id) {
brick.supported_by.push(other_brick_id);
other_brick.supports.push(i as u16);
}
}
}
from_above[y as usize][x as usize] = i as u16;
}
}
}
// Part 1
let sum1 = bricks.iter().filter(|&brick| can_be_taken_out(&bricks, brick)).count();
// Part 2
let sum2 = (0..bricks.len()).map(|i| count_fallen(&bricks, i) as u32).sum::<u32>();
let elapsed = time_start.elapsed().as_micros();
let elapsed_no_io = time_start_no_io.elapsed().as_micros();
println!("Time: {}us", elapsed);
println!("Time without file i/o: {}us", elapsed_no_io);
println!("Sum1: {}", sum1);
println!("Sum2: {}", sum2);
}