advent-of-code/2022/day9/rust/src/main.rs

63 lines
1.6 KiB
Rust

#![feature(iterator_try_reduce)]
#![warn(clippy::pedantic)]
use std::{
collections::BTreeSet,
io::{stdin, Read},
};
use aoc::vec2::{Direction, Vec2};
fn knot_movement(previous: Vec2, knot: Vec2) -> Option<Vec2> {
let (dx, dy) = (previous - knot).into();
if dx.abs() <= 1 && dy.abs() <= 1 {
None
} else {
Some((dx.signum(), dy.signum()).into())
}
}
fn simulate_knots(num_knots: usize, instructions: &[(Direction, usize)]) -> usize {
const START: Vec2 = Vec2::new(0, 0);
assert!(num_knots >= 2);
let mut knots = vec![START; num_knots];
let mut tail_positions = BTreeSet::new();
tail_positions.insert(START);
for (direction, distance) in instructions {
for _i in 0..*distance {
knots[0] += Vec2::from(*direction);
if let Some(tail) = knots.iter_mut().try_reduce(|previous, knot| {
*knot += knot_movement(*previous, *knot)?;
Some(knot)
}) {
tail_positions.insert(tail.copied().unwrap());
}
}
}
tail_positions.len()
}
fn main() {
let mut data = String::new();
stdin().read_to_string(&mut data).unwrap();
let instructions: Vec<_> = data
.lines()
.map(|line| {
let (direction, distance) = line.split_once(' ').unwrap();
let direction = direction.parse().unwrap();
let distance = distance.parse().unwrap();
(direction, distance)
})
.collect();
println!("{:?}", simulate_knots(2, &instructions));
println!("{:?}", simulate_knots(10, &instructions));
}