advent-of-code/2022/day14/rust/src/main.rs
2022-12-14 19:33:01 +01:00

81 lines
2.1 KiB
Rust

#![warn(clippy::pedantic)]
use std::{collections::HashSet, io::stdin};
use aoc::vec2::{Line, Vec2};
use itertools::Itertools;
fn parse_points(s: &str) -> impl Iterator<Item = Vec2> + '_ {
s.split(" -> ").map(|p| {
let (x, y) = p.split_once(',').unwrap();
let x = x.parse().unwrap();
let y = y.parse().unwrap();
(x, y).into()
})
}
fn simulate(structures: HashSet<Vec2>, floor: Option<usize>) -> usize {
let mut points = structures;
let lowest = points.iter().map(|v| v.y).max().unwrap();
let start = Vec2::new(500, 0);
let mut pieces = 0;
'pieces: loop {
let mut pos = start;
'fall: loop {
let new_pos = [(0, 1), (-1, 1), (1, 1)]
.into_iter()
.map(|direction| pos + direction.into())
.find(|pos| !points.contains(pos));
if let Some(new_pos) = new_pos {
pos = new_pos;
match floor {
Some(offset) => {
if pos.y >= lowest + i32::try_from(offset).unwrap() - 1 {
// landed on the floor
break 'fall;
}
}
None => {
if pos.y >= lowest {
// fell into the void
break 'pieces;
}
}
}
} else {
// stuck
break 'fall;
}
}
points.insert(pos);
pieces += 1;
if pos == start {
// all filled up
break 'pieces;
}
}
pieces
}
fn main() {
let points: HashSet<Vec2> = stdin()
.lines()
.flat_map(|line| {
parse_points(&line.unwrap())
.tuple_windows()
.map(|(start, end)| Line { start, end })
.collect::<Vec<_>>()
})
.flat_map(|line| line.points().unwrap())
.collect();
println!("{}", simulate(points.clone(), None));
println!("{}", simulate(points, Some(2)));
}