81 lines
2.1 KiB
Rust
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)));
|
|
}
|