Skip to content
This repository has been archived by the owner on Aug 1, 2024. It is now read-only.

Commit

Permalink
day 22
Browse files Browse the repository at this point in the history
  • Loading branch information
jpyamamoto committed Jan 17, 2024
1 parent 4717361 commit c581f4e
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
| [Day 19](./src/bin/19.rs) | `504.1µs` | `486.3µs` |
| [Day 20](./src/bin/20.rs) | `4.3ms` | `18.2ms` |
| [Day 21](./src/bin/21.rs) | `1.5ms` | `70.1ms` |
| [Day 22](./src/bin/22.rs) | `9.5ms` | `17.6ms` |

**Total: 46581.81ms**
**Total: 46608.91ms**
<!--- benchmarking table --->

---
Expand Down
139 changes: 139 additions & 0 deletions src/bin/22.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use std::cmp::{max, min};
use std::collections::{VecDeque, HashSet};

advent_of_code::solution!(22);

struct Brick {
x: usize,
y: usize,
z: usize,
ex: usize,
ey: usize,
ez: usize
}

impl Brick {
fn overlap_plane(&self, other: &Brick) -> bool {
max(self.x, other.x) <= min(self.ex, other.ex) && // Overlap in x
max(self.y, other.y) <= min(self.ey, other.ey) // Overlap in y
}
}

fn parse(input: &str) -> Vec<Brick> {
input.lines()
.map(|l| {
let parts: Vec<usize> = l.split(&[',', '~']).map(|c| c.parse().unwrap()).collect();

Brick { x: parts[0],
y: parts[1],
z: parts[2],
ex: parts[3],
ey: parts[4],
ez: parts[5]
}
})
.collect()
}

fn fall_bricks(bricks: &mut Vec<Brick>) {
bricks.sort_by_key(|b| b.z);

for i in 0..bricks.len() {
let mut top_z: usize = 1;

let bricks_below: &[Brick] = &bricks[..i];

for b in bricks_below {
if bricks[i].overlap_plane(b) {
top_z = max(top_z, b.ez + 1);
}
}

let brick = &mut bricks[i];

brick.ez -= brick.z - top_z;
brick.z = top_z;
}

bricks.sort_by_key(|b| b.z);
}

fn compute_supports(bricks: &Vec<Brick>) -> (Vec<Vec<usize>>, Vec<Vec<usize>>) {
let mut supported_by: Vec<Vec<usize>> = vec![vec![]; bricks.len()];
let mut supports: Vec<Vec<usize>> = vec![vec![]; bricks.len()];

for (j, brick) in bricks.iter().enumerate() {
for (i, below) in bricks[..j].iter().enumerate() {
if brick.overlap_plane(below) && brick.z == below.ez + 1 {
supported_by[j].push(i);
supports[i].push(j);
}
}
}

(supported_by, supports)
}

fn compute_falls(brick: usize, supported_by: &Vec<Vec<usize>>, supports: &Vec<Vec<usize>>) -> u32 {
let will_fall: Vec<usize> = supports[brick].iter().filter(|&b| supported_by[*b].len() == 1).cloned().collect();
let mut queue = VecDeque::from_iter(will_fall.iter().cloned());

let mut falling: HashSet<usize> = HashSet::from_iter(will_fall.into_iter());
falling.insert(brick);

while let Some(other) = queue.pop_front() {
for &b in &supports[other] {
if !falling.contains(&b) {
if supported_by[b].iter().all(|s| falling.contains(s)) {
queue.push_back(b);
falling.insert(b);
}
}
}
}

(falling.len() - 1) as u32
}

pub fn part_one(input: &str) -> Option<u32> {
let mut bricks = parse(input);
fall_bricks(&mut bricks);

let (supported_by, supports) = compute_supports(&bricks);

let result: usize = supports.iter()
.filter(|bricks|
bricks.iter().all(|&i| supported_by[i].len() >= 2))
.count();

Some(result as u32)
}

pub fn part_two(input: &str) -> Option<u32> {
let mut bricks = parse(input);
fall_bricks(&mut bricks);

let (supported_by, supports) = compute_supports(&bricks);

(0..bricks.len())
.map(|i| compute_falls(i, &supported_by, &supports))
.sum::<u32>()
.into()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(5));
}

#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(7));
}
}

0 comments on commit c581f4e

Please sign in to comment.